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
package/util.js CHANGED
@@ -1,3 +1,4 @@
1
+ //#region packages/eslint-plugin-formatjs/util.ts
1
2
  const FORMAT_FUNCTION_NAMES = new Set([
2
3
  "$formatMessage",
3
4
  "formatMessage",
@@ -5,7 +6,7 @@ const FORMAT_FUNCTION_NAMES = new Set([
5
6
  ]);
6
7
  const COMPONENT_NAMES = new Set(["FormattedMessage"]);
7
8
  const DECLARATION_FUNCTION_NAMES = new Set(["defineMessage"]);
8
- export function getSettings({ settings }) {
9
+ function getSettings({ settings }) {
9
10
  return settings.formatjs ?? settings;
10
11
  }
11
12
  function isStringLiteral(node) {
@@ -17,35 +18,19 @@ function isTemplateLiteralWithoutVar(node) {
17
18
  function staticallyEvaluateStringConcat(node) {
18
19
  const right = node.right;
19
20
  const left = node.left;
20
- if (!isStringLiteral(right)) {
21
- return ["", false];
22
- }
23
- if (isStringLiteral(left)) {
24
- return [left.value + right.value, true];
25
- }
21
+ if (!isStringLiteral(right)) return ["", false];
22
+ if (isStringLiteral(left)) return [left.value + right.value, true];
26
23
  if (node.left.type === "BinaryExpression") {
27
24
  const [result, isStaticallyEvaluatable] = staticallyEvaluateStringConcat(node.left);
28
25
  return [result + right.value, isStaticallyEvaluatable];
29
26
  }
30
27
  return ["", false];
31
28
  }
32
- export function isIntlFormatMessageCall(node) {
33
- // GH #4890: Check for both MemberExpression (intl.formatMessage) and Identifier (formatMessage) patterns
34
- if (node.type !== "CallExpression") {
35
- return false;
36
- }
37
- // Check if call has at least one argument that is an object expression
38
- if (node.arguments.length < 1 || node.arguments[0].type !== "ObjectExpression") {
39
- return false;
40
- }
41
- // Pattern 1: intl.formatMessage() or something.intl.formatMessage()
42
- if (node.callee.type === "MemberExpression") {
43
- return (node.callee.object.type === "Identifier" && node.callee.object.name === "intl" || node.callee.object.type === "MemberExpression" && node.callee.object.property.type === "Identifier" && node.callee.object.property.name === "intl") && node.callee.property.type === "Identifier" && (node.callee.property.name === "formatMessage" || node.callee.property.name === "$t");
44
- }
45
- // Pattern 2: formatMessage() (destructured from useIntl)
46
- if (node.callee.type === "Identifier") {
47
- return FORMAT_FUNCTION_NAMES.has(node.callee.name);
48
- }
29
+ function isIntlFormatMessageCall(node) {
30
+ if (node.type !== "CallExpression") return false;
31
+ if (node.arguments.length < 1 || node.arguments[0].type !== "ObjectExpression") return false;
32
+ if (node.callee.type === "MemberExpression") return (node.callee.object.type === "Identifier" && node.callee.object.name === "intl" || node.callee.object.type === "MemberExpression" && node.callee.object.property.type === "Identifier" && node.callee.object.property.name === "intl") && node.callee.property.type === "Identifier" && (node.callee.property.name === "formatMessage" || node.callee.property.name === "$t");
33
+ if (node.callee.type === "Identifier") return FORMAT_FUNCTION_NAMES.has(node.callee.name);
49
34
  return false;
50
35
  }
51
36
  function isSingleMessageDescriptorDeclaration(node, functionNames) {
@@ -54,45 +39,31 @@ function isSingleMessageDescriptorDeclaration(node, functionNames) {
54
39
  function isMultipleMessageDescriptorDeclaration(node) {
55
40
  return node.type === "CallExpression" && node.callee.type === "Identifier" && node.callee.name === "defineMessages";
56
41
  }
57
- export function extractMessageDescriptor(node) {
58
- if (!node || node.type !== "ObjectExpression") {
59
- return;
60
- }
42
+ function extractMessageDescriptor(node) {
43
+ if (!node || node.type !== "ObjectExpression") return;
61
44
  const result = {
62
45
  messageDescriptorNode: node,
63
46
  message: {},
64
- messageNode: undefined,
65
- messagePropNode: undefined,
66
- descriptionNode: undefined,
67
- idValueNode: undefined
47
+ messageNode: void 0,
48
+ messagePropNode: void 0,
49
+ descriptionNode: void 0,
50
+ idValueNode: void 0
68
51
  };
69
52
  for (const prop of node.properties) {
70
- if (prop.type !== "Property" || prop.key.type !== "Identifier") {
71
- continue;
72
- }
73
- // Only extract values for message-related props
74
- // GH #5069: Don't process other props like tagName, values, etc.
53
+ if (prop.type !== "Property" || prop.key.type !== "Identifier") continue;
75
54
  const propName = prop.key.name;
76
- if (propName !== "id" && propName !== "defaultMessage" && propName !== "description") {
77
- continue;
78
- }
55
+ if (propName !== "id" && propName !== "defaultMessage" && propName !== "description") continue;
79
56
  const valueNode = prop.value;
80
- let value = undefined;
81
- if (isStringLiteral(valueNode)) {
82
- value = valueNode.value;
83
- } else if (isTemplateLiteralWithoutVar(valueNode)) {
84
- value = valueNode.quasis[0].value.cooked ?? undefined;
85
- } else if (valueNode.type === "TaggedTemplateExpression") {
57
+ let value = void 0;
58
+ if (isStringLiteral(valueNode)) value = valueNode.value;
59
+ else if (isTemplateLiteralWithoutVar(valueNode)) value = valueNode.quasis[0].value.cooked ?? void 0;
60
+ else if (valueNode.type === "TaggedTemplateExpression") {
86
61
  const { quasi } = valueNode;
87
- if (!isTemplateLiteralWithoutVar(quasi)) {
88
- throw new Error("Tagged template expression must be no substitution");
89
- }
90
- value = quasi.quasis[0].value.cooked ?? undefined;
62
+ if (!isTemplateLiteralWithoutVar(quasi)) throw new Error("Tagged template expression must be no substitution");
63
+ value = quasi.quasis[0].value.cooked ?? void 0;
91
64
  } else if (valueNode.type === "BinaryExpression") {
92
65
  const [result, isStatic] = staticallyEvaluateStringConcat(valueNode);
93
- if (isStatic) {
94
- value = result;
95
- }
66
+ if (isStatic) value = result;
96
67
  }
97
68
  switch (propName) {
98
69
  case "defaultMessage":
@@ -114,54 +85,37 @@ export function extractMessageDescriptor(node) {
114
85
  return result;
115
86
  }
116
87
  function extractMessageDescriptorFromJSXElement(node) {
117
- if (!node || !node.attributes) {
118
- return;
119
- }
88
+ if (!node || !node.attributes) return;
120
89
  let values;
121
90
  const result = {
122
91
  messageDescriptorNode: node,
123
92
  message: {},
124
- messageNode: undefined,
125
- messagePropNode: undefined,
126
- descriptionNode: undefined,
127
- idValueNode: undefined,
128
- idPropNode: undefined
93
+ messageNode: void 0,
94
+ messagePropNode: void 0,
95
+ descriptionNode: void 0,
96
+ idValueNode: void 0,
97
+ idPropNode: void 0
129
98
  };
130
99
  let hasSpreadAttribute = false;
131
100
  for (const prop of node.attributes) {
132
- // We can't analyze spread attr
133
- if (prop.type === "JSXSpreadAttribute") {
134
- hasSpreadAttribute = true;
135
- }
136
- if (prop.type !== "JSXAttribute" || prop.name.type !== "JSXIdentifier") {
137
- continue;
138
- }
139
- const key = prop.name;
140
- const keyName = key.name;
141
- // Only extract values for message-related props
142
- // GH #5069: Don't process other props like tagName, values, etc.
143
- // Allow them to have tagged templates with substitutions
101
+ if (prop.type === "JSXSpreadAttribute") hasSpreadAttribute = true;
102
+ if (prop.type !== "JSXAttribute" || prop.name.type !== "JSXIdentifier") continue;
103
+ const keyName = prop.name.name;
144
104
  const isMessageProp = keyName === "id" || keyName === "defaultMessage" || keyName === "description";
145
105
  let valueNode = prop.value;
146
- let value = undefined;
106
+ let value = void 0;
147
107
  if (valueNode && isMessageProp) {
148
- if (isStringLiteral(valueNode)) {
149
- value = valueNode.value;
150
- } else if (valueNode?.type === "JSXExpressionContainer") {
108
+ if (isStringLiteral(valueNode)) value = valueNode.value;
109
+ else if (valueNode?.type === "JSXExpressionContainer") {
151
110
  const { expression } = valueNode;
152
111
  if (expression.type === "BinaryExpression") {
153
112
  const [result, isStatic] = staticallyEvaluateStringConcat(expression);
154
- if (isStatic) {
155
- value = result;
156
- }
157
- } else if (isTemplateLiteralWithoutVar(expression)) {
158
- value = expression.quasis[0].value.cooked ?? undefined;
159
- } else if (expression.type === "TaggedTemplateExpression") {
113
+ if (isStatic) value = result;
114
+ } else if (isTemplateLiteralWithoutVar(expression)) value = expression.quasis[0].value.cooked ?? void 0;
115
+ else if (expression.type === "TaggedTemplateExpression") {
160
116
  const { quasi } = expression;
161
- if (!isTemplateLiteralWithoutVar(quasi)) {
162
- throw new Error("Tagged template expression must be no substitution");
163
- }
164
- value = quasi.quasis[0].value.cooked ?? undefined;
117
+ if (!isTemplateLiteralWithoutVar(quasi)) throw new Error("Tagged template expression must be no substitution");
118
+ value = quasi.quasis[0].value.cooked ?? void 0;
165
119
  }
166
120
  }
167
121
  }
@@ -169,78 +123,51 @@ function extractMessageDescriptorFromJSXElement(node) {
169
123
  case "defaultMessage":
170
124
  result.messagePropNode = prop;
171
125
  result.messageNode = valueNode;
172
- if (value) {
173
- result.message.defaultMessage = value;
174
- }
126
+ if (value) result.message.defaultMessage = value;
175
127
  break;
176
128
  case "description":
177
129
  result.descriptionNode = valueNode;
178
- if (value) {
179
- result.message.description = value;
180
- }
130
+ if (value) result.message.description = value;
181
131
  break;
182
132
  case "id":
183
133
  result.idValueNode = valueNode;
184
134
  result.idPropNode = prop;
185
- if (value) {
186
- result.message.id = value;
187
- }
135
+ if (value) result.message.id = value;
188
136
  break;
189
137
  case "values":
190
- if (valueNode?.type === "JSXExpressionContainer" && valueNode.expression.type === "ObjectExpression") {
191
- values = valueNode.expression;
192
- }
138
+ if (valueNode?.type === "JSXExpressionContainer" && valueNode.expression.type === "ObjectExpression") values = valueNode.expression;
193
139
  break;
194
140
  }
195
141
  }
196
- if (!result.messagePropNode && !result.descriptionNode && !result.idPropNode && hasSpreadAttribute) {
197
- return;
198
- }
142
+ if (!result.messagePropNode && !result.descriptionNode && !result.idPropNode && hasSpreadAttribute) return;
199
143
  return [result, values];
200
144
  }
201
145
  function extractMessageDescriptors(node) {
202
- if (!node || node.type !== "ObjectExpression" || !node.properties.length) {
203
- return [];
204
- }
146
+ if (!node || node.type !== "ObjectExpression" || !node.properties.length) return [];
205
147
  const msgs = [];
206
148
  for (const prop of node.properties) {
207
- if (prop.type !== "Property") {
208
- continue;
209
- }
149
+ if (prop.type !== "Property") continue;
210
150
  const msg = prop.value;
211
- if (msg.type !== "ObjectExpression") {
212
- continue;
213
- }
151
+ if (msg.type !== "ObjectExpression") continue;
214
152
  const nodeInfo = extractMessageDescriptor(msg);
215
- if (nodeInfo) {
216
- msgs.push(nodeInfo);
217
- }
153
+ if (nodeInfo) msgs.push(nodeInfo);
218
154
  }
219
155
  return msgs;
220
156
  }
221
- export function extractMessages(node, { additionalComponentNames, additionalFunctionNames, excludeMessageDeclCalls } = {}) {
157
+ function extractMessages(node, { additionalComponentNames, additionalFunctionNames, excludeMessageDeclCalls } = {}) {
222
158
  const allFormatFunctionNames = Array.isArray(additionalFunctionNames) ? new Set([...Array.from(FORMAT_FUNCTION_NAMES), ...additionalFunctionNames]) : FORMAT_FUNCTION_NAMES;
223
159
  const allComponentNames = Array.isArray(additionalComponentNames) ? new Set([...Array.from(COMPONENT_NAMES), ...additionalComponentNames]) : COMPONENT_NAMES;
224
160
  if (node.type === "CallExpression") {
225
161
  const args0 = node.arguments[0];
226
162
  const args1 = node.arguments[1];
227
- // We can't really analyze spread element
228
- if (!args0 || args0.type === "SpreadElement") {
229
- return [];
230
- }
163
+ if (!args0 || args0.type === "SpreadElement") return [];
231
164
  if (!excludeMessageDeclCalls && isSingleMessageDescriptorDeclaration(node, DECLARATION_FUNCTION_NAMES) || isIntlFormatMessageCall(node) || isSingleMessageDescriptorDeclaration(node, allFormatFunctionNames)) {
232
165
  const msgDescriptorNodeInfo = extractMessageDescriptor(args0);
233
- if (msgDescriptorNodeInfo && (!args1 || args1.type !== "SpreadElement")) {
234
- return [[msgDescriptorNodeInfo, args1]];
235
- }
236
- } else if (!excludeMessageDeclCalls && isMultipleMessageDescriptorDeclaration(node)) {
237
- return extractMessageDescriptors(args0).map((msg) => [msg, undefined]);
238
- }
166
+ if (msgDescriptorNodeInfo && (!args1 || args1.type !== "SpreadElement")) return [[msgDescriptorNodeInfo, args1]];
167
+ } else if (!excludeMessageDeclCalls && isMultipleMessageDescriptorDeclaration(node)) return extractMessageDescriptors(args0).map((msg) => [msg, void 0]);
239
168
  } else if (node.type === "JSXOpeningElement" && node.name && node.name.type === "JSXIdentifier" && allComponentNames.has(node.name.name)) {
240
169
  const msgDescriptorNodeInfo = extractMessageDescriptorFromJSXElement(node);
241
- if (msgDescriptorNodeInfo) {
242
- return [msgDescriptorNodeInfo];
243
- }
170
+ if (msgDescriptorNodeInfo) return [msgDescriptorNodeInfo];
244
171
  }
245
172
  return [];
246
173
  }
@@ -249,11 +176,12 @@ export function extractMessages(node, { additionalComponentNames, additionalFunc
249
176
  * `fixer.replaceText(messageNode, <return value>)`. If the return value is null,
250
177
  * it means that the patch cannot be applied.
251
178
  */
252
- export function patchMessage(messageNode, ast, patcher) {
253
- if (messageNode.type === "Literal" && messageNode.value && typeof messageNode.value === "string") {
254
- return "\"" + patcher(messageNode.value, ast).replace("\"", "\\\"") + "\"";
255
- } else if (messageNode.type === "TemplateLiteral" && messageNode.quasis.length === 1 && messageNode.expressions.length === 0) {
256
- return "`" + patcher(messageNode.quasis[0].value.cooked, ast).replace(/\\/g, "\\\\").replace(/`/g, "\\`") + "`";
257
- }
179
+ function patchMessage(messageNode, ast, patcher) {
180
+ if (messageNode.type === "Literal" && messageNode.value && typeof messageNode.value === "string") return "\"" + patcher(messageNode.value, ast).replace("\"", "\\\"") + "\"";
181
+ else if (messageNode.type === "TemplateLiteral" && messageNode.quasis.length === 1 && messageNode.expressions.length === 0) return "`" + patcher(messageNode.quasis[0].value.cooked, ast).replace(/\\/g, "\\\\").replace(/`/g, "\\`") + "`";
258
182
  return null;
259
183
  }
184
+ //#endregion
185
+ export { extractMessageDescriptor, extractMessages, getSettings, isIntlFormatMessageCall, patchMessage };
186
+
187
+ //# sourceMappingURL=util.js.map
package/util.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"util.js","names":[],"sources":["../util.ts"],"sourcesContent":["import type {MessageFormatElement} from '@formatjs/icu-messageformat-parser'\nimport type {Rule} from 'eslint'\nimport type {\n BinaryExpression,\n Expression,\n Literal,\n Node,\n ObjectExpression,\n Property,\n TemplateLiteral,\n} from 'estree-jsx'\nimport type {JSXAttribute, JSXOpeningElement} from 'estree-jsx'\n\nexport interface MessageDescriptor {\n id?: string\n defaultMessage?: string\n description?: string | object\n}\n\nconst FORMAT_FUNCTION_NAMES = new Set(['$formatMessage', 'formatMessage', '$t'])\nconst COMPONENT_NAMES = new Set(['FormattedMessage'])\nconst DECLARATION_FUNCTION_NAMES = new Set(['defineMessage'])\n\nexport interface Settings {\n excludeMessageDeclCalls?: boolean\n additionalFunctionNames?: string[]\n additionalComponentNames?: string[]\n ignoreTag?: boolean\n}\nexport interface MessageDescriptorNodeInfo {\n message: MessageDescriptor\n messageDescriptorNode: ObjectExpression | JSXOpeningElement\n messageNode?: Property['value'] | JSXAttribute['value']\n messagePropNode?: Property | JSXAttribute\n descriptionNode?: Property['value'] | JSXAttribute['value']\n idValueNode?: Property['value'] | JSXAttribute['value']\n idPropNode?: Property | JSXAttribute\n}\n\nexport function getSettings({settings}: Rule.RuleContext): Settings {\n return settings.formatjs ?? settings\n}\n\nfunction isStringLiteral(node: Node): node is Literal & {value: string} {\n return node.type === 'Literal' && typeof node.value === 'string'\n}\n\nfunction isTemplateLiteralWithoutVar(node: Node): node is TemplateLiteral {\n return node.type === 'TemplateLiteral' && node.quasis.length === 1\n}\n\nfunction staticallyEvaluateStringConcat(\n node: BinaryExpression\n): [result: string, isStaticallyEvaluatable: boolean] {\n const right = node.right as Node\n const left = node.left as Node\n if (!isStringLiteral(right)) {\n return ['', false]\n }\n if (isStringLiteral(left)) {\n return [left.value + right.value, true]\n }\n if (node.left.type === 'BinaryExpression') {\n const [result, isStaticallyEvaluatable] = staticallyEvaluateStringConcat(\n node.left\n )\n return [result + right.value, isStaticallyEvaluatable]\n }\n return ['', false]\n}\n\nexport function isIntlFormatMessageCall(node: Node): boolean {\n // GH #4890: Check for both MemberExpression (intl.formatMessage) and Identifier (formatMessage) patterns\n if (node.type !== 'CallExpression') {\n return false\n }\n\n // Check if call has at least one argument that is an object expression\n if (\n node.arguments.length < 1 ||\n node.arguments[0].type !== 'ObjectExpression'\n ) {\n return false\n }\n\n // Pattern 1: intl.formatMessage() or something.intl.formatMessage()\n if (node.callee.type === 'MemberExpression') {\n return (\n ((node.callee.object.type === 'Identifier' &&\n node.callee.object.name === 'intl') ||\n (node.callee.object.type === 'MemberExpression' &&\n node.callee.object.property.type === 'Identifier' &&\n node.callee.object.property.name === 'intl')) &&\n node.callee.property.type === 'Identifier' &&\n (node.callee.property.name === 'formatMessage' ||\n node.callee.property.name === '$t')\n )\n }\n\n // Pattern 2: formatMessage() (destructured from useIntl)\n if (node.callee.type === 'Identifier') {\n return FORMAT_FUNCTION_NAMES.has(node.callee.name)\n }\n\n return false\n}\n\nfunction isSingleMessageDescriptorDeclaration(\n node: Node,\n functionNames: Set<string>\n) {\n return (\n node.type === 'CallExpression' &&\n node.callee.type === 'Identifier' &&\n functionNames.has(node.callee.name)\n )\n}\n\nfunction isMultipleMessageDescriptorDeclaration(node: Node) {\n return (\n node.type === 'CallExpression' &&\n node.callee.type === 'Identifier' &&\n node.callee.name === 'defineMessages'\n )\n}\n\nexport function extractMessageDescriptor(\n node?: Expression\n): MessageDescriptorNodeInfo | undefined {\n if (!node || node.type !== 'ObjectExpression') {\n return\n }\n const result: MessageDescriptorNodeInfo = {\n messageDescriptorNode: node,\n message: {},\n messageNode: undefined,\n messagePropNode: undefined,\n descriptionNode: undefined,\n idValueNode: undefined,\n }\n for (const prop of node.properties) {\n if (prop.type !== 'Property' || prop.key.type !== 'Identifier') {\n continue\n }\n\n // Only extract values for message-related props\n // GH #5069: Don't process other props like tagName, values, etc.\n const propName = prop.key.name\n if (\n propName !== 'id' &&\n propName !== 'defaultMessage' &&\n propName !== 'description'\n ) {\n continue\n }\n\n const valueNode = prop.value\n let value: string | undefined = undefined\n if (isStringLiteral(valueNode as Node)) {\n value = (valueNode as Literal & {value: string}).value\n }\n // like \"`asd`\"\n else if (isTemplateLiteralWithoutVar(valueNode as Node)) {\n value = (valueNode as TemplateLiteral).quasis[0].value.cooked ?? undefined\n }\n // like \"dedent`asd`\"\n else if (valueNode.type === 'TaggedTemplateExpression') {\n const {quasi} = valueNode\n if (!isTemplateLiteralWithoutVar(quasi as Node)) {\n throw new Error('Tagged template expression must be no substitution')\n }\n value = quasi.quasis[0].value.cooked ?? undefined\n }\n // like \"`asd` + `asd`\"\n else if (valueNode.type === 'BinaryExpression') {\n const [result, isStatic] = staticallyEvaluateStringConcat(valueNode)\n if (isStatic) {\n value = result\n }\n }\n\n switch (propName) {\n case 'defaultMessage':\n result.messagePropNode = prop\n result.messageNode = valueNode\n result.message.defaultMessage = value\n break\n case 'description':\n result.descriptionNode = valueNode\n result.message.description = value\n break\n case 'id':\n result.message.id = value\n result.idValueNode = valueNode\n result.idPropNode = prop\n break\n }\n }\n return result\n}\n\nfunction extractMessageDescriptorFromJSXElement(\n node?: JSXOpeningElement\n): [MessageDescriptorNodeInfo, ObjectExpression | undefined] | undefined {\n if (!node || !node.attributes) {\n return\n }\n let values: ObjectExpression | undefined\n const result: MessageDescriptorNodeInfo = {\n messageDescriptorNode: node,\n message: {},\n messageNode: undefined,\n messagePropNode: undefined,\n descriptionNode: undefined,\n idValueNode: undefined,\n idPropNode: undefined,\n }\n let hasSpreadAttribute = false\n for (const prop of node.attributes) {\n // We can't analyze spread attr\n if (prop.type === 'JSXSpreadAttribute') {\n hasSpreadAttribute = true\n }\n if (prop.type !== 'JSXAttribute' || prop.name.type !== 'JSXIdentifier') {\n continue\n }\n const key = prop.name\n const keyName = key.name\n\n // Only extract values for message-related props\n // GH #5069: Don't process other props like tagName, values, etc.\n // Allow them to have tagged templates with substitutions\n const isMessageProp =\n keyName === 'id' ||\n keyName === 'defaultMessage' ||\n keyName === 'description'\n\n let valueNode = prop.value\n let value: string | undefined = undefined\n if (valueNode && isMessageProp) {\n if (isStringLiteral(valueNode as Node)) {\n value = (valueNode as Literal & {value: string}).value\n } else if (valueNode?.type === 'JSXExpressionContainer') {\n const {expression} = valueNode\n if (expression.type === 'BinaryExpression') {\n const [result, isStatic] = staticallyEvaluateStringConcat(expression)\n if (isStatic) {\n value = result\n }\n }\n // like \"`asd`\"\n else if (isTemplateLiteralWithoutVar(expression as Node)) {\n value =\n (expression as TemplateLiteral).quasis[0].value.cooked ?? undefined\n }\n // like \"dedent`asd`\"\n else if (expression.type === 'TaggedTemplateExpression') {\n const {quasi} = expression\n if (!isTemplateLiteralWithoutVar(quasi as Node)) {\n throw new Error(\n 'Tagged template expression must be no substitution'\n )\n }\n value = quasi.quasis[0].value.cooked ?? undefined\n }\n }\n }\n\n switch (keyName) {\n case 'defaultMessage':\n result.messagePropNode = prop\n result.messageNode = valueNode\n if (value) {\n result.message.defaultMessage = value\n }\n break\n case 'description':\n result.descriptionNode = valueNode\n if (value) {\n result.message.description = value\n }\n break\n case 'id':\n result.idValueNode = valueNode\n result.idPropNode = prop\n if (value) {\n result.message.id = value\n }\n break\n case 'values':\n if (\n valueNode?.type === 'JSXExpressionContainer' &&\n valueNode.expression.type === 'ObjectExpression'\n ) {\n values = valueNode.expression\n }\n break\n }\n }\n if (\n !result.messagePropNode &&\n !result.descriptionNode &&\n !result.idPropNode &&\n hasSpreadAttribute\n ) {\n return\n }\n return [result, values]\n}\n\nfunction extractMessageDescriptors(node?: Expression) {\n if (!node || node.type !== 'ObjectExpression' || !node.properties.length) {\n return []\n }\n const msgs = []\n for (const prop of node.properties) {\n if (prop.type !== 'Property') {\n continue\n }\n const msg = prop.value\n if (msg.type !== 'ObjectExpression') {\n continue\n }\n const nodeInfo = extractMessageDescriptor(msg as Expression)\n if (nodeInfo) {\n msgs.push(nodeInfo)\n }\n }\n return msgs\n}\n\nexport function extractMessages(\n node: Node,\n {\n additionalComponentNames,\n additionalFunctionNames,\n excludeMessageDeclCalls,\n }: Settings = {}\n): Array<[MessageDescriptorNodeInfo, Expression | undefined]> {\n const allFormatFunctionNames = Array.isArray(additionalFunctionNames)\n ? new Set([\n ...Array.from(FORMAT_FUNCTION_NAMES),\n ...additionalFunctionNames,\n ])\n : FORMAT_FUNCTION_NAMES\n const allComponentNames = Array.isArray(additionalComponentNames)\n ? new Set([...Array.from(COMPONENT_NAMES), ...additionalComponentNames])\n : COMPONENT_NAMES\n if (node.type === 'CallExpression') {\n const args0 = node.arguments[0]\n const args1 = node.arguments[1]\n // We can't really analyze spread element\n if (!args0 || args0.type === 'SpreadElement') {\n return []\n }\n if (\n (!excludeMessageDeclCalls &&\n isSingleMessageDescriptorDeclaration(\n node,\n DECLARATION_FUNCTION_NAMES\n )) ||\n isIntlFormatMessageCall(node) ||\n isSingleMessageDescriptorDeclaration(node, allFormatFunctionNames)\n ) {\n const msgDescriptorNodeInfo = extractMessageDescriptor(args0)\n if (msgDescriptorNodeInfo && (!args1 || args1.type !== 'SpreadElement')) {\n return [[msgDescriptorNodeInfo, args1 as Expression]]\n }\n } else if (\n !excludeMessageDeclCalls &&\n isMultipleMessageDescriptorDeclaration(node)\n ) {\n return extractMessageDescriptors(args0).map(msg => [msg, undefined])\n }\n } else if (\n node.type === 'JSXOpeningElement' &&\n node.name &&\n node.name.type === 'JSXIdentifier' &&\n allComponentNames.has(node.name.name)\n ) {\n const msgDescriptorNodeInfo = extractMessageDescriptorFromJSXElement(node)\n if (msgDescriptorNodeInfo) {\n return [msgDescriptorNodeInfo]\n }\n }\n return []\n}\n\n/**\n * Apply changes to the ICU message in code. The return value can be used in\n * `fixer.replaceText(messageNode, <return value>)`. If the return value is null,\n * it means that the patch cannot be applied.\n */\nexport function patchMessage(\n messageNode: Node,\n ast: MessageFormatElement[],\n patcher: (messageContent: string, ast: MessageFormatElement[]) => string\n): string | null {\n if (\n messageNode.type === 'Literal' &&\n messageNode.value &&\n typeof messageNode.value === 'string'\n ) {\n return (\n '\"' + patcher(messageNode.value as string, ast).replace('\"', '\\\\\"') + '\"'\n )\n } else if (\n messageNode.type === 'TemplateLiteral' &&\n messageNode.quasis.length === 1 &&\n messageNode.expressions.length === 0\n ) {\n return (\n '`' +\n patcher(messageNode.quasis[0].value.cooked!, ast)\n .replace(/\\\\/g, '\\\\\\\\')\n .replace(/`/g, '\\\\`') +\n '`'\n )\n }\n\n return null\n}\n"],"mappings":"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"}
@@ -1,27 +0,0 @@
1
- /**
2
- * Auto-generated emoji version data from Unicode emoji-data.txt
3
- * DO NOT EDIT MANUALLY - Generated by scripts/generate-emoji-data.ts
4
- *
5
- * Unicode Version: 17.0.0
6
- * Ranges: 418 emoji codepoint ranges
7
- */
8
- export type EmojiVersion = "0.0" | "0.6" | "0.7" | "1.0" | "2.0" | "3.0" | "4.0" | "5.0" | "11.0" | "12.0" | "13.0" | "14.0" | "15.0" | "16.0" | "17.0";
9
- export declare const EMOJI_VERSIONS: EmojiVersion[];
10
- export interface EmojiRange {
11
- /** Start codepoint (decimal) */
12
- start: number;
13
- /** End codepoint (decimal), same as start for single codepoint */
14
- end: number;
15
- /** Unicode emoji version */
16
- version: EmojiVersion;
17
- /** Description */
18
- name: string;
19
- }
20
- /**
21
- * Emoji codepoint ranges with their Unicode versions
22
- * Total ranges: 418
23
- *
24
- * To check if a codepoint belongs to a version, iterate through ranges
25
- * and check if codepoint >= start && codepoint <= end
26
- */
27
- export declare const EMOJI_RANGES: readonly EmojiRange[];