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
@@ -1,213 +0,0 @@
1
- import picomatch from 'picomatch'
2
- import type {Rule} from 'eslint'
3
- import {TSESTree} from '@typescript-eslint/typescript-estree'
4
-
5
- type PropMatcher = readonly [TagNamePattern: string, PropNamePattern: string][]
6
-
7
- type CompiledPropMatcher = readonly [
8
- TagNamePattern: RegExp,
9
- PropNamePattern: RegExp
10
- ][]
11
-
12
- type Config = {
13
- props?: {
14
- include?: PropMatcher
15
- exclude?: PropMatcher
16
- }
17
- }
18
-
19
- const propMatcherSchema = {
20
- type: 'array',
21
- items: {
22
- type: 'array',
23
- items: [{type: 'string'}, {type: 'string'}],
24
- },
25
- } as const
26
-
27
- const defaultPropIncludePattern: PropMatcher = [
28
- ['*', 'aria-{label,description,details,errormessage}'],
29
- ['[a-z]*([a-z0-9])', '(placeholder|title)'],
30
- ['img', 'alt'],
31
- ]
32
-
33
- const defaultPropExcludePattern: PropMatcher = []
34
-
35
- function stringifyJsxTagName(tagName: TSESTree.JSXTagNameExpression): string {
36
- switch (tagName.type) {
37
- case TSESTree.AST_NODE_TYPES.JSXIdentifier:
38
- return tagName.name
39
- case TSESTree.AST_NODE_TYPES.JSXMemberExpression:
40
- return `${stringifyJsxTagName(tagName.object)}.${tagName.property.name}`
41
- case TSESTree.AST_NODE_TYPES.JSXNamespacedName:
42
- return `${tagName.namespace.name}:${tagName.name.name}`
43
- }
44
- }
45
-
46
- function compilePropMatcher(propMatcher: PropMatcher): CompiledPropMatcher {
47
- return propMatcher.map(([tagNamePattern, propNamePattern]) => {
48
- return [
49
- picomatch.makeRe(tagNamePattern, {contains: false}),
50
- picomatch.makeRe(propNamePattern, {contains: false}),
51
- ]
52
- })
53
- }
54
-
55
- const rule: Rule.RuleModule = {
56
- meta: {
57
- type: 'problem',
58
- docs: {
59
- description: 'Disallow untranslated literal strings without translation.',
60
- category: 'Errors',
61
- recommended: false,
62
- url: 'https://formatjs.io/docs/tooling/linter#no-literal-string-in-jsx',
63
- },
64
- schema: [
65
- {
66
- type: 'object',
67
- properties: {
68
- props: {
69
- type: 'object',
70
- properties: {
71
- include: {
72
- ...propMatcherSchema,
73
- },
74
- exclude: {
75
- ...propMatcherSchema,
76
- },
77
- },
78
- },
79
- },
80
- },
81
- ],
82
- },
83
- // TODO: Vue support
84
- create(context) {
85
- const userConfig: Config = context.options[0] || {}
86
-
87
- const propIncludePattern: CompiledPropMatcher = compilePropMatcher([
88
- ...defaultPropIncludePattern,
89
- ...(userConfig.props?.include ?? []),
90
- ])
91
-
92
- const propExcludePattern: CompiledPropMatcher = compilePropMatcher([
93
- ...defaultPropExcludePattern,
94
- ...(userConfig.props?.exclude ?? []),
95
- ])
96
-
97
- const lexicalJsxStack: (TSESTree.JSXElement | TSESTree.JSXFragment)[] = []
98
-
99
- const shouldSkipCurrentJsxAttribute = (node: TSESTree.JSXAttribute) => {
100
- const currentJsxNode = lexicalJsxStack[lexicalJsxStack.length - 1]!
101
- if (currentJsxNode.type === 'JSXFragment') {
102
- return false
103
- }
104
-
105
- const nameString = stringifyJsxTagName(currentJsxNode.openingElement.name)
106
- const attributeName =
107
- typeof node.name.name === 'string'
108
- ? node.name.name
109
- : node.name.name.name
110
-
111
- // match exclude
112
- for (const [tagNamePattern, propNamePattern] of propExcludePattern) {
113
- if (
114
- tagNamePattern.test(nameString) &&
115
- propNamePattern.test(attributeName)
116
- ) {
117
- return true
118
- }
119
- }
120
-
121
- // match include
122
- for (const [tagNamePattern, propNamePattern] of propIncludePattern) {
123
- if (
124
- tagNamePattern.test(nameString) &&
125
- propNamePattern.test(attributeName)
126
- ) {
127
- return false
128
- }
129
- }
130
-
131
- return true
132
- }
133
-
134
- const checkJSXExpression = (
135
- node: TSESTree.Expression | TSESTree.PrivateIdentifier
136
- ) => {
137
- // Check if this is either a string literal / template literal, or the concat of them.
138
- if (
139
- (node.type === 'Literal' && typeof node.value === 'string') ||
140
- node.type === 'TemplateLiteral'
141
- ) {
142
- context.report({
143
- node: node as any,
144
- message: 'Cannot have untranslated text in JSX',
145
- })
146
- } else if (node.type === 'BinaryExpression' && node.operator === '+') {
147
- checkJSXExpression(node.left)
148
- checkJSXExpression(node.right)
149
- }
150
- }
151
-
152
- return {
153
- JSXElement: (node: TSESTree.Node) => {
154
- lexicalJsxStack.push(node as TSESTree.JSXElement)
155
- },
156
- 'JSXElement:exit': () => {
157
- lexicalJsxStack.pop()
158
- },
159
-
160
- JSXFragment: (node: TSESTree.Node) => {
161
- lexicalJsxStack.push(node as TSESTree.JSXFragment)
162
- },
163
- 'JSXFragment:exit': () => {
164
- lexicalJsxStack.pop()
165
- },
166
-
167
- JSXAttribute: (node: TSESTree.JSXAttribute) => {
168
- if (shouldSkipCurrentJsxAttribute(node)) {
169
- return
170
- }
171
-
172
- if (!node.value) {
173
- return
174
- }
175
-
176
- if (node.value.type === 'Literal') {
177
- context.report({
178
- node: node as any,
179
- message: 'Cannot have untranslated text in JSX',
180
- })
181
- } else if (
182
- node.value.type === 'JSXExpressionContainer' &&
183
- node.value.expression.type !== 'JSXEmptyExpression'
184
- ) {
185
- checkJSXExpression(node.value.expression)
186
- }
187
- },
188
-
189
- JSXText: (node: TSESTree.JSXText) => {
190
- // Ignore purely spacing fragments
191
- if (!node.value.replace(/\s*/gm, '')) {
192
- return
193
- }
194
-
195
- context.report({
196
- node: node as any,
197
- message: 'Cannot have untranslated text in JSX',
198
- })
199
- },
200
-
201
- // Children expression container
202
- 'JSXElement > JSXExpressionContainer': (
203
- node: TSESTree.JSXExpressionContainer
204
- ) => {
205
- if (node.expression.type !== 'JSXEmptyExpression') {
206
- checkJSXExpression(node.expression)
207
- }
208
- },
209
- } as any
210
- },
211
- }
212
-
213
- export default rule
@@ -1,89 +0,0 @@
1
- import {Rule} from 'eslint'
2
- import {TSESTree} from '@typescript-eslint/typescript-estree'
3
- import {extractMessages, getSettings} from '../util'
4
- import {
5
- parse,
6
- isPluralElement,
7
- MessageFormatElement,
8
- } from '@formatjs/icu-messageformat-parser'
9
-
10
- class MultiplePlurals extends Error {
11
- public message = 'Cannot specify more than 1 plural rules'
12
- }
13
-
14
- function verifyAst(ast: MessageFormatElement[], pluralCount = {count: 0}) {
15
- for (const el of ast) {
16
- if (isPluralElement(el)) {
17
- pluralCount.count++
18
- if (pluralCount.count > 1) {
19
- throw new MultiplePlurals()
20
- }
21
- const {options} = el
22
- for (const selector of Object.keys(options)) {
23
- verifyAst(options[selector].value, pluralCount)
24
- }
25
- }
26
- }
27
- }
28
-
29
- function checkNode(context: Rule.RuleContext, node: TSESTree.Node) {
30
- const settings = getSettings(context)
31
- const msgs = extractMessages(node, settings)
32
-
33
- for (const [
34
- {
35
- message: {defaultMessage},
36
- messageNode,
37
- },
38
- ] of msgs) {
39
- if (!defaultMessage || !messageNode) {
40
- continue
41
- }
42
- try {
43
- verifyAst(
44
- parse(defaultMessage, {
45
- ignoreTag: settings.ignoreTag,
46
- })
47
- )
48
- } catch (e) {
49
- context.report({
50
- node: messageNode as any,
51
- message: e instanceof Error ? e.message : String(e),
52
- })
53
- }
54
- }
55
- }
56
-
57
- const rule: Rule.RuleModule = {
58
- meta: {
59
- type: 'problem',
60
- docs: {
61
- description: 'Disallow multiple plural rules in the same message',
62
- category: 'Errors',
63
- recommended: false,
64
- url: 'https://formatjs.io/docs/tooling/linter#no-multiple-plurals',
65
- },
66
- fixable: 'code',
67
- },
68
- create(context) {
69
- const callExpressionVisitor = (node: TSESTree.Node) =>
70
- checkNode(context, node)
71
-
72
- if (context.parserServices.defineTemplateBodyVisitor) {
73
- return context.parserServices.defineTemplateBodyVisitor(
74
- {
75
- CallExpression: callExpressionVisitor,
76
- },
77
- {
78
- CallExpression: callExpressionVisitor,
79
- }
80
- )
81
- }
82
- return {
83
- JSXOpeningElement: (node: TSESTree.Node) => checkNode(context, node),
84
- CallExpression: callExpressionVisitor,
85
- }
86
- },
87
- }
88
-
89
- export default rule
@@ -1,194 +0,0 @@
1
- import {
2
- LiteralElement,
3
- MessageFormatElement,
4
- parse,
5
- TYPE,
6
- } from '@formatjs/icu-messageformat-parser'
7
- import {TSESTree} from '@typescript-eslint/typescript-estree'
8
- import {Rule} from 'eslint'
9
- import {extractMessages, getSettings} from '../util'
10
-
11
- function isAstValid(ast: MessageFormatElement[]): boolean {
12
- for (const element of ast) {
13
- switch (element.type) {
14
- case TYPE.literal:
15
- if (/\s{2,}/gm.test(element.value)) {
16
- return false
17
- }
18
- break
19
- case TYPE.argument:
20
- case TYPE.date:
21
- case TYPE.literal:
22
- case TYPE.number:
23
- case TYPE.pound:
24
- case TYPE.tag:
25
- case TYPE.time:
26
- break
27
- case TYPE.plural:
28
- case TYPE.select: {
29
- for (const option of Object.values(element.options)) {
30
- if (!isAstValid(option.value)) {
31
- return false
32
- }
33
- }
34
- break
35
- }
36
- }
37
- }
38
- return true
39
- }
40
-
41
- function trimMultiWhitespaces(
42
- message: string,
43
- ast: MessageFormatElement[]
44
- ): string {
45
- const literalElements: LiteralElement[] = []
46
-
47
- const collectLiteralElements = (elements: MessageFormatElement[]) => {
48
- for (const element of elements) {
49
- switch (element.type) {
50
- case TYPE.literal:
51
- literalElements.push(element)
52
- break
53
- case TYPE.argument:
54
- case TYPE.date:
55
- case TYPE.literal:
56
- case TYPE.number:
57
- case TYPE.pound:
58
- case TYPE.tag:
59
- case TYPE.time:
60
- break
61
- case TYPE.plural:
62
- case TYPE.select: {
63
- for (const option of Object.values(element.options)) {
64
- collectLiteralElements(option.value)
65
- }
66
- break
67
- }
68
- }
69
- }
70
- }
71
- collectLiteralElements(ast)
72
-
73
- // Surgically trim whitespaces in the literal element ranges.
74
- // This is to preserve the original whitespaces and newlines info that are lost to parsing.
75
- let trimmedFragments: string[] = []
76
- let currentOffset = 0
77
-
78
- for (const literal of literalElements) {
79
- const {start, end} = literal.location!
80
- const startOffset = start.offset
81
- const endOffset = end.offset
82
-
83
- trimmedFragments.push(message.slice(currentOffset, startOffset))
84
- trimmedFragments.push(
85
- message.slice(startOffset, endOffset).replace(/\s{2,}/gm, ' ')
86
- )
87
-
88
- currentOffset = endOffset
89
- }
90
-
91
- trimmedFragments.push(message.slice(currentOffset))
92
-
93
- return trimmedFragments.join('')
94
- }
95
-
96
- function checkNode(context: Rule.RuleContext, node: TSESTree.Node) {
97
- const msgs = extractMessages(node, getSettings(context))
98
-
99
- for (const [
100
- {
101
- message: {defaultMessage},
102
- messageNode,
103
- },
104
- ] of msgs) {
105
- if (!defaultMessage || !messageNode) {
106
- continue
107
- }
108
-
109
- let ast: MessageFormatElement[]
110
- try {
111
- ast = parse(defaultMessage, {captureLocation: true})
112
- } catch (e) {
113
- context.report({
114
- node: messageNode as any,
115
- message: e instanceof Error ? e.message : String(e),
116
- })
117
- return
118
- }
119
-
120
- if (!isAstValid(ast)) {
121
- const reportObject: Parameters<typeof context['report']>[0] = {
122
- node: messageNode as any,
123
- message: 'Multiple consecutive whitespaces are not allowed',
124
- }
125
-
126
- if (
127
- messageNode.type === 'Literal' &&
128
- messageNode.value &&
129
- typeof messageNode.value === 'string'
130
- ) {
131
- reportObject.fix = function (fixer) {
132
- return fixer.replaceText(
133
- messageNode as any,
134
- JSON.stringify(
135
- trimMultiWhitespaces(messageNode.value as string, ast)
136
- )
137
- )
138
- }
139
- } else if (
140
- messageNode.type === 'TemplateLiteral' &&
141
- messageNode.quasis.length === 1 &&
142
- messageNode.expressions.length === 0
143
- ) {
144
- reportObject.fix = function (fixer) {
145
- return fixer.replaceText(
146
- messageNode as any,
147
- '`' +
148
- trimMultiWhitespaces(messageNode.quasis[0].value.cooked, ast)
149
- .replace(/\\/g, '\\\\')
150
- .replace(/`/g, '\\`') +
151
- '`'
152
- )
153
- }
154
- }
155
-
156
- context.report(reportObject)
157
- }
158
- }
159
- }
160
-
161
- const rule: Rule.RuleModule = {
162
- meta: {
163
- type: 'problem',
164
- docs: {
165
- description:
166
- 'Prevents usage of multiple consecutive whitespaces in message',
167
- category: 'Errors',
168
- recommended: false,
169
- url: 'https://formatjs.io/docs/tooling/linter#no-multiple-whitespaces',
170
- },
171
- fixable: 'code',
172
- },
173
- create(context) {
174
- const callExpressionVisitor = (node: TSESTree.Node) =>
175
- checkNode(context, node)
176
-
177
- if (context.parserServices.defineTemplateBodyVisitor) {
178
- return context.parserServices.defineTemplateBodyVisitor(
179
- {
180
- CallExpression: callExpressionVisitor,
181
- },
182
- {
183
- CallExpression: callExpressionVisitor,
184
- }
185
- )
186
- }
187
- return {
188
- JSXOpeningElement: (node: TSESTree.Node) => checkNode(context, node),
189
- CallExpression: callExpressionVisitor,
190
- }
191
- },
192
- }
193
-
194
- export default rule
@@ -1,88 +0,0 @@
1
- import {Rule} from 'eslint'
2
- import {TSESTree} from '@typescript-eslint/typescript-estree'
3
- import {extractMessages, getSettings} from '../util'
4
- import {
5
- parse,
6
- isPluralElement,
7
- MessageFormatElement,
8
- } from '@formatjs/icu-messageformat-parser'
9
-
10
- class NoOffsetError extends Error {
11
- public message = 'offset are not allowed in plural rules'
12
- }
13
-
14
- function verifyAst(ast: MessageFormatElement[]) {
15
- for (const el of ast) {
16
- if (isPluralElement(el)) {
17
- if (el.offset) {
18
- throw new NoOffsetError()
19
- }
20
- const {options} = el
21
- for (const selector of Object.keys(options)) {
22
- verifyAst(options[selector].value)
23
- }
24
- }
25
- }
26
- }
27
-
28
- function checkNode(context: Rule.RuleContext, node: TSESTree.Node) {
29
- const settings = getSettings(context)
30
- const msgs = extractMessages(node, settings)
31
-
32
- for (const [
33
- {
34
- message: {defaultMessage},
35
- messageNode,
36
- },
37
- ] of msgs) {
38
- if (!defaultMessage || !messageNode) {
39
- continue
40
- }
41
- try {
42
- verifyAst(
43
- parse(defaultMessage, {
44
- ignoreTag: settings.ignoreTag,
45
- })
46
- )
47
- } catch (e) {
48
- context.report({
49
- node: messageNode as any,
50
- message: (e as Error).message,
51
- })
52
- }
53
- }
54
- }
55
-
56
- const rule: Rule.RuleModule = {
57
- meta: {
58
- type: 'problem',
59
- docs: {
60
- description: 'Disallow offset in plural rules',
61
- category: 'Errors',
62
- recommended: false,
63
- url: 'https://formatjs.io/docs/tooling/linter#no-offset',
64
- },
65
- fixable: 'code',
66
- },
67
- create(context) {
68
- const callExpressionVisitor = (node: TSESTree.Node) =>
69
- checkNode(context, node)
70
-
71
- if (context.parserServices.defineTemplateBodyVisitor) {
72
- return context.parserServices.defineTemplateBodyVisitor(
73
- {
74
- CallExpression: callExpressionVisitor,
75
- },
76
- {
77
- CallExpression: callExpressionVisitor,
78
- }
79
- )
80
- }
81
- return {
82
- JSXOpeningElement: (node: TSESTree.Node) => checkNode(context, node),
83
- CallExpression: callExpressionVisitor,
84
- }
85
- },
86
- }
87
-
88
- export default rule
@@ -1,120 +0,0 @@
1
- import blocklistElements from '../rules/blocklist-elements'
2
- import {dynamicMessage, emptyFnCall, noMatch, spreadJsx} from './fixtures'
3
- import {ruleTester, vueRuleTester} from './util'
4
-
5
- ruleTester.run('blocklist-elements', blocklistElements, {
6
- valid: [
7
- {
8
- code: `import {defineMessage} from 'react-intl'
9
- defineMessage({
10
- defaultMessage: '{count, plural, one {#} other {# more}}'
11
- })`,
12
- options: [['selectordinal']],
13
- },
14
- {
15
- code: `import {defineMessage} from 'react-intl'
16
- defineMessage({
17
- defaultMessage: '{count, plural, one {#} other {# more}} <a href="asd"></a>'
18
- })`,
19
- options: [['selectordinal']],
20
- settings: {
21
- formatjs: {
22
- ignoreTag: true,
23
- },
24
- },
25
- },
26
- {
27
- code: `
28
- $t({
29
- defaultMessage: '{count, plural, one {#} other {# more}}'
30
- })`,
31
- options: [['selectordinal']],
32
- settings: {
33
- formatjs: {
34
- additionalFunctionNames: ['$t'],
35
- },
36
- },
37
- },
38
- dynamicMessage,
39
- noMatch,
40
- spreadJsx,
41
- emptyFnCall,
42
- ],
43
- invalid: [
44
- {
45
- code: `
46
- import {defineMessage} from 'react-intl'
47
- defineMessage({
48
- defaultMessage: '{count, selectordinal, offset:1 one {#} other {# more}}'
49
- })`,
50
- options: [['selectordinal']],
51
- errors: [
52
- {
53
- message: 'selectordinal element is blocklisted',
54
- },
55
- ],
56
- },
57
- {
58
- code: `
59
- $t({
60
- defaultMessage: '{count, selectordinal, offset:1 one {#} other {# more}}'
61
- })`,
62
- options: [['selectordinal']],
63
- settings: {
64
- formatjs: {
65
- additionalFunctionNames: ['$t'],
66
- },
67
- },
68
- errors: [
69
- {
70
- message: 'selectordinal element is blocklisted',
71
- },
72
- ],
73
- },
74
- ],
75
- })
76
-
77
- vueRuleTester.run('vue/blocklist-elements', blocklistElements, {
78
- valid: [
79
- {
80
- code: `<template>
81
- <p>{{ $formatMessage({
82
- defaultMessage: '{count, plural, offset:1 one {#} other {# more} }'
83
- }) }} World!</p>
84
- </template>`,
85
- options: [['selectordinal']],
86
- },
87
- `<script>${dynamicMessage}</script>`,
88
- `<script>${noMatch}</script>`,
89
- `<script>${emptyFnCall}</script>`,
90
- ],
91
- invalid: [
92
- {
93
- code: `
94
- <script>
95
- intl.formatMessage({
96
- defaultMessage: '{count, selectordinal, offset:1 one {#} other {# more}}'
97
- })</script>`,
98
- options: [['selectordinal']],
99
- errors: [
100
- {
101
- message: 'selectordinal element is blocklisted',
102
- },
103
- ],
104
- },
105
- {
106
- code: `
107
- <template>
108
- <p>{{ $formatMessage({
109
- defaultMessage: '{count, selectordinal, offset:1 one {#} other {# more} }'
110
- }) }} World!</p>
111
- </template>`,
112
- options: [['selectordinal']],
113
- errors: [
114
- {
115
- message: 'selectordinal element is blocklisted',
116
- },
117
- ],
118
- },
119
- ],
120
- })