eslint-plugin-formatjs 4.2.0 → 4.2.2

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 (88) hide show
  1. package/index.d.ts +22 -0
  2. package/index.d.ts.map +1 -0
  3. package/index.js +38 -0
  4. package/package.json +3 -3
  5. package/rules/blocklist-elements.d.ts +4 -0
  6. package/rules/blocklist-elements.d.ts.map +1 -0
  7. package/rules/blocklist-elements.js +127 -0
  8. package/rules/enforce-default-message.d.ts +4 -0
  9. package/rules/enforce-default-message.d.ts.map +1 -0
  10. package/rules/enforce-default-message.js +57 -0
  11. package/rules/enforce-description.d.ts +4 -0
  12. package/rules/enforce-description.d.ts.map +1 -0
  13. package/rules/enforce-description.js +54 -0
  14. package/rules/enforce-id.d.ts +4 -0
  15. package/rules/enforce-id.d.ts.map +1 -0
  16. package/rules/enforce-id.js +125 -0
  17. package/rules/enforce-placeholders.d.ts +4 -0
  18. package/rules/enforce-placeholders.d.ts.map +1 -0
  19. package/rules/enforce-placeholders.js +118 -0
  20. package/rules/enforce-plural-rules.d.ts +4 -0
  21. package/rules/enforce-plural-rules.d.ts.map +1 -0
  22. package/rules/enforce-plural-rules.js +104 -0
  23. package/rules/no-camel-case.d.ts +4 -0
  24. package/rules/no-camel-case.d.ts.map +1 -0
  25. package/rules/no-camel-case.js +77 -0
  26. package/rules/no-complex-selectors.d.ts +4 -0
  27. package/rules/no-complex-selectors.d.ts.map +1 -0
  28. package/rules/no-complex-selectors.js +99 -0
  29. package/rules/no-emoji.d.ts +4 -0
  30. package/rules/no-emoji.d.ts.map +1 -0
  31. package/rules/no-emoji.js +47 -0
  32. package/rules/no-id.d.ts +4 -0
  33. package/rules/no-id.d.ts.map +1 -0
  34. package/rules/no-id.js +52 -0
  35. package/rules/no-invalid-icu.d.ts +4 -0
  36. package/rules/no-invalid-icu.d.ts.map +1 -0
  37. package/rules/no-invalid-icu.js +54 -0
  38. package/rules/no-literal-string-in-jsx.d.ts +4 -0
  39. package/rules/no-literal-string-in-jsx.d.ts.map +1 -0
  40. package/rules/no-literal-string-in-jsx.js +166 -0
  41. package/rules/no-multiple-plurals.d.ts +4 -0
  42. package/rules/no-multiple-plurals.d.ts.map +1 -0
  43. package/rules/no-multiple-plurals.js +71 -0
  44. package/rules/no-multiple-whitespaces.d.ts +4 -0
  45. package/rules/no-multiple-whitespaces.d.ts.map +1 -0
  46. package/rules/no-multiple-whitespaces.js +146 -0
  47. package/rules/no-offset.d.ts +4 -0
  48. package/rules/no-offset.d.ts.map +1 -0
  49. package/rules/no-offset.js +70 -0
  50. package/util.d.ts +24 -0
  51. package/util.d.ts.map +1 -0
  52. package/util.js +240 -0
  53. package/BUILD +0 -89
  54. package/CHANGELOG.md +0 -892
  55. package/index.ts +0 -38
  56. package/rules/blocklist-elements.ts +0 -159
  57. package/rules/enforce-default-message.ts +0 -71
  58. package/rules/enforce-description.ts +0 -68
  59. package/rules/enforce-id.ts +0 -171
  60. package/rules/enforce-placeholders.ts +0 -161
  61. package/rules/enforce-plural-rules.ts +0 -134
  62. package/rules/no-camel-case.ts +0 -97
  63. package/rules/no-complex-selectors.ts +0 -125
  64. package/rules/no-emoji.ts +0 -60
  65. package/rules/no-id.ts +0 -63
  66. package/rules/no-invalid-icu.ts +0 -69
  67. package/rules/no-literal-string-in-jsx.ts +0 -213
  68. package/rules/no-multiple-plurals.ts +0 -89
  69. package/rules/no-multiple-whitespaces.ts +0 -194
  70. package/rules/no-offset.ts +0 -88
  71. package/tests/blocklist-elements.test.ts +0 -120
  72. package/tests/enforce-default-message.test.ts +0 -260
  73. package/tests/enforce-description.test.ts +0 -117
  74. package/tests/enforce-id.test.ts +0 -209
  75. package/tests/enforce-placeholders.test.ts +0 -170
  76. package/tests/enforce-plural-rules.test.ts +0 -86
  77. package/tests/fixtures.ts +0 -15
  78. package/tests/no-camel-case.test.ts +0 -31
  79. package/tests/no-complex-selectors.test.ts +0 -125
  80. package/tests/no-id.test.ts +0 -151
  81. package/tests/no-invalid-icu.test.ts +0 -106
  82. package/tests/no-literal-string-in-jsx.test.ts +0 -213
  83. package/tests/no-multiple-plurals.test.ts +0 -42
  84. package/tests/no-multiple-whitespaces.test.ts +0 -100
  85. package/tests/no-offset.test.ts +0 -41
  86. package/tests/util.ts +0 -26
  87. package/tsconfig.json +0 -5
  88. package/util.ts +0 -307
package/util.ts DELETED
@@ -1,307 +0,0 @@
1
- import {Rule} from 'eslint'
2
- import {TSESTree} from '@typescript-eslint/typescript-estree'
3
-
4
- export interface MessageDescriptor {
5
- id?: string
6
- defaultMessage?: string
7
- description?: string | object
8
- }
9
-
10
- const FORMAT_FUNCTION_NAMES = new Set(['$formatMessage', 'formatMessage'])
11
- const COMPONENT_NAMES = new Set(['FormattedMessage'])
12
- const DECLARATION_FUNCTION_NAMES = new Set(['defineMessage'])
13
-
14
- export interface Settings {
15
- excludeMessageDeclCalls?: boolean
16
- additionalFunctionNames?: string[]
17
- additionalComponentNames?: string[]
18
- ignoreTag?: boolean
19
- }
20
- export interface MessageDescriptorNodeInfo {
21
- message: MessageDescriptor
22
- messageNode?: TSESTree.Property['value'] | TSESTree.JSXAttribute['value']
23
- messagePropNode?: TSESTree.Property | TSESTree.JSXAttribute
24
- descriptionNode?: TSESTree.Property['value'] | TSESTree.JSXAttribute['value']
25
- idValueNode?: TSESTree.Property['value'] | TSESTree.JSXAttribute['value']
26
- idPropNode?: TSESTree.Property | TSESTree.JSXAttribute
27
- }
28
-
29
- export function getSettings({settings}: Rule.RuleContext): Settings {
30
- return settings.formatjs ?? settings
31
- }
32
-
33
- function isStringLiteral(node: TSESTree.Node): node is TSESTree.StringLiteral {
34
- return node.type === 'Literal' && typeof node.value === 'string'
35
- }
36
-
37
- function isTemplateLiteralWithoutVar(
38
- node: TSESTree.Node
39
- ): node is TSESTree.TemplateLiteral {
40
- return node.type === 'TemplateLiteral' && node.quasis.length === 1
41
- }
42
-
43
- function staticallyEvaluateStringConcat(
44
- node: TSESTree.BinaryExpression
45
- ): [result: string, isStaticallyEvaluatable: boolean] {
46
- if (!isStringLiteral(node.right)) {
47
- return ['', false]
48
- }
49
- if (isStringLiteral(node.left)) {
50
- return [String(node.left.value) + node.right.value, true]
51
- }
52
- if (node.left.type === 'BinaryExpression') {
53
- const [result, isStaticallyEvaluatable] = staticallyEvaluateStringConcat(
54
- node.left
55
- )
56
- return [result + node.right.value, isStaticallyEvaluatable]
57
- }
58
- return ['', false]
59
- }
60
-
61
- function isIntlFormatMessageCall(node: TSESTree.Node) {
62
- return (
63
- node.type === 'CallExpression' &&
64
- node.callee.type === 'MemberExpression' &&
65
- node.callee.object.type === 'Identifier' &&
66
- node.callee.object.name === 'intl' &&
67
- node.callee.property.type === 'Identifier' &&
68
- node.callee.property.name === 'formatMessage' &&
69
- node.arguments.length >= 1 &&
70
- node.arguments[0].type === 'ObjectExpression'
71
- )
72
- }
73
-
74
- function isSingleMessageDescriptorDeclaration(
75
- node: TSESTree.Node,
76
- functionNames: Set<string>
77
- ) {
78
- return (
79
- node.type === 'CallExpression' &&
80
- node.callee.type === 'Identifier' &&
81
- functionNames.has(node.callee.name)
82
- )
83
- }
84
-
85
- function isMultipleMessageDescriptorDeclaration(node: TSESTree.Node) {
86
- return (
87
- node.type === 'CallExpression' &&
88
- node.callee.type === 'Identifier' &&
89
- node.callee.name === 'defineMessages'
90
- )
91
- }
92
-
93
- function extractMessageDescriptor(
94
- node?: TSESTree.Expression
95
- ): MessageDescriptorNodeInfo | undefined {
96
- if (!node || node.type !== 'ObjectExpression') {
97
- return
98
- }
99
- const result: MessageDescriptorNodeInfo = {
100
- message: {},
101
- messageNode: undefined,
102
- messagePropNode: undefined,
103
- descriptionNode: undefined,
104
- idValueNode: undefined,
105
- }
106
- for (const prop of node.properties) {
107
- if (prop.type !== 'Property' || prop.key.type !== 'Identifier') {
108
- continue
109
- }
110
- const valueNode = prop.value
111
- let value: string | undefined = undefined
112
- if (isStringLiteral(valueNode)) {
113
- value = valueNode.value
114
- } else if (isTemplateLiteralWithoutVar(valueNode)) {
115
- value = valueNode.quasis[0].value.cooked
116
- } else if (valueNode.type === 'BinaryExpression') {
117
- const [result, isStatic] = staticallyEvaluateStringConcat(valueNode)
118
- if (isStatic) {
119
- value = result
120
- }
121
- }
122
-
123
- switch (prop.key.name) {
124
- case 'defaultMessage':
125
- result.messagePropNode = prop
126
- result.messageNode = valueNode
127
- result.message.defaultMessage = value
128
- break
129
- case 'description':
130
- result.descriptionNode = valueNode
131
- result.message.description = value
132
- break
133
- case 'id':
134
- result.message.id = value
135
- result.idValueNode = valueNode
136
- result.idPropNode = prop
137
- break
138
- }
139
- }
140
- return result
141
- }
142
-
143
- function extractMessageDescriptorFromJSXElement(
144
- node?: TSESTree.JSXOpeningElement
145
- ):
146
- | [MessageDescriptorNodeInfo, TSESTree.ObjectExpression | undefined]
147
- | undefined {
148
- if (!node || !node.attributes) {
149
- return
150
- }
151
- let values: TSESTree.ObjectExpression | undefined
152
- const result: MessageDescriptorNodeInfo = {
153
- message: {},
154
- messageNode: undefined,
155
- messagePropNode: undefined,
156
- descriptionNode: undefined,
157
- idValueNode: undefined,
158
- idPropNode: undefined,
159
- }
160
- let hasSpreadAttribute = false
161
- for (const prop of node.attributes) {
162
- // We can't analyze spread attr
163
- if (prop.type === 'JSXSpreadAttribute') {
164
- hasSpreadAttribute = true
165
- }
166
- if (prop.type !== 'JSXAttribute' || prop.name.type !== 'JSXIdentifier') {
167
- continue
168
- }
169
- const key = prop.name
170
- let valueNode = prop.value
171
- let value: string | undefined = undefined
172
- if (valueNode) {
173
- if (isStringLiteral(valueNode)) {
174
- value = valueNode.value
175
- } else if (valueNode?.type === 'JSXExpressionContainer') {
176
- const {expression} = valueNode
177
- if (expression.type === 'BinaryExpression') {
178
- const [result, isStatic] = staticallyEvaluateStringConcat(expression)
179
- if (isStatic) {
180
- value = result
181
- }
182
- } else if (isTemplateLiteralWithoutVar(expression)) {
183
- value = expression.quasis[0].value.cooked
184
- }
185
- }
186
- }
187
-
188
- switch (key.name) {
189
- case 'defaultMessage':
190
- result.messagePropNode = prop
191
- result.messageNode = valueNode
192
- if (value) {
193
- result.message.defaultMessage = value
194
- }
195
- break
196
- case 'description':
197
- result.descriptionNode = valueNode
198
- if (value) {
199
- result.message.description = value
200
- }
201
- break
202
- case 'id':
203
- result.idValueNode = valueNode
204
- result.idPropNode = prop
205
- if (value) {
206
- result.message.id = value
207
- }
208
- break
209
- case 'values':
210
- if (
211
- valueNode?.type === 'JSXExpressionContainer' &&
212
- valueNode.expression.type === 'ObjectExpression'
213
- ) {
214
- values = valueNode.expression
215
- }
216
- break
217
- }
218
- }
219
- if (
220
- !result.messagePropNode &&
221
- !result.descriptionNode &&
222
- !result.idPropNode &&
223
- hasSpreadAttribute
224
- ) {
225
- return
226
- }
227
- return [result, values]
228
- }
229
-
230
- function extractMessageDescriptors(node?: TSESTree.Expression) {
231
- if (!node || node.type !== 'ObjectExpression' || !node.properties.length) {
232
- return []
233
- }
234
- const msgs = []
235
- for (const prop of node.properties) {
236
- if (prop.type !== 'Property') {
237
- continue
238
- }
239
- const msg = prop.value
240
- if (msg.type !== 'ObjectExpression') {
241
- continue
242
- }
243
- const nodeInfo = extractMessageDescriptor(msg)
244
- if (nodeInfo) {
245
- msgs.push(nodeInfo)
246
- }
247
- }
248
- return msgs
249
- }
250
-
251
- export function extractMessages(
252
- node: TSESTree.Node,
253
- {
254
- additionalComponentNames,
255
- additionalFunctionNames,
256
- excludeMessageDeclCalls,
257
- }: Settings = {}
258
- ): Array<[MessageDescriptorNodeInfo, TSESTree.Expression | undefined]> {
259
- const allFormatFunctionNames = Array.isArray(additionalFunctionNames)
260
- ? new Set([
261
- ...Array.from(FORMAT_FUNCTION_NAMES),
262
- ...additionalFunctionNames,
263
- ])
264
- : FORMAT_FUNCTION_NAMES
265
- const allComponentNames = Array.isArray(additionalComponentNames)
266
- ? new Set([...Array.from(COMPONENT_NAMES), ...additionalComponentNames])
267
- : COMPONENT_NAMES
268
- if (node.type === 'CallExpression') {
269
- const expr = node
270
- const args0 = expr.arguments[0]
271
- const args1 = expr.arguments[1]
272
- // We can't really analyze spread element
273
- if (!args0 || args0.type === 'SpreadElement') {
274
- return []
275
- }
276
- if (
277
- (!excludeMessageDeclCalls &&
278
- isSingleMessageDescriptorDeclaration(
279
- node,
280
- DECLARATION_FUNCTION_NAMES
281
- )) ||
282
- isIntlFormatMessageCall(node) ||
283
- isSingleMessageDescriptorDeclaration(node, allFormatFunctionNames)
284
- ) {
285
- const msgDescriptorNodeInfo = extractMessageDescriptor(args0)
286
- if (msgDescriptorNodeInfo && (!args1 || args1.type !== 'SpreadElement')) {
287
- return [[msgDescriptorNodeInfo, args1]]
288
- }
289
- } else if (
290
- !excludeMessageDeclCalls &&
291
- isMultipleMessageDescriptorDeclaration(node)
292
- ) {
293
- return extractMessageDescriptors(args0).map(msg => [msg, undefined])
294
- }
295
- } else if (
296
- node.type === 'JSXOpeningElement' &&
297
- node.name &&
298
- node.name.type === 'JSXIdentifier' &&
299
- allComponentNames.has(node.name.name)
300
- ) {
301
- const msgDescriptorNodeInfo = extractMessageDescriptorFromJSXElement(node)
302
- if (msgDescriptorNodeInfo) {
303
- return [msgDescriptorNodeInfo]
304
- }
305
- }
306
- return []
307
- }