@gitlab/eslint-plugin 9.1.0 → 10.0.0
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.
- package/CHANGELOG.md +36 -0
- package/docs/rules/require-valid-i18n-helpers.md +41 -0
- package/docs/rules/vue-require-valid-i18n-helpers.md +42 -0
- package/docs/rules.md +2 -2
- package/lib/configs/default.js +0 -1
- package/lib/configs/i18n.js +2 -0
- package/lib/index.js +2 -1
- package/lib/rules/require-i18n-strings.js +5 -11
- package/lib/rules/require-valid-i18n-helpers.js +29 -0
- package/lib/rules/vue-require-valid-i18n-helpers.js +30 -0
- package/lib/utils/i18n-utils.js +68 -0
- package/lib/utils/rule-utils.js +27 -0
- package/package.json +1 -1
- package/docs/rules/require-string-literal-i18n-helpers.md +0 -26
- package/lib/rules/require-string-literal-i18n-helpers.js +0 -61
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,39 @@
|
|
|
1
|
+
# [10.0.0](https://gitlab.com/gitlab-org/frontend/eslint-plugin/compare/v9.4.0...v10.0.0) (2021-11-03)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* lint against missing translation namespaces ([db00d87](https://gitlab.com/gitlab-org/frontend/eslint-plugin/commit/db00d87e3877fa0fe538775280a54fd820c89572))
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### BREAKING CHANGES
|
|
10
|
+
|
|
11
|
+
* require-string-literal-i18n-helpers and
|
|
12
|
+
vue-require-string-literal-i18n-helpers rules have been renamed to
|
|
13
|
+
require-valid-i18n-helpers and vue-require-valid-i18n-helpers
|
|
14
|
+
respectively.
|
|
15
|
+
|
|
16
|
+
# [9.4.0](https://gitlab.com/gitlab-org/frontend/eslint-plugin/compare/v9.3.0...v9.4.0) (2021-09-21)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
### Features
|
|
20
|
+
|
|
21
|
+
* Ignore import path order ([9391f9c](https://gitlab.com/gitlab-org/frontend/eslint-plugin/commit/9391f9c83fd016a8d6ea10e6eae6f44e79907c14))
|
|
22
|
+
|
|
23
|
+
# [9.3.0](https://gitlab.com/gitlab-org/frontend/eslint-plugin/compare/v9.2.0...v9.3.0) (2021-09-06)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
### Features
|
|
27
|
+
|
|
28
|
+
* add vue-require-string-literal-i18n-helpers rule ([34fd19d](https://gitlab.com/gitlab-org/frontend/eslint-plugin/commit/34fd19df7d14f5d1c62b6795927e0ff15e3aaf44))
|
|
29
|
+
|
|
30
|
+
# [9.2.0](https://gitlab.com/gitlab-org/frontend/eslint-plugin/compare/v9.1.0...v9.2.0) (2021-08-30)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
### Features
|
|
34
|
+
|
|
35
|
+
* enable require-string-literal-i18n-helpers ([04b6dee](https://gitlab.com/gitlab-org/frontend/eslint-plugin/commit/04b6dee2ac4efa8e9fe0941f96ad48c179b0a2ca))
|
|
36
|
+
|
|
1
37
|
# [9.1.0](https://gitlab.com/gitlab-org/frontend/eslint-plugin/compare/v9.0.3...v9.1.0) (2021-08-26)
|
|
2
38
|
|
|
3
39
|
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# @gitlab/require-valid-i18n-helpers
|
|
2
|
+
|
|
3
|
+
This rule enforces valid usages of the translation helpers (`__`, `s__` and `n__`). It requires the
|
|
4
|
+
following:
|
|
5
|
+
|
|
6
|
+
- All helpers should be called with string-literal arguments to ensure the strings are properly
|
|
7
|
+
collected by the `gettext:regenerate` script.
|
|
8
|
+
- `s__` requires a translation namespace to be provided.
|
|
9
|
+
|
|
10
|
+
## Rule Details
|
|
11
|
+
|
|
12
|
+
### Examples of **incorrect** code for this rule
|
|
13
|
+
|
|
14
|
+
```js
|
|
15
|
+
// Invalid argument types
|
|
16
|
+
const label = __(LABEL);
|
|
17
|
+
const description = __(getDescription());
|
|
18
|
+
|
|
19
|
+
// Missing translation namespace
|
|
20
|
+
const namespacedTranslation = s__('NamespacedTranslation');
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### Examples of **correct** code for this rule
|
|
24
|
+
|
|
25
|
+
```js
|
|
26
|
+
// Valid argument type
|
|
27
|
+
const label = __('Some label');
|
|
28
|
+
|
|
29
|
+
// Valid translation namespace
|
|
30
|
+
const namespacedTranslation = s__('Namespace|Translation');
|
|
31
|
+
// or
|
|
32
|
+
const otherNamespacedTranslation = s__('Namespace', 'Other translation');
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Options
|
|
36
|
+
|
|
37
|
+
Nothing
|
|
38
|
+
|
|
39
|
+
## Related rules
|
|
40
|
+
|
|
41
|
+
- TBA
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# @gitlab/vue-require-valid-i18n-helpers
|
|
2
|
+
|
|
3
|
+
This rule is like [require-valid-i18n-helpers](./require-valid-i18n-helpers.md) for Vue templates.
|
|
4
|
+
|
|
5
|
+
## Rule Details
|
|
6
|
+
|
|
7
|
+
### Examples of **incorrect** code for this rule
|
|
8
|
+
|
|
9
|
+
```html
|
|
10
|
+
<template>
|
|
11
|
+
<div>
|
|
12
|
+
<!-- Invalid argument types -->
|
|
13
|
+
{{ __(LABEL) }}
|
|
14
|
+
{{ __(getDescription()) }}
|
|
15
|
+
|
|
16
|
+
<!-- Missing translation namespace -->
|
|
17
|
+
{{ s__('NamespacedTranslation') }}
|
|
18
|
+
</div>
|
|
19
|
+
</template>
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### Examples of **correct** code for this rule
|
|
23
|
+
|
|
24
|
+
```html
|
|
25
|
+
<template>
|
|
26
|
+
<div>
|
|
27
|
+
<!-- Valid argument type -->
|
|
28
|
+
{{ __('Some label') }}
|
|
29
|
+
|
|
30
|
+
<!-- Valid translation namespace -->
|
|
31
|
+
{{ s__('Namespace|Translation') }}
|
|
32
|
+
</div>
|
|
33
|
+
</template>
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Options
|
|
37
|
+
|
|
38
|
+
Nothing
|
|
39
|
+
|
|
40
|
+
## Related rules
|
|
41
|
+
|
|
42
|
+
- TBA
|
package/docs/rules.md
CHANGED
|
@@ -4,15 +4,15 @@
|
|
|
4
4
|
|
|
5
5
|
Available rules:
|
|
6
6
|
|
|
7
|
-
- [require-string-literal-i18n-helpers](./rules/require-string-literal-i18n-helpers.md): Requires
|
|
8
|
-
translation helpers to be called with string literals.
|
|
9
7
|
- [no-global-event-off](./rules/no-global-event-off.md): Throw an error when globally deregistering all event listeners.
|
|
10
8
|
- [no-runtime-template-compiler](./rules/no-runtime-template-compiler.md): Disallow components which rely on a runtime template compiler.
|
|
11
9
|
- [require-i18n-strings](./rules/require-i18n-strings.md): Detect a string which has been hard coded and requires externalization.
|
|
10
|
+
- [require-valid-i18n-helpers](./rules/require-valid-i18n-helpers.md): Enforces valid usage of translation helpers in JavaScript.
|
|
12
11
|
- [vue-emit-events-with-two-args](./rules/vue-emit-events-with-two-args.md): Throw an error when emit is called with more than two arguments.
|
|
13
12
|
- [vue-no-data-toggle](./rules/vue-no-data-toggle.md): Restrict the use of `data-toggle` bootstrap behaviors within Vue templates
|
|
14
13
|
- [vue-no-new-non-primitive-in-template](./rules/vue-no-new-non-primitive-in-template.md): Prevents non-primitive values from being declared in templates
|
|
15
14
|
- [vue-require-i18n-attribute-strings](./rules/vue-require-i18n-attribute-strings.md): Detect non externalized strings in vue `<template>` attributes
|
|
16
15
|
- [vue-require-i18n-strings](./rules/vue-require-i18n-strings.md): enforce no bare strings in vue `<template>`
|
|
17
16
|
- [vue-require-required-key](./rules/vue-require-required-key.md): Require the required key to be set
|
|
17
|
+
- [vue-require-valid-i18n-helpers](./rules/vue-require-valid-i18n-helpers.md): Enforces valid usage of translation helpers in Vue templates.
|
|
18
18
|
- [vue-slot-name-casing](./rules/vue-slot-name-casing.md): enforce specific casing for slot naming style in template
|
package/lib/configs/default.js
CHANGED
package/lib/configs/i18n.js
CHANGED
|
@@ -4,5 +4,7 @@ module.exports = {
|
|
|
4
4
|
'@gitlab/require-i18n-strings': 'error',
|
|
5
5
|
'@gitlab/vue-require-i18n-attribute-strings': 'error',
|
|
6
6
|
'@gitlab/vue-require-i18n-strings': 'error',
|
|
7
|
+
'@gitlab/require-valid-i18n-helpers': 'error',
|
|
8
|
+
'@gitlab/vue-require-valid-i18n-helpers': 'error',
|
|
7
9
|
},
|
|
8
10
|
};
|
package/lib/index.js
CHANGED
|
@@ -3,16 +3,17 @@
|
|
|
3
3
|
*/
|
|
4
4
|
module.exports = {
|
|
5
5
|
rules: {
|
|
6
|
-
'require-string-literal-i18n-helpers': require('./rules/require-string-literal-i18n-helpers.js'),
|
|
7
6
|
'no-global-event-off': require('./rules/no-global-event-off.js'),
|
|
8
7
|
'no-runtime-template-compiler': require('./rules/no-runtime-template-compiler.js'),
|
|
9
8
|
'require-i18n-strings': require('./rules/require-i18n-strings.js'),
|
|
9
|
+
'require-valid-i18n-helpers': require('./rules/require-valid-i18n-helpers.js'),
|
|
10
10
|
'vue-emit-events-with-two-args': require('./rules/vue-emit-events-with-two-args.js'),
|
|
11
11
|
'vue-no-data-toggle': require('./rules/vue-no-data-toggle.js'),
|
|
12
12
|
'vue-no-new-non-primitive-in-template': require('./rules/vue-no-new-non-primitive-in-template.js'),
|
|
13
13
|
'vue-require-i18n-attribute-strings': require('./rules/vue-require-i18n-attribute-strings.js'),
|
|
14
14
|
'vue-require-i18n-strings': require('./rules/vue-require-i18n-strings.js'),
|
|
15
15
|
'vue-require-required-key': require('./rules/vue-require-required-key.js'),
|
|
16
|
+
'vue-require-valid-i18n-helpers': require('./rules/vue-require-valid-i18n-helpers.js'),
|
|
16
17
|
'vue-slot-name-casing': require('./rules/vue-slot-name-casing.js'),
|
|
17
18
|
},
|
|
18
19
|
configs: {
|
|
@@ -4,6 +4,11 @@
|
|
|
4
4
|
*/
|
|
5
5
|
'use strict';
|
|
6
6
|
|
|
7
|
+
// ------------------------------------------------------------------------------
|
|
8
|
+
// Requirements
|
|
9
|
+
// ------------------------------------------------------------------------------
|
|
10
|
+
const { isTemplateLiteral, getTemplateLiteralString } = require('../utils/rule-utils');
|
|
11
|
+
|
|
7
12
|
//------------------------------------------------------------------------------
|
|
8
13
|
// Rule Definition
|
|
9
14
|
//------------------------------------------------------------------------------
|
|
@@ -269,21 +274,10 @@ module.exports = {
|
|
|
269
274
|
return node.type === 'Literal';
|
|
270
275
|
}
|
|
271
276
|
|
|
272
|
-
function isTemplateLiteral(node) {
|
|
273
|
-
return node.type === 'TemplateLiteral';
|
|
274
|
-
}
|
|
275
|
-
|
|
276
277
|
function stripVariables(value) {
|
|
277
278
|
return value ? value.replace(/(\%{[\w-]+})/g, '') : '';
|
|
278
279
|
}
|
|
279
280
|
|
|
280
|
-
function getTemplateLiteralString(node) {
|
|
281
|
-
return node.quasis
|
|
282
|
-
.filter((quasi) => quasi.type === 'TemplateElement')
|
|
283
|
-
.map((quasi) => quasi.value.raw)
|
|
284
|
-
.join('');
|
|
285
|
-
}
|
|
286
|
-
|
|
287
281
|
function getCallExpressionString(node, callee) {
|
|
288
282
|
if (callee.name === 'sprintf') {
|
|
289
283
|
return stripVariables(node.value);
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// ------------------------------------------------------------------------------
|
|
2
|
+
// Requirements
|
|
3
|
+
// ------------------------------------------------------------------------------
|
|
4
|
+
const { DOCS_BASE_URL } = require('../constants');
|
|
5
|
+
const { validateI18nHelperCallFactory } = require('../utils/i18n-utils');
|
|
6
|
+
|
|
7
|
+
// ------------------------------------------------------------------------------
|
|
8
|
+
// Rule Definition
|
|
9
|
+
// ------------------------------------------------------------------------------
|
|
10
|
+
|
|
11
|
+
module.exports = {
|
|
12
|
+
meta: {
|
|
13
|
+
type: 'error',
|
|
14
|
+
docs: {
|
|
15
|
+
description: 'Enforces valid usage of translation helpers in JavaScript.',
|
|
16
|
+
category: 'i18n',
|
|
17
|
+
url: DOCS_BASE_URL + '/require-valid-i18n-helpers.md',
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
create(context) {
|
|
21
|
+
const validateI18nHelperCall = validateI18nHelperCallFactory(context);
|
|
22
|
+
|
|
23
|
+
return {
|
|
24
|
+
CallExpression(node) {
|
|
25
|
+
validateI18nHelperCall(node);
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
},
|
|
29
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// ------------------------------------------------------------------------------
|
|
2
|
+
// Requirements
|
|
3
|
+
// ------------------------------------------------------------------------------
|
|
4
|
+
const { DOCS_BASE_URL } = require('../constants');
|
|
5
|
+
const { defineTemplateBodyVisitor } = require('../utils/index');
|
|
6
|
+
const { validateI18nHelperCallFactory } = require('../utils/i18n-utils');
|
|
7
|
+
|
|
8
|
+
// ------------------------------------------------------------------------------
|
|
9
|
+
// Rule Definition
|
|
10
|
+
// ------------------------------------------------------------------------------
|
|
11
|
+
|
|
12
|
+
module.exports = {
|
|
13
|
+
meta: {
|
|
14
|
+
type: 'error',
|
|
15
|
+
docs: {
|
|
16
|
+
description: 'Enforces valid usage of translation helpers in Vue templates.',
|
|
17
|
+
category: 'i18n',
|
|
18
|
+
url: DOCS_BASE_URL + '/vue-require-valid-i18n-helpers.md',
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
create(context) {
|
|
22
|
+
const validateI18nHelperCall = validateI18nHelperCallFactory(context);
|
|
23
|
+
|
|
24
|
+
return defineTemplateBodyVisitor(context, {
|
|
25
|
+
CallExpression(node) {
|
|
26
|
+
validateI18nHelperCall(node);
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
},
|
|
30
|
+
};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
const {
|
|
2
|
+
getFunctionName,
|
|
3
|
+
isString,
|
|
4
|
+
isTemplateLiteral,
|
|
5
|
+
getTemplateLiteralString,
|
|
6
|
+
} = require('../utils/rule-utils');
|
|
7
|
+
|
|
8
|
+
const GETTEXT = '__';
|
|
9
|
+
const P_GETTEXT = 's__';
|
|
10
|
+
const N_GETTEXT = 'n__';
|
|
11
|
+
|
|
12
|
+
const ERROR_MESSAGE_STRING_LITERAL = 'Translation helpers must be called with a string literal.';
|
|
13
|
+
const ERROR_MESSAGE_MISSING_NAMESPACE = 's__ requires a translation namespace to be provided.';
|
|
14
|
+
|
|
15
|
+
const mustBeCalledWithStringLiteralArguments = (context, node) => {
|
|
16
|
+
const report = (node) => {
|
|
17
|
+
context.report({
|
|
18
|
+
node,
|
|
19
|
+
message: ERROR_MESSAGE_STRING_LITERAL,
|
|
20
|
+
});
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
if (!node.arguments.length) {
|
|
24
|
+
report(node);
|
|
25
|
+
}
|
|
26
|
+
const [arg1, arg2] = node.arguments;
|
|
27
|
+
if ([arg1, arg2].some((arg) => arg && !isString(arg))) {
|
|
28
|
+
report(node);
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const mustHaveNamespace = (context, node) => {
|
|
33
|
+
if (node.arguments.length === 2) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const [arg] = node.arguments;
|
|
38
|
+
const value = isTemplateLiteral(arg) ? getTemplateLiteralString(arg).trim() : arg.value;
|
|
39
|
+
if (!/^\w.+\|/.test(value)) {
|
|
40
|
+
context.report({
|
|
41
|
+
node,
|
|
42
|
+
message: ERROR_MESSAGE_MISSING_NAMESPACE,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const VALIDATORS = {
|
|
48
|
+
[GETTEXT]: [mustBeCalledWithStringLiteralArguments],
|
|
49
|
+
[P_GETTEXT]: [mustBeCalledWithStringLiteralArguments, mustHaveNamespace],
|
|
50
|
+
[N_GETTEXT]: [mustBeCalledWithStringLiteralArguments],
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const validateI18nHelperCallFactory = (context) => (node) => {
|
|
54
|
+
const functionName = getFunctionName(node);
|
|
55
|
+
if (!Object.keys(VALIDATORS).includes(functionName)) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
VALIDATORS[functionName].forEach((validator) => {
|
|
60
|
+
validator(context, node);
|
|
61
|
+
});
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
module.exports = {
|
|
65
|
+
validateI18nHelperCallFactory,
|
|
66
|
+
ERROR_MESSAGE_STRING_LITERAL,
|
|
67
|
+
ERROR_MESSAGE_MISSING_NAMESPACE,
|
|
68
|
+
};
|
package/lib/utils/rule-utils.js
CHANGED
|
@@ -7,6 +7,7 @@ const V_TEXT = 'VText';
|
|
|
7
7
|
const V_ELEMENT = 'VElement';
|
|
8
8
|
const TEMPLATE_LITERAL = 'TemplateLiteral';
|
|
9
9
|
const LITERAL = 'Literal';
|
|
10
|
+
const IDENTIFIER = 'Identifier';
|
|
10
11
|
|
|
11
12
|
const NODE_TYPES = {
|
|
12
13
|
CALL_EXPRESSION,
|
|
@@ -18,6 +19,7 @@ const NODE_TYPES = {
|
|
|
18
19
|
V_ELEMENT,
|
|
19
20
|
TEMPLATE_LITERAL,
|
|
20
21
|
LITERAL,
|
|
22
|
+
IDENTIFIER,
|
|
21
23
|
};
|
|
22
24
|
|
|
23
25
|
function closest(node, predicate) {
|
|
@@ -39,6 +41,29 @@ function isString(node) {
|
|
|
39
41
|
return [LITERAL, TEMPLATE_LITERAL].includes(node.type);
|
|
40
42
|
}
|
|
41
43
|
|
|
44
|
+
/**
|
|
45
|
+
* Checks whether a node is a template literal.
|
|
46
|
+
*
|
|
47
|
+
* @param {ASTNode} node The node to type check
|
|
48
|
+
* @returns {boolean} `true` if node is a template literal.
|
|
49
|
+
*/
|
|
50
|
+
function isTemplateLiteral(node) {
|
|
51
|
+
return node.type === TEMPLATE_LITERAL;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Extracts the string out of a template literal node.
|
|
56
|
+
*
|
|
57
|
+
* @param {ASTNode} node The template literal node
|
|
58
|
+
* @returns {string} The extracted string.
|
|
59
|
+
*/
|
|
60
|
+
function getTemplateLiteralString(node) {
|
|
61
|
+
return node.quasis
|
|
62
|
+
.filter((quasi) => quasi.type === 'TemplateElement')
|
|
63
|
+
.map((quasi) => quasi.value.raw)
|
|
64
|
+
.join('');
|
|
65
|
+
}
|
|
66
|
+
|
|
42
67
|
/**
|
|
43
68
|
* Check that a node is a `VLiteral type`
|
|
44
69
|
* @param {ASTNode} node The node to type check
|
|
@@ -170,6 +195,8 @@ module.exports = {
|
|
|
170
195
|
clearSplitLines,
|
|
171
196
|
closest,
|
|
172
197
|
isString,
|
|
198
|
+
isTemplateLiteral,
|
|
199
|
+
getTemplateLiteralString,
|
|
173
200
|
isVLiteral,
|
|
174
201
|
removeNewLines,
|
|
175
202
|
selectFixFunction,
|
package/package.json
CHANGED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
# @gitlab/require-string-literal-i18n-helpers
|
|
2
|
-
|
|
3
|
-
Prevents translation helpers from being called with non-string-literal arguments.
|
|
4
|
-
|
|
5
|
-
## Rule Details
|
|
6
|
-
|
|
7
|
-
### Examples of **incorrect** code for this rule
|
|
8
|
-
|
|
9
|
-
```js
|
|
10
|
-
const label = __(LABEL);
|
|
11
|
-
const description = __(getDescription());
|
|
12
|
-
```
|
|
13
|
-
|
|
14
|
-
### Examples of **correct** code for this rule
|
|
15
|
-
|
|
16
|
-
```js
|
|
17
|
-
const label = __('Some label');
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
## Options
|
|
21
|
-
|
|
22
|
-
Nothing
|
|
23
|
-
|
|
24
|
-
## Related rules
|
|
25
|
-
|
|
26
|
-
- TBA
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
// ------------------------------------------------------------------------------
|
|
2
|
-
// Requirements
|
|
3
|
-
// ------------------------------------------------------------------------------
|
|
4
|
-
const { DOCS_BASE_URL } = require('../constants');
|
|
5
|
-
const { getFunctionName, isString } = require('../utils/rule-utils');
|
|
6
|
-
|
|
7
|
-
// ------------------------------------------------------------------------------
|
|
8
|
-
// Helpers
|
|
9
|
-
// ------------------------------------------------------------------------------
|
|
10
|
-
|
|
11
|
-
const I18N_HELPERS = new Set(['__', 's__', 'n__']);
|
|
12
|
-
const ERROR_MESSAGE = 'Translation helpers must be called with a string literal.';
|
|
13
|
-
|
|
14
|
-
const isI18nCall = (node) => {
|
|
15
|
-
const functionName = getFunctionName(node);
|
|
16
|
-
return functionName && I18N_HELPERS.has(functionName);
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
const checkFunctionArgumentFactory = (context) => (node) => {
|
|
20
|
-
if (!isI18nCall(node)) {
|
|
21
|
-
return;
|
|
22
|
-
}
|
|
23
|
-
const report = (node) => {
|
|
24
|
-
context.report({
|
|
25
|
-
node,
|
|
26
|
-
message: ERROR_MESSAGE,
|
|
27
|
-
});
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
if (!node.arguments.length) {
|
|
31
|
-
report(node);
|
|
32
|
-
}
|
|
33
|
-
const [arg1, arg2] = node.arguments;
|
|
34
|
-
if ([arg1, arg2].some((arg) => arg && !isString(arg))) {
|
|
35
|
-
report(node);
|
|
36
|
-
}
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
// ------------------------------------------------------------------------------
|
|
40
|
-
// Rule Definition
|
|
41
|
-
// ------------------------------------------------------------------------------
|
|
42
|
-
|
|
43
|
-
module.exports = {
|
|
44
|
-
meta: {
|
|
45
|
-
type: 'error',
|
|
46
|
-
docs: {
|
|
47
|
-
description: 'Prevents translation helpers from being called with non-string-literal arguments.',
|
|
48
|
-
category: 'i18n',
|
|
49
|
-
url: DOCS_BASE_URL + '/require-string-literal-i18n-helpers.md',
|
|
50
|
-
},
|
|
51
|
-
},
|
|
52
|
-
create(context) {
|
|
53
|
-
const checkFunctionArgument = checkFunctionArgumentFactory(context);
|
|
54
|
-
|
|
55
|
-
return {
|
|
56
|
-
CallExpression(node) {
|
|
57
|
-
checkFunctionArgument(node);
|
|
58
|
-
},
|
|
59
|
-
};
|
|
60
|
-
},
|
|
61
|
-
};
|