eslint-plugin-formatjs 6.4.4 → 6.4.6

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 (55) hide show
  1. package/index.d.ts +15 -12
  2. package/index.js +4603 -54
  3. package/index.js.map +1 -0
  4. package/package.json +3 -3
  5. package/util.d.ts +654 -29
  6. package/util.js +62 -134
  7. package/util.js.map +1 -0
  8. package/emoji-data.generated.d.ts +0 -27
  9. package/emoji-data.generated.js +0 -2564
  10. package/emoji-utils.d.ts +0 -43
  11. package/emoji-utils.js +0 -145
  12. package/messages.d.ts +0 -2
  13. package/messages.js +0 -1
  14. package/rules/blocklist-elements.d.ts +0 -14
  15. package/rules/blocklist-elements.js +0 -129
  16. package/rules/enforce-default-message.d.ts +0 -7
  17. package/rules/enforce-default-message.js +0 -57
  18. package/rules/enforce-description.d.ts +0 -11
  19. package/rules/enforce-description.js +0 -97
  20. package/rules/enforce-id.d.ts +0 -8
  21. package/rules/enforce-id.js +0 -135
  22. package/rules/enforce-placeholders.d.ts +0 -3
  23. package/rules/enforce-placeholders.js +0 -128
  24. package/rules/enforce-plural-rules.d.ts +0 -14
  25. package/rules/enforce-plural-rules.js +0 -108
  26. package/rules/no-camel-case.d.ts +0 -3
  27. package/rules/no-camel-case.js +0 -85
  28. package/rules/no-complex-selectors.d.ts +0 -3
  29. package/rules/no-complex-selectors.js +0 -119
  30. package/rules/no-emoji.d.ts +0 -8
  31. package/rules/no-emoji.js +0 -88
  32. package/rules/no-id.d.ts +0 -3
  33. package/rules/no-id.js +0 -48
  34. package/rules/no-invalid-icu.d.ts +0 -3
  35. package/rules/no-invalid-icu.js +0 -56
  36. package/rules/no-literal-string-in-jsx.d.ts +0 -3
  37. package/rules/no-literal-string-in-jsx.js +0 -161
  38. package/rules/no-literal-string-in-object.d.ts +0 -3
  39. package/rules/no-literal-string-in-object.js +0 -59
  40. package/rules/no-missing-icu-plural-one-placeholders.d.ts +0 -5
  41. package/rules/no-missing-icu-plural-one-placeholders.js +0 -94
  42. package/rules/no-multiple-plurals.d.ts +0 -3
  43. package/rules/no-multiple-plurals.js +0 -76
  44. package/rules/no-multiple-whitespaces.d.ts +0 -3
  45. package/rules/no-multiple-whitespaces.js +0 -126
  46. package/rules/no-offset.d.ts +0 -3
  47. package/rules/no-offset.js +0 -75
  48. package/rules/no-useless-message.d.ts +0 -3
  49. package/rules/no-useless-message.js +0 -69
  50. package/rules/prefer-formatted-message.d.ts +0 -3
  51. package/rules/prefer-formatted-message.js +0 -26
  52. package/rules/prefer-full-sentence.d.ts +0 -3
  53. package/rules/prefer-full-sentence.js +0 -111
  54. package/rules/prefer-pound-in-plural.d.ts +0 -3
  55. package/rules/prefer-pound-in-plural.js +0 -163
@@ -1,128 +0,0 @@
1
- import { TYPE, parse } from "@formatjs/icu-messageformat-parser";
2
- import { extractMessages, getSettings } from "../util.js";
3
- import { CORE_MESSAGES } from "../messages.js";
4
- function collectPlaceholderNames(ast) {
5
- const placeholderNames = new Set();
6
- _traverse(ast);
7
- return placeholderNames;
8
- function _traverse(ast) {
9
- for (const element of ast) {
10
- switch (element.type) {
11
- case TYPE.literal:
12
- case TYPE.pound: break;
13
- case TYPE.tag:
14
- placeholderNames.add(element.value);
15
- _traverse(element.children);
16
- break;
17
- case TYPE.plural:
18
- case TYPE.select:
19
- placeholderNames.add(element.value);
20
- for (const { value } of Object.values(element.options)) {
21
- _traverse(value);
22
- }
23
- break;
24
- default:
25
- placeholderNames.add(element.value);
26
- break;
27
- }
28
- }
29
- }
30
- }
31
- function checkNode(context, node) {
32
- const settings = getSettings(context);
33
- const msgs = extractMessages(node, {
34
- excludeMessageDeclCalls: true,
35
- ...settings
36
- });
37
- const { options: [opt] } = context;
38
- const ignoreList = new Set(opt?.ignoreList || []);
39
- for (const [{ message: { defaultMessage }, messageNode }, values] of msgs) {
40
- if (!defaultMessage || !messageNode) {
41
- continue;
42
- }
43
- if (values && values.type !== "ObjectExpression") {
44
- // cannot evaluate this
45
- continue;
46
- }
47
- if (values?.properties.find((prop) => prop.type === "SpreadElement")) {
48
- // cannot evaluate the spread element
49
- continue;
50
- }
51
- const literalElementByLiteralKey = new Map();
52
- if (values) {
53
- for (const prop of values.properties) {
54
- if (prop.type === "Property" && !prop.computed) {
55
- const name = prop.key.type === "Identifier" ? prop.key.name : String(prop.key.value);
56
- literalElementByLiteralKey.set(name, prop);
57
- }
58
- }
59
- }
60
- let ast;
61
- try {
62
- ast = parse(defaultMessage, { ignoreTag: settings.ignoreTag });
63
- } catch (e) {
64
- context.report({
65
- node: messageNode,
66
- messageId: "parseError",
67
- data: { error: e instanceof Error ? e.message : String(e) }
68
- });
69
- continue;
70
- }
71
- const placeholderNames = collectPlaceholderNames(ast);
72
- const missingPlaceholders = [];
73
- placeholderNames.forEach((name) => {
74
- if (!ignoreList.has(name) && !literalElementByLiteralKey.has(name)) {
75
- missingPlaceholders.push(name);
76
- }
77
- });
78
- if (missingPlaceholders.length > 0) {
79
- context.report({
80
- node: messageNode,
81
- messageId: "missingValue",
82
- data: { list: missingPlaceholders.join(", ") }
83
- });
84
- }
85
- literalElementByLiteralKey.forEach((element, key) => {
86
- if (!ignoreList.has(key) && !placeholderNames.has(key)) {
87
- context.report({
88
- node: element,
89
- messageId: "unusedValue"
90
- });
91
- }
92
- });
93
- }
94
- }
95
- export const name = "enforce-placeholders";
96
- export const rule = {
97
- meta: {
98
- type: "problem",
99
- docs: {
100
- description: "Enforce that all messages with placeholders have enough passed-in values",
101
- url: "https://formatjs.github.io/docs/tooling/linter#enforce-placeholders"
102
- },
103
- schema: [{
104
- type: "object",
105
- properties: { ignoreList: {
106
- type: "array",
107
- items: { type: "string" }
108
- } },
109
- additionalProperties: false
110
- }],
111
- messages: {
112
- ...CORE_MESSAGES,
113
- missingValue: "Missing value(s) for the following placeholder(s): {{list}}.",
114
- unusedValue: "Value not used by the message."
115
- }
116
- },
117
- create(context) {
118
- const callExpressionVisitor = (node) => checkNode(context, node);
119
- const parserServices = context.sourceCode.parserServices;
120
- if (parserServices?.defineTemplateBodyVisitor) {
121
- return parserServices.defineTemplateBodyVisitor({ CallExpression: callExpressionVisitor }, { CallExpression: callExpressionVisitor });
122
- }
123
- return {
124
- JSXOpeningElement: (node) => checkNode(context, node),
125
- CallExpression: callExpressionVisitor
126
- };
127
- }
128
- };
@@ -1,14 +0,0 @@
1
- import type { Rule } from "eslint";
2
- declare enum LDML {
3
- zero = "zero",
4
- one = "one",
5
- two = "two",
6
- few = "few",
7
- many = "many",
8
- other = "other"
9
- }
10
- type PluralConfig = { [key in LDML]? : boolean };
11
- export type Options = [PluralConfig?];
12
- export declare const name = "enforce-plural-rules";
13
- export declare const rule: Rule.RuleModule;
14
- export {};
@@ -1,108 +0,0 @@
1
- import { isPluralElement, parse } from "@formatjs/icu-messageformat-parser";
2
- import { extractMessages, getSettings } from "../util.js";
3
- import { CORE_MESSAGES } from "../messages.js";
4
- var LDML = /* @__PURE__ */ function(LDML) {
5
- LDML["zero"] = "zero";
6
- LDML["one"] = "one";
7
- LDML["two"] = "two";
8
- LDML["few"] = "few";
9
- LDML["many"] = "many";
10
- LDML["other"] = "other";
11
- return LDML;
12
- }(LDML || {});
13
- function verifyAst(plConfig, ast) {
14
- const errors = [];
15
- for (const el of ast) {
16
- if (isPluralElement(el)) {
17
- const rules = Object.keys(plConfig);
18
- for (const rule of rules) {
19
- if (plConfig[rule] && !el.options[rule]) {
20
- errors.push({
21
- messageId: "missingPlural",
22
- data: { rule }
23
- });
24
- }
25
- if (!plConfig[rule] && el.options[rule]) {
26
- errors.push({
27
- messageId: "forbidden",
28
- data: { rule }
29
- });
30
- }
31
- }
32
- const { options } = el;
33
- for (const selector of Object.keys(options)) {
34
- errors.push(...verifyAst(plConfig, options[selector].value));
35
- }
36
- }
37
- }
38
- return errors;
39
- }
40
- function checkNode(context, node) {
41
- const settings = getSettings(context);
42
- const msgs = extractMessages(node, settings);
43
- if (!msgs.length) {
44
- return;
45
- }
46
- const plConfig = context.options[0];
47
- if (!plConfig) {
48
- return;
49
- }
50
- for (const [{ message: { defaultMessage }, messageNode }] of msgs) {
51
- if (!defaultMessage || !messageNode) {
52
- continue;
53
- }
54
- let ast;
55
- try {
56
- ast = parse(defaultMessage, { ignoreTag: settings.ignoreTag });
57
- } catch (e) {
58
- context.report({
59
- node: messageNode,
60
- messageId: "parseError",
61
- data: { error: e.message }
62
- });
63
- continue;
64
- }
65
- const errors = verifyAst(plConfig, ast);
66
- for (const error of errors) {
67
- context.report({
68
- node: messageNode,
69
- ...error
70
- });
71
- }
72
- }
73
- }
74
- export const name = "enforce-plural-rules";
75
- export const rule = {
76
- meta: {
77
- type: "problem",
78
- docs: {
79
- description: "Enforce plural rules to always specify certain categories like `one`/`other`",
80
- url: "https://formatjs.github.io/docs/tooling/linter#enforce-plural-rules"
81
- },
82
- fixable: "code",
83
- schema: [{
84
- type: "object",
85
- properties: Object.keys(LDML).reduce((schema, k) => {
86
- schema[k] = { type: "boolean" };
87
- return schema;
88
- }, {}),
89
- additionalProperties: false
90
- }],
91
- messages: {
92
- ...CORE_MESSAGES,
93
- missingPlural: `Missing plural rule "{{rule}}"`,
94
- forbidden: `Plural rule "{{rule}}" is forbidden`
95
- }
96
- },
97
- create(context) {
98
- const callExpressionVisitor = (node) => checkNode(context, node);
99
- const parserServices = context.sourceCode.parserServices;
100
- if (parserServices?.defineTemplateBodyVisitor) {
101
- return parserServices.defineTemplateBodyVisitor({ CallExpression: callExpressionVisitor }, { CallExpression: callExpressionVisitor });
102
- }
103
- return {
104
- JSXOpeningElement: (node) => checkNode(context, node),
105
- CallExpression: callExpressionVisitor
106
- };
107
- }
108
- };
@@ -1,3 +0,0 @@
1
- import type { Rule } from "eslint";
2
- export declare const name = "no-camel-case";
3
- export declare const rule: Rule.RuleModule;
@@ -1,85 +0,0 @@
1
- import { isArgumentElement, isPluralElement, parse } from "@formatjs/icu-messageformat-parser";
2
- import { extractMessages, getSettings } from "../util.js";
3
- import { CORE_MESSAGES } from "../messages.js";
4
- export const name = "no-camel-case";
5
- const CAMEL_CASE_REGEX = /[A-Z]/;
6
- function verifyAst(ast) {
7
- const errors = [];
8
- for (const el of ast) {
9
- if (isArgumentElement(el)) {
10
- if (CAMEL_CASE_REGEX.test(el.value)) {
11
- errors.push({
12
- messageId: "camelcase",
13
- data: {}
14
- });
15
- }
16
- continue;
17
- }
18
- if (isPluralElement(el)) {
19
- if (CAMEL_CASE_REGEX.test(el.value)) {
20
- errors.push({
21
- messageId: "camelcase",
22
- data: {}
23
- });
24
- }
25
- const { options } = el;
26
- for (const selector of Object.keys(options)) {
27
- errors.push(...verifyAst(options[selector].value));
28
- }
29
- }
30
- }
31
- return errors;
32
- }
33
- function checkNode(context, node) {
34
- const settings = getSettings(context);
35
- const msgs = extractMessages(node, settings);
36
- for (const [{ message: { defaultMessage }, messageNode }] of msgs) {
37
- if (!defaultMessage || !messageNode) {
38
- continue;
39
- }
40
- let ast;
41
- try {
42
- ast = parse(defaultMessage, { ignoreTag: settings.ignoreTag });
43
- } catch (e) {
44
- context.report({
45
- node: messageNode,
46
- messageId: "parseError",
47
- data: { error: e.message }
48
- });
49
- continue;
50
- }
51
- const errors = verifyAst(ast);
52
- for (const error of errors) {
53
- context.report({
54
- node: messageNode,
55
- ...error
56
- });
57
- }
58
- }
59
- }
60
- export const rule = {
61
- meta: {
62
- type: "problem",
63
- docs: {
64
- description: "Disallow camel case placeholders in message",
65
- url: "https://formatjs.github.io/docs/tooling/linter#no-camel-case"
66
- },
67
- fixable: "code",
68
- schema: [],
69
- messages: {
70
- ...CORE_MESSAGES,
71
- camelcase: "Camel case arguments are not allowed"
72
- }
73
- },
74
- create(context) {
75
- const callExpressionVisitor = (node) => checkNode(context, node);
76
- const parserServices = context.sourceCode.parserServices;
77
- if (parserServices?.defineTemplateBodyVisitor) {
78
- return parserServices.defineTemplateBodyVisitor({ CallExpression: callExpressionVisitor }, { CallExpression: callExpressionVisitor });
79
- }
80
- return {
81
- JSXOpeningElement: (node) => checkNode(context, node),
82
- CallExpression: callExpressionVisitor
83
- };
84
- }
85
- };
@@ -1,3 +0,0 @@
1
- import type { Rule } from "eslint";
2
- export declare const name = "no-complex-selectors";
3
- export declare const rule: Rule.RuleModule;
@@ -1,119 +0,0 @@
1
- import { TYPE, parse } from "@formatjs/icu-messageformat-parser";
2
- import { extractMessages, getSettings } from "../util.js";
3
- import { CORE_MESSAGES } from "../messages.js";
4
- function calculateComplexity(ast) {
5
- // Dynamic programming: define a complexity function f, where:
6
- // f(plural | select) = sum(f(option) for each option) * f(next element),
7
- // f(tag) = f(first element of children) * f(next element),
8
- // f(other) = f(next element),
9
- // f(out of bound) = 1.
10
- const complexityByNode = new Map();
11
- return _calculate(ast, 0);
12
- function _calculate(ast, index) {
13
- const element = ast[index];
14
- if (!element) {
15
- return 1;
16
- }
17
- const cachedComplexity = complexityByNode.get(element);
18
- if (cachedComplexity !== undefined) {
19
- return cachedComplexity;
20
- }
21
- let complexity;
22
- switch (element.type) {
23
- case TYPE.plural:
24
- case TYPE.select: {
25
- let sumOfOptions = 0;
26
- for (const { value } of Object.values(element.options)) {
27
- sumOfOptions += _calculate(value, 0);
28
- }
29
- complexity = sumOfOptions * _calculate(ast, index + 1);
30
- break;
31
- }
32
- case TYPE.tag:
33
- complexity = _calculate(element.children, 0) * _calculate(ast, index + 1);
34
- break;
35
- default:
36
- complexity = _calculate(ast, index + 1);
37
- break;
38
- }
39
- complexityByNode.set(element, complexity);
40
- return complexity;
41
- }
42
- }
43
- function checkNode(context, node) {
44
- const settings = getSettings(context);
45
- const msgs = extractMessages(node, settings);
46
- if (!msgs.length) {
47
- return;
48
- }
49
- const config = {
50
- limit: 20,
51
- ...context.options[0]
52
- };
53
- for (const [{ message: { defaultMessage }, messageNode }] of msgs) {
54
- if (!defaultMessage || !messageNode) {
55
- continue;
56
- }
57
- let ast;
58
- try {
59
- ast = parse(defaultMessage, { ignoreTag: settings.ignoreTag });
60
- } catch (e) {
61
- context.report({
62
- node: messageNode,
63
- messageId: "parseError",
64
- data: { error: e instanceof Error ? e.message : String(e) }
65
- });
66
- return;
67
- }
68
- const complexity = calculateComplexity(ast);
69
- if (complexity > config.limit) {
70
- context.report({
71
- node: messageNode,
72
- messageId: "tooComplex",
73
- data: {
74
- complexity,
75
- limit: config.limit
76
- }
77
- });
78
- }
79
- }
80
- }
81
- export const name = "no-complex-selectors";
82
- export const rule = {
83
- meta: {
84
- type: "problem",
85
- docs: {
86
- description: `Make sure a sentence is not too complex.
87
- Complexity is determined by how many strings are produced when we try to
88
- flatten the sentence given its selectors. For example:
89
- "I have {count, plural, one{a dog} other{many dogs}}"
90
- has the complexity of 2 because flattening the plural selector
91
- results in 2 sentences: "I have a dog" & "I have many dogs".
92
- Default complexity limit is 20
93
- (using Smartling as a reference: https://help.smartling.com/hc/en-us/articles/360008030994-ICU-MessageFormat)
94
- `,
95
- url: "https://formatjs.github.io/docs/tooling/linter#no-complex-selectors"
96
- },
97
- schema: [{
98
- type: "object",
99
- properties: { limit: { type: "number" } },
100
- additionalProperties: false
101
- }],
102
- fixable: "code",
103
- messages: {
104
- ...CORE_MESSAGES,
105
- tooComplex: `Message complexity is too high ({{complexity}} vs limit at {{limit}})`
106
- }
107
- },
108
- create(context) {
109
- const callExpressionVisitor = (node) => checkNode(context, node);
110
- const parserServices = context.sourceCode.parserServices;
111
- if (parserServices?.defineTemplateBodyVisitor) {
112
- return parserServices.defineTemplateBodyVisitor({ CallExpression: callExpressionVisitor }, { CallExpression: callExpressionVisitor });
113
- }
114
- return {
115
- JSXOpeningElement: (node) => checkNode(context, node),
116
- CallExpression: callExpressionVisitor
117
- };
118
- }
119
- };
@@ -1,8 +0,0 @@
1
- import type { Rule } from "eslint";
2
- export declare const name = "no-emoji";
3
- type NoEmojiConfig = {
4
- versionAbove: string;
5
- };
6
- export type Options = [NoEmojiConfig?];
7
- export declare const rule: Rule.RuleModule;
8
- export {};
package/rules/no-emoji.js DELETED
@@ -1,88 +0,0 @@
1
- import { extractEmojis, filterEmojis, hasEmoji, isValidEmojiVersion } from "../emoji-utils.js";
2
- import { extractMessages, getSettings } from "../util.js";
3
- export const name = "no-emoji";
4
- function checkNode(context, node) {
5
- const msgs = extractMessages(node, getSettings(context));
6
- let versionAbove;
7
- const [emojiConfig] = context.options;
8
- if (emojiConfig?.versionAbove && isValidEmojiVersion(emojiConfig.versionAbove)) {
9
- versionAbove = emojiConfig.versionAbove;
10
- }
11
- for (const [{ message: { defaultMessage }, messageNode }] of msgs) {
12
- if (!defaultMessage || !messageNode) {
13
- continue;
14
- }
15
- if (hasEmoji(defaultMessage)) {
16
- if (versionAbove) {
17
- const filter = filterEmojis(versionAbove);
18
- for (const emoji of extractEmojis(defaultMessage)) {
19
- // Check if the emoji's version is allowed (filterEmojis returns true for allowed emojis)
20
- if (!filter(emoji)) {
21
- context.report({
22
- node: messageNode,
23
- messageId: "notAllowedAboveVersion",
24
- data: {
25
- versionAbove,
26
- emoji
27
- }
28
- });
29
- }
30
- }
31
- } else {
32
- context.report({
33
- node: messageNode,
34
- messageId: "notAllowed"
35
- });
36
- }
37
- }
38
- }
39
- }
40
- const versionAboveEnums = [
41
- "0.6",
42
- "0.7",
43
- "1.0",
44
- "2.0",
45
- "3.0",
46
- "4.0",
47
- "5.0",
48
- "11.0",
49
- "12.0",
50
- "13.0",
51
- "14.0",
52
- "15.0",
53
- "16.0",
54
- "17.0"
55
- ];
56
- export const rule = {
57
- meta: {
58
- type: "problem",
59
- docs: {
60
- description: "Disallow emojis in message",
61
- url: "https://formatjs.github.io/docs/tooling/linter#no-emoji"
62
- },
63
- fixable: "code",
64
- schema: [{
65
- type: "object",
66
- properties: { versionAbove: {
67
- type: "string",
68
- enum: versionAboveEnums
69
- } },
70
- additionalProperties: false
71
- }],
72
- messages: {
73
- notAllowed: "Emojis are not allowed",
74
- notAllowedAboveVersion: "Emojis above version {{versionAbove}} are not allowed - Emoji: {{emoji}}"
75
- }
76
- },
77
- create(context) {
78
- const callExpressionVisitor = (node) => checkNode(context, node);
79
- const parserServices = context.sourceCode.parserServices;
80
- if (parserServices?.defineTemplateBodyVisitor) {
81
- return parserServices.defineTemplateBodyVisitor({ CallExpression: callExpressionVisitor }, { CallExpression: callExpressionVisitor });
82
- }
83
- return {
84
- JSXOpeningElement: (node) => checkNode(context, node),
85
- CallExpression: callExpressionVisitor
86
- };
87
- }
88
- };
package/rules/no-id.d.ts DELETED
@@ -1,3 +0,0 @@
1
- import type { Rule } from "eslint";
2
- export declare const name = "no-id";
3
- export declare const rule: Rule.RuleModule;
package/rules/no-id.js DELETED
@@ -1,48 +0,0 @@
1
- import { extractMessages, getSettings } from "../util.js";
2
- function isComment(token) {
3
- return !!token && (token.type === "Block" || token.type === "Line");
4
- }
5
- export const name = "no-id";
6
- function checkNode(context, node) {
7
- const msgs = extractMessages(node, getSettings(context));
8
- for (const [{ idPropNode }] of msgs) {
9
- if (idPropNode) {
10
- context.report({
11
- node: idPropNode,
12
- messageId: "noId",
13
- fix(fixer) {
14
- const src = context.sourceCode;
15
- const token = src.getTokenAfter(idPropNode);
16
- const fixes = [fixer.remove(idPropNode)];
17
- if (token && !isComment(token) && token?.value === ",") {
18
- fixes.push(fixer.remove(token));
19
- }
20
- return fixes;
21
- }
22
- });
23
- }
24
- }
25
- }
26
- export const rule = {
27
- meta: {
28
- type: "problem",
29
- docs: {
30
- description: "Ban explicit ID from MessageDescriptor",
31
- url: "https://formatjs.github.io/docs/tooling/linter#no-id"
32
- },
33
- fixable: "code",
34
- schema: [],
35
- messages: { noId: "Manual `id` are not allowed in message descriptor" }
36
- },
37
- create(context) {
38
- const callExpressionVisitor = (node) => checkNode(context, node);
39
- const parserServices = context.sourceCode.parserServices;
40
- if (parserServices?.defineTemplateBodyVisitor) {
41
- return parserServices.defineTemplateBodyVisitor({ CallExpression: callExpressionVisitor }, { CallExpression: callExpressionVisitor });
42
- }
43
- return {
44
- JSXOpeningElement: (node) => checkNode(context, node),
45
- CallExpression: callExpressionVisitor
46
- };
47
- }
48
- };
@@ -1,3 +0,0 @@
1
- import type { Rule } from "eslint";
2
- export declare const name = "no-invalid-icu";
3
- export declare const rule: Rule.RuleModule;
@@ -1,56 +0,0 @@
1
- import { parse } from "@formatjs/icu-messageformat-parser";
2
- import { extractMessages, getSettings } from "../util.js";
3
- import { CORE_MESSAGES } from "../messages.js";
4
- export const name = "no-invalid-icu";
5
- function checkNode(context, node) {
6
- const settings = getSettings(context);
7
- let msgs;
8
- try {
9
- msgs = extractMessages(node, settings);
10
- } catch (e) {
11
- // GH #5069: Handle errors from extractMessages (e.g., tagged templates with substitutions)
12
- context.report({
13
- node,
14
- messageId: "parseError",
15
- data: { error: e.message }
16
- });
17
- return;
18
- }
19
- if (!msgs.length) {
20
- return;
21
- }
22
- for (const [{ message: { defaultMessage }, messageNode }] of msgs) {
23
- if (!defaultMessage || !messageNode) {
24
- continue;
25
- }
26
- try {
27
- parse(defaultMessage, { ignoreTag: settings.ignoreTag });
28
- } catch (e) {
29
- context.report({
30
- node: messageNode,
31
- messageId: "parseError",
32
- data: { error: e.message }
33
- });
34
- }
35
- }
36
- }
37
- export const rule = {
38
- meta: {
39
- type: "problem",
40
- docs: { description: `Make sure ICU messages are formatted correctly with no bad select statements, plurals, etc.` },
41
- fixable: "code",
42
- schema: [],
43
- messages: CORE_MESSAGES
44
- },
45
- create(context) {
46
- const callExpressionVisitor = (node) => checkNode(context, node);
47
- const parserServices = context.sourceCode.parserServices;
48
- if (parserServices?.defineTemplateBodyVisitor) {
49
- return parserServices.defineTemplateBodyVisitor({ CallExpression: callExpressionVisitor }, { CallExpression: callExpressionVisitor });
50
- }
51
- return {
52
- JSXOpeningElement: (node) => checkNode(context, node),
53
- CallExpression: callExpressionVisitor
54
- };
55
- }
56
- };
@@ -1,3 +0,0 @@
1
- import type { Rule } from "eslint";
2
- export declare const name = "no-literal-string-in-jsx";
3
- export declare const rule: Rule.RuleModule;