eslint-plugin-formatjs 5.4.1 → 6.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/context-compat.js +1 -5
- package/index.d.ts +15 -1
- package/index.js +46 -45
- package/package.json +6 -4
- package/rules/blocklist-elements.d.ts +1 -2
- package/rules/blocklist-elements.js +23 -26
- package/rules/enforce-default-message.js +8 -11
- package/rules/enforce-description.js +8 -11
- package/rules/enforce-id.d.ts +1 -0
- package/rules/enforce-id.js +21 -14
- package/rules/enforce-placeholders.js +14 -17
- package/rules/enforce-plural-rules.js +10 -13
- package/rules/no-camel-case.js +11 -14
- package/rules/no-complex-selectors.js +13 -16
- package/rules/no-emoji.js +11 -14
- package/rules/no-id.js +6 -9
- package/rules/no-invalid-icu.js +9 -12
- package/rules/no-literal-string-in-jsx.js +33 -13
- package/rules/no-literal-string-in-object.js +8 -11
- package/rules/no-missing-icu-plural-one-placeholders.js +15 -19
- package/rules/no-multiple-plurals.js +10 -13
- package/rules/no-multiple-whitespaces.js +27 -32
- package/rules/no-offset.js +10 -13
- package/rules/no-useless-message.js +13 -16
- package/rules/prefer-formatted-message.js +4 -7
- package/rules/prefer-pound-in-plural.js +25 -29
- package/util.js +5 -12
- package/lib_esnext/context-compat.d.ts +0 -3
- package/lib_esnext/context-compat.js +0 -6
- package/lib_esnext/index.d.ts +0 -1
- package/lib_esnext/index.js +0 -146
- package/lib_esnext/package.json +0 -31
- package/lib_esnext/rules/blocklist-elements.d.ts +0 -15
- package/lib_esnext/rules/blocklist-elements.js +0 -132
- package/lib_esnext/rules/enforce-default-message.d.ts +0 -10
- package/lib_esnext/rules/enforce-default-message.js +0 -68
- package/lib_esnext/rules/enforce-description.d.ts +0 -10
- package/lib_esnext/rules/enforce-description.js +0 -66
- package/lib_esnext/rules/enforce-id.d.ts +0 -10
- package/lib_esnext/rules/enforce-id.js +0 -153
- package/lib_esnext/rules/enforce-placeholders.d.ts +0 -8
- package/lib_esnext/rules/enforce-placeholders.js +0 -147
- package/lib_esnext/rules/enforce-plural-rules.d.ts +0 -17
- package/lib_esnext/rules/enforce-plural-rules.js +0 -103
- package/lib_esnext/rules/no-camel-case.d.ts +0 -5
- package/lib_esnext/rules/no-camel-case.js +0 -76
- package/lib_esnext/rules/no-complex-selectors.d.ts +0 -9
- package/lib_esnext/rules/no-complex-selectors.js +0 -136
- package/lib_esnext/rules/no-emoji.d.ts +0 -9
- package/lib_esnext/rules/no-emoji.js +0 -99
- package/lib_esnext/rules/no-id.d.ts +0 -5
- package/lib_esnext/rules/no-id.js +0 -58
- package/lib_esnext/rules/no-invalid-icu.d.ts +0 -5
- package/lib_esnext/rules/no-invalid-icu.js +0 -60
- package/lib_esnext/rules/no-literal-string-in-jsx.d.ts +0 -13
- package/lib_esnext/rules/no-literal-string-in-jsx.js +0 -179
- package/lib_esnext/rules/no-literal-string-in-object.d.ts +0 -9
- package/lib_esnext/rules/no-literal-string-in-object.js +0 -90
- package/lib_esnext/rules/no-missing-icu-plural-one-placeholders.d.ts +0 -6
- package/lib_esnext/rules/no-missing-icu-plural-one-placeholders.js +0 -99
- package/lib_esnext/rules/no-multiple-plurals.d.ts +0 -5
- package/lib_esnext/rules/no-multiple-plurals.js +0 -70
- package/lib_esnext/rules/no-multiple-whitespaces.d.ts +0 -5
- package/lib_esnext/rules/no-multiple-whitespaces.js +0 -141
- package/lib_esnext/rules/no-offset.d.ts +0 -5
- package/lib_esnext/rules/no-offset.js +0 -69
- package/lib_esnext/rules/no-useless-message.d.ts +0 -5
- package/lib_esnext/rules/no-useless-message.js +0 -71
- package/lib_esnext/rules/prefer-formatted-message.d.ts +0 -5
- package/lib_esnext/rules/prefer-formatted-message.js +0 -33
- package/lib_esnext/rules/prefer-pound-in-plural.d.ts +0 -5
- package/lib_esnext/rules/prefer-pound-in-plural.js +0 -191
- package/lib_esnext/util.d.ts +0 -32
- package/lib_esnext/util.js +0 -280
package/context-compat.js
CHANGED
|
@@ -1,10 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getParserServices = void 0;
|
|
4
|
-
const getParserServices = (context) => {
|
|
1
|
+
export const getParserServices = (context) => {
|
|
5
2
|
if (context.parserServices) {
|
|
6
3
|
return context.parserServices;
|
|
7
4
|
}
|
|
8
5
|
return context.sourceCode.parserServices;
|
|
9
6
|
};
|
|
10
|
-
exports.getParserServices = getParserServices;
|
package/index.d.ts
CHANGED
|
@@ -1 +1,15 @@
|
|
|
1
|
-
|
|
1
|
+
import type { Linter } from 'eslint';
|
|
2
|
+
import { ESLint } from 'eslint';
|
|
3
|
+
type Plugin = {
|
|
4
|
+
meta: {
|
|
5
|
+
name: string;
|
|
6
|
+
version: string;
|
|
7
|
+
};
|
|
8
|
+
rules: ESLint.Plugin['rules'];
|
|
9
|
+
configs: {
|
|
10
|
+
strict: Linter.Config;
|
|
11
|
+
recommended: Linter.Config;
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
declare const plugin: Plugin;
|
|
15
|
+
export default plugin;
|
package/index.js
CHANGED
|
@@ -1,73 +1,74 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const
|
|
23
|
-
const
|
|
1
|
+
import { name as blocklistElementRuleName, rule as blocklistElements, } from './rules/blocklist-elements.js';
|
|
2
|
+
import { rule as enforceDefaultMessage, name as enforceDefaultMessageName, } from './rules/enforce-default-message.js';
|
|
3
|
+
import { rule as enforceDescription, name as enforceDescriptionName, } from './rules/enforce-description.js';
|
|
4
|
+
import { rule as enforceId, name as enforceIdName } from './rules/enforce-id.js';
|
|
5
|
+
import { rule as enforcePlaceholders, name as enforcePlaceholdersName, } from './rules/enforce-placeholders.js';
|
|
6
|
+
import { rule as enforcePluralRules, name as enforcePluralRulesName, } from './rules/enforce-plural-rules.js';
|
|
7
|
+
import { rule as noCamelCase, name as noCamelCaseName, } from './rules/no-camel-case.js';
|
|
8
|
+
import { rule as noComplexSelectors, name as noComplexSelectorsName, } from './rules/no-complex-selectors.js';
|
|
9
|
+
import { rule as noEmoji, name as noEmojiName } from './rules/no-emoji.js';
|
|
10
|
+
import { rule as noId, name as noIdName } from './rules/no-id.js';
|
|
11
|
+
import { rule as noInvalidICU, name as noInvalidICUName, } from './rules/no-invalid-icu.js';
|
|
12
|
+
import { rule as noLiteralStringInJsx, name as noLiteralStringInJsxName, } from './rules/no-literal-string-in-jsx.js';
|
|
13
|
+
import { rule as noMissingIcuPluralOnePlaceholders, name as noMissingIcuPluralOnePlaceholdersName, } from './rules/no-missing-icu-plural-one-placeholders.js';
|
|
14
|
+
import { rule as noMultiplePlurals, name as noMultiplePluralsName, } from './rules/no-multiple-plurals.js';
|
|
15
|
+
import { rule as noMultipleWhitespaces, name as noMultipleWhitespacesName, } from './rules/no-multiple-whitespaces.js';
|
|
16
|
+
import { rule as noOffset, name as noOffsetName } from './rules/no-offset.js';
|
|
17
|
+
import { rule as noUselessMessage, name as noUselessMessageName, } from './rules/no-useless-message.js';
|
|
18
|
+
import { rule as preferFormattedMessage, name as preferFormattedMessageName, } from './rules/prefer-formatted-message.js';
|
|
19
|
+
import { rule as preferPoundInPlural, name as preferPoundInPluralName, } from './rules/prefer-pound-in-plural.js';
|
|
20
|
+
import { rule as noLiteralStringInObject, name as noLiteralStringInObjectName, } from './rules/no-literal-string-in-object.js';
|
|
21
|
+
import * as packageJsonNs from './package.json' with { type: 'json' };
|
|
22
|
+
const packageJson = packageJsonNs.default ?? packageJsonNs;
|
|
23
|
+
const { name, version } = packageJson;
|
|
24
24
|
// All rules
|
|
25
25
|
const rules = {
|
|
26
26
|
// @ts-expect-error
|
|
27
|
-
[
|
|
27
|
+
[blocklistElementRuleName]: blocklistElements,
|
|
28
28
|
// @ts-expect-error
|
|
29
|
-
[
|
|
29
|
+
[enforceDefaultMessageName]: enforceDefaultMessage,
|
|
30
30
|
// @ts-expect-error
|
|
31
|
-
[
|
|
31
|
+
[enforceDescriptionName]: enforceDescription,
|
|
32
32
|
// @ts-expect-error
|
|
33
|
-
[
|
|
33
|
+
[enforceIdName]: enforceId,
|
|
34
34
|
// @ts-expect-error
|
|
35
|
-
[
|
|
35
|
+
[enforcePlaceholdersName]: enforcePlaceholders,
|
|
36
36
|
// @ts-expect-error
|
|
37
|
-
[
|
|
37
|
+
[enforcePluralRulesName]: enforcePluralRules,
|
|
38
38
|
// @ts-expect-error
|
|
39
|
-
[
|
|
39
|
+
[noCamelCaseName]: noCamelCase,
|
|
40
40
|
// @ts-expect-error
|
|
41
|
-
[
|
|
41
|
+
[noComplexSelectorsName]: noComplexSelectors,
|
|
42
42
|
// @ts-expect-error
|
|
43
|
-
[
|
|
43
|
+
[noEmojiName]: noEmoji,
|
|
44
44
|
// @ts-expect-error
|
|
45
|
-
[
|
|
45
|
+
[noIdName]: noId,
|
|
46
46
|
// @ts-expect-error
|
|
47
|
-
[
|
|
47
|
+
[noInvalidICUName]: noInvalidICU,
|
|
48
48
|
// @ts-expect-error
|
|
49
|
-
[
|
|
49
|
+
[noLiteralStringInJsxName]: noLiteralStringInJsx,
|
|
50
50
|
// @ts-expect-error
|
|
51
|
-
[
|
|
51
|
+
[noMultiplePluralsName]: noMultiplePlurals,
|
|
52
52
|
// @ts-expect-error
|
|
53
|
-
[
|
|
53
|
+
[noMultipleWhitespacesName]: noMultipleWhitespaces,
|
|
54
54
|
// @ts-expect-error
|
|
55
|
-
[
|
|
55
|
+
[noOffsetName]: noOffset,
|
|
56
56
|
// @ts-expect-error
|
|
57
|
-
[
|
|
57
|
+
[noUselessMessageName]: noUselessMessage,
|
|
58
58
|
// @ts-expect-error
|
|
59
|
-
[
|
|
59
|
+
[preferFormattedMessageName]: preferFormattedMessage,
|
|
60
60
|
// @ts-expect-error
|
|
61
|
-
[
|
|
61
|
+
[preferPoundInPluralName]: preferPoundInPlural,
|
|
62
62
|
// @ts-expect-error
|
|
63
|
-
[
|
|
63
|
+
[noMissingIcuPluralOnePlaceholdersName]: noMissingIcuPluralOnePlaceholders,
|
|
64
64
|
// @ts-expect-error
|
|
65
|
-
[
|
|
65
|
+
[noLiteralStringInObjectName]: noLiteralStringInObject,
|
|
66
66
|
};
|
|
67
67
|
// Base plugin
|
|
68
68
|
const plugin = {
|
|
69
|
-
meta: { name
|
|
69
|
+
meta: { name, version },
|
|
70
70
|
rules,
|
|
71
|
+
configs: {}, // will be populated later
|
|
71
72
|
};
|
|
72
73
|
// Configs
|
|
73
74
|
const configs = {
|
|
@@ -145,4 +146,4 @@ const configs = {
|
|
|
145
146
|
},
|
|
146
147
|
};
|
|
147
148
|
plugin.configs = configs;
|
|
148
|
-
|
|
149
|
+
export default plugin;
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-formatjs",
|
|
3
3
|
"description": "ESLint plugin for formatjs",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "6.0.0",
|
|
5
5
|
"author": "Long Ho <holevietlong@gmail.com>",
|
|
6
6
|
"bugs": "https://github.com/formatjs/formatjs/issues",
|
|
7
7
|
"dependencies": {
|
|
8
|
-
"@formatjs/icu-messageformat-parser": "
|
|
9
|
-
"@formatjs/ts-transformer": "
|
|
8
|
+
"@formatjs/icu-messageformat-parser": "3.0.0",
|
|
9
|
+
"@formatjs/ts-transformer": "4.0.0",
|
|
10
10
|
"@types/eslint": "^9.6.1",
|
|
11
11
|
"@types/picomatch": "^3",
|
|
12
12
|
"@typescript-eslint/utils": "^8.27.0",
|
|
@@ -27,5 +27,7 @@
|
|
|
27
27
|
"peerDependencies": {
|
|
28
28
|
"eslint": "9.30.1"
|
|
29
29
|
},
|
|
30
|
-
"repository": "formatjs/formatjs.git"
|
|
30
|
+
"repository": "formatjs/formatjs.git",
|
|
31
|
+
"type": "module",
|
|
32
|
+
"types": "index.d.ts"
|
|
31
33
|
}
|
|
@@ -11,5 +11,4 @@ export declare enum Element {
|
|
|
11
11
|
plural = "plural",
|
|
12
12
|
tag = "tag"
|
|
13
13
|
}
|
|
14
|
-
export declare const rule: ESLintUtils.RuleModule<'blocklist', [
|
|
15
|
-
], unknown, ESLintUtils.RuleListener>;
|
|
14
|
+
export declare const rule: ESLintUtils.RuleModule<'blocklist', Element[][], unknown, ESLintUtils.RuleListener>;
|
|
@@ -1,18 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const
|
|
6
|
-
const context_compat_1 = require("../context-compat");
|
|
7
|
-
const util_1 = require("../util");
|
|
8
|
-
exports.name = 'blocklist-elements';
|
|
1
|
+
import { isArgumentElement, isDateElement, isLiteralElement, isNumberElement, isPluralElement, isSelectElement, isTagElement, isTimeElement, parse, } from '@formatjs/icu-messageformat-parser';
|
|
2
|
+
import { ESLintUtils } from '@typescript-eslint/utils';
|
|
3
|
+
import { getParserServices } from '../context-compat.js';
|
|
4
|
+
import { extractMessages, getSettings } from '../util.js';
|
|
5
|
+
export const name = 'blocklist-elements';
|
|
9
6
|
function getMessage(type) {
|
|
10
7
|
return {
|
|
11
8
|
messageId: 'blocklist',
|
|
12
9
|
data: { type },
|
|
13
10
|
};
|
|
14
11
|
}
|
|
15
|
-
var Element;
|
|
12
|
+
export var Element;
|
|
16
13
|
(function (Element) {
|
|
17
14
|
Element["literal"] = "literal";
|
|
18
15
|
Element["argument"] = "argument";
|
|
@@ -23,32 +20,32 @@ var Element;
|
|
|
23
20
|
Element["selectordinal"] = "selectordinal";
|
|
24
21
|
Element["plural"] = "plural";
|
|
25
22
|
Element["tag"] = "tag";
|
|
26
|
-
})(Element || (
|
|
23
|
+
})(Element || (Element = {}));
|
|
27
24
|
function verifyAst(blocklist, ast) {
|
|
28
25
|
const errors = [];
|
|
29
26
|
for (const el of ast) {
|
|
30
|
-
if (
|
|
27
|
+
if (isLiteralElement(el) && blocklist.includes(Element.literal)) {
|
|
31
28
|
errors.push(getMessage(Element.literal));
|
|
32
29
|
}
|
|
33
|
-
if (
|
|
30
|
+
if (isArgumentElement(el) && blocklist.includes(Element.argument)) {
|
|
34
31
|
errors.push(getMessage(Element.argument));
|
|
35
32
|
}
|
|
36
|
-
if (
|
|
33
|
+
if (isNumberElement(el) && blocklist.includes(Element.number)) {
|
|
37
34
|
errors.push(getMessage(Element.number));
|
|
38
35
|
}
|
|
39
|
-
if (
|
|
36
|
+
if (isDateElement(el) && blocklist.includes(Element.date)) {
|
|
40
37
|
errors.push(getMessage(Element.date));
|
|
41
38
|
}
|
|
42
|
-
if (
|
|
39
|
+
if (isTimeElement(el) && blocklist.includes(Element.time)) {
|
|
43
40
|
errors.push(getMessage(Element.time));
|
|
44
41
|
}
|
|
45
|
-
if (
|
|
42
|
+
if (isSelectElement(el) && blocklist.includes(Element.select)) {
|
|
46
43
|
errors.push(getMessage(Element.select));
|
|
47
44
|
}
|
|
48
|
-
if (
|
|
45
|
+
if (isTagElement(el) && blocklist.includes(Element.tag)) {
|
|
49
46
|
errors.push(getMessage(Element.tag));
|
|
50
47
|
}
|
|
51
|
-
if (
|
|
48
|
+
if (isPluralElement(el)) {
|
|
52
49
|
if (blocklist.includes(Element.plural)) {
|
|
53
50
|
errors.push(getMessage(Element.argument));
|
|
54
51
|
}
|
|
@@ -57,7 +54,7 @@ function verifyAst(blocklist, ast) {
|
|
|
57
54
|
errors.push(getMessage(Element.selectordinal));
|
|
58
55
|
}
|
|
59
56
|
}
|
|
60
|
-
if (
|
|
57
|
+
if (isSelectElement(el) || isPluralElement(el)) {
|
|
61
58
|
const { options } = el;
|
|
62
59
|
for (const selector of Object.keys(options)) {
|
|
63
60
|
verifyAst(blocklist, options[selector].value);
|
|
@@ -67,8 +64,8 @@ function verifyAst(blocklist, ast) {
|
|
|
67
64
|
return errors;
|
|
68
65
|
}
|
|
69
66
|
function checkNode(context, node) {
|
|
70
|
-
const settings =
|
|
71
|
-
const msgs =
|
|
67
|
+
const settings = getSettings(context);
|
|
68
|
+
const msgs = extractMessages(node, settings);
|
|
72
69
|
if (!msgs.length) {
|
|
73
70
|
return;
|
|
74
71
|
}
|
|
@@ -80,7 +77,7 @@ function checkNode(context, node) {
|
|
|
80
77
|
if (!defaultMessage || !messageNode) {
|
|
81
78
|
continue;
|
|
82
79
|
}
|
|
83
|
-
const errors = verifyAst(blocklist,
|
|
80
|
+
const errors = verifyAst(blocklist, parse(defaultMessage, {
|
|
84
81
|
ignoreTag: settings.ignoreTag,
|
|
85
82
|
}));
|
|
86
83
|
for (const error of errors) {
|
|
@@ -91,9 +88,9 @@ function checkNode(context, node) {
|
|
|
91
88
|
}
|
|
92
89
|
}
|
|
93
90
|
}
|
|
94
|
-
const createRule =
|
|
95
|
-
|
|
96
|
-
name
|
|
91
|
+
const createRule = ESLintUtils.RuleCreator(_ => 'https://formatjs.github.io/docs/tooling/linter#blocklist-elements');
|
|
92
|
+
export const rule = createRule({
|
|
93
|
+
name,
|
|
97
94
|
meta: {
|
|
98
95
|
type: 'problem',
|
|
99
96
|
docs: {
|
|
@@ -117,7 +114,7 @@ exports.rule = createRule({
|
|
|
117
114
|
defaultOptions: [],
|
|
118
115
|
create(context) {
|
|
119
116
|
const callExpressionVisitor = node => checkNode(context, node);
|
|
120
|
-
const parserServices =
|
|
117
|
+
const parserServices = getParserServices(context);
|
|
121
118
|
//@ts-expect-error defineTemplateBodyVisitor exists in Vue parser
|
|
122
119
|
if (parserServices?.defineTemplateBodyVisitor) {
|
|
123
120
|
//@ts-expect-error
|
|
@@ -1,16 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const context_compat_1 = require("../context-compat");
|
|
5
|
-
const util_1 = require("../util");
|
|
6
|
-
var Option;
|
|
1
|
+
import { getParserServices } from '../context-compat.js';
|
|
2
|
+
import { extractMessages, getSettings } from '../util.js';
|
|
3
|
+
export var Option;
|
|
7
4
|
(function (Option) {
|
|
8
5
|
Option["literal"] = "literal";
|
|
9
6
|
Option["anything"] = "anything";
|
|
10
|
-
})(Option || (
|
|
11
|
-
|
|
7
|
+
})(Option || (Option = {}));
|
|
8
|
+
export const name = 'enforce-default-message';
|
|
12
9
|
function checkNode(context, node) {
|
|
13
|
-
const msgs =
|
|
10
|
+
const msgs = extractMessages(node, getSettings(context));
|
|
14
11
|
const { options: [type], } = context;
|
|
15
12
|
for (const [{ message: { defaultMessage }, messageNode, },] of msgs) {
|
|
16
13
|
if (!defaultMessage) {
|
|
@@ -29,7 +26,7 @@ function checkNode(context, node) {
|
|
|
29
26
|
}
|
|
30
27
|
}
|
|
31
28
|
}
|
|
32
|
-
|
|
29
|
+
export const rule = {
|
|
33
30
|
meta: {
|
|
34
31
|
type: 'problem',
|
|
35
32
|
docs: {
|
|
@@ -53,7 +50,7 @@ exports.rule = {
|
|
|
53
50
|
defaultOptions: [],
|
|
54
51
|
create(context) {
|
|
55
52
|
const callExpressionVisitor = (node) => checkNode(context, node);
|
|
56
|
-
const parserServices =
|
|
53
|
+
const parserServices = getParserServices(context);
|
|
57
54
|
//@ts-expect-error defineTemplateBodyVisitor exists in Vue parser
|
|
58
55
|
if (parserServices?.defineTemplateBodyVisitor) {
|
|
59
56
|
//@ts-expect-error
|
|
@@ -1,15 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const context_compat_1 = require("../context-compat");
|
|
5
|
-
const util_1 = require("../util");
|
|
6
|
-
var Option;
|
|
1
|
+
import { getParserServices } from '../context-compat.js';
|
|
2
|
+
import { extractMessages, getSettings } from '../util.js';
|
|
3
|
+
export var Option;
|
|
7
4
|
(function (Option) {
|
|
8
5
|
Option["literal"] = "literal";
|
|
9
6
|
Option["anything"] = "anything";
|
|
10
|
-
})(Option || (
|
|
7
|
+
})(Option || (Option = {}));
|
|
11
8
|
function checkNode(context, node) {
|
|
12
|
-
const msgs =
|
|
9
|
+
const msgs = extractMessages(node, getSettings(context));
|
|
13
10
|
const { options: [type], } = context;
|
|
14
11
|
for (const [{ message: { description }, descriptionNode, },] of msgs) {
|
|
15
12
|
if (!description) {
|
|
@@ -28,8 +25,8 @@ function checkNode(context, node) {
|
|
|
28
25
|
}
|
|
29
26
|
}
|
|
30
27
|
}
|
|
31
|
-
|
|
32
|
-
|
|
28
|
+
export const name = 'enforce-description';
|
|
29
|
+
export const rule = {
|
|
33
30
|
meta: {
|
|
34
31
|
type: 'problem',
|
|
35
32
|
docs: {
|
|
@@ -51,7 +48,7 @@ exports.rule = {
|
|
|
51
48
|
defaultOptions: [],
|
|
52
49
|
create(context) {
|
|
53
50
|
const callExpressionVisitor = (node) => checkNode(context, node);
|
|
54
|
-
const parserServices =
|
|
51
|
+
const parserServices = getParserServices(context);
|
|
55
52
|
//@ts-expect-error defineTemplateBodyVisitor exists in Vue parser
|
|
56
53
|
if (parserServices?.defineTemplateBodyVisitor) {
|
|
57
54
|
//@ts-expect-error
|
package/rules/enforce-id.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { RuleModule } from '@typescript-eslint/utils/ts-eslint';
|
|
|
2
2
|
export type Option = {
|
|
3
3
|
idInterpolationPattern: string;
|
|
4
4
|
idWhitelist?: string[];
|
|
5
|
+
quoteStyle?: 'single' | 'double';
|
|
5
6
|
};
|
|
6
7
|
type MessageIds = 'enforceId' | 'enforceIdDefaultMessage' | 'enforceIdDescription' | 'enforceIdMatching' | 'enforceIdMatchingAllowlisted';
|
|
7
8
|
type Options = [Option];
|
package/rules/enforce-id.js
CHANGED
|
@@ -1,11 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const
|
|
6
|
-
const util_1 = require("../util");
|
|
7
|
-
function checkNode(context, node, { idInterpolationPattern, idWhitelistRegexps, }) {
|
|
8
|
-
const msgs = (0, util_1.extractMessages)(node, (0, util_1.getSettings)(context));
|
|
1
|
+
import { interpolateName } from '@formatjs/ts-transformer';
|
|
2
|
+
import { getParserServices } from '../context-compat.js';
|
|
3
|
+
import { extractMessages, getSettings } from '../util.js';
|
|
4
|
+
function checkNode(context, node, { idInterpolationPattern, idWhitelistRegexps, quoteStyle, }) {
|
|
5
|
+
const msgs = extractMessages(node, getSettings(context));
|
|
9
6
|
for (const [{ message: { defaultMessage, description, id }, idPropNode, descriptionNode, messagePropNode, },] of msgs) {
|
|
10
7
|
if (!idInterpolationPattern && !idPropNode) {
|
|
11
8
|
context.report({
|
|
@@ -33,7 +30,7 @@ function checkNode(context, node, { idInterpolationPattern, idWhitelistRegexps,
|
|
|
33
30
|
// messageId is allowlisted so skip interpolation id check
|
|
34
31
|
continue;
|
|
35
32
|
}
|
|
36
|
-
const correctId =
|
|
33
|
+
const correctId = interpolateName({
|
|
37
34
|
resourcePath: context.getFilename(),
|
|
38
35
|
}, idInterpolationPattern, {
|
|
39
36
|
content: description
|
|
@@ -56,6 +53,7 @@ function checkNode(context, node, { idInterpolationPattern, idWhitelistRegexps,
|
|
|
56
53
|
.join(', '),
|
|
57
54
|
};
|
|
58
55
|
}
|
|
56
|
+
const quote = quoteStyle === 'double' ? '"' : "'";
|
|
59
57
|
context.report({
|
|
60
58
|
node,
|
|
61
59
|
messageId,
|
|
@@ -63,16 +61,18 @@ function checkNode(context, node, { idInterpolationPattern, idWhitelistRegexps,
|
|
|
63
61
|
fix(fixer) {
|
|
64
62
|
if (idPropNode) {
|
|
65
63
|
if (idPropNode.type === 'JSXAttribute') {
|
|
64
|
+
// Always use double quotes for JSX attributes
|
|
66
65
|
return fixer.replaceText(idPropNode, `id="${correctId}"`);
|
|
67
66
|
}
|
|
68
|
-
return fixer.replaceText(idPropNode, `id:
|
|
67
|
+
return fixer.replaceText(idPropNode, `id: ${quote}${correctId}${quote}`);
|
|
69
68
|
}
|
|
70
69
|
if (messagePropNode) {
|
|
71
70
|
// Insert after default message node
|
|
72
71
|
if (messagePropNode.type === 'JSXAttribute') {
|
|
72
|
+
// Always use double quotes for JSX attributes
|
|
73
73
|
return fixer.insertTextAfter(messagePropNode, ` id="${correctId}"`);
|
|
74
74
|
}
|
|
75
|
-
return fixer.insertTextAfter(messagePropNode, `, id:
|
|
75
|
+
return fixer.insertTextAfter(messagePropNode, `, id: ${quote}${correctId}${quote}`);
|
|
76
76
|
}
|
|
77
77
|
return null;
|
|
78
78
|
},
|
|
@@ -82,8 +82,8 @@ function checkNode(context, node, { idInterpolationPattern, idWhitelistRegexps,
|
|
|
82
82
|
}
|
|
83
83
|
}
|
|
84
84
|
}
|
|
85
|
-
|
|
86
|
-
|
|
85
|
+
export const name = 'enforce-id';
|
|
86
|
+
export const rule = {
|
|
87
87
|
meta: {
|
|
88
88
|
type: 'problem',
|
|
89
89
|
docs: {
|
|
@@ -106,6 +106,11 @@ exports.rule = {
|
|
|
106
106
|
type: 'string',
|
|
107
107
|
},
|
|
108
108
|
},
|
|
109
|
+
quoteStyle: {
|
|
110
|
+
type: 'string',
|
|
111
|
+
enum: ['single', 'double'],
|
|
112
|
+
description: 'Quote style for generated IDs. Defaults to single quotes.',
|
|
113
|
+
},
|
|
109
114
|
},
|
|
110
115
|
required: ['idInterpolationPattern'],
|
|
111
116
|
additionalProperties: false,
|
|
@@ -126,19 +131,21 @@ Actual: {{actual}}`,
|
|
|
126
131
|
defaultOptions: [
|
|
127
132
|
{
|
|
128
133
|
idInterpolationPattern: '[sha512:contenthash:base64:6]',
|
|
134
|
+
quoteStyle: 'single',
|
|
129
135
|
},
|
|
130
136
|
],
|
|
131
137
|
create(context) {
|
|
132
138
|
const tmp = context.options[0];
|
|
133
139
|
let opts = {
|
|
134
140
|
idInterpolationPattern: tmp?.idInterpolationPattern,
|
|
141
|
+
quoteStyle: tmp?.quoteStyle || 'single',
|
|
135
142
|
};
|
|
136
143
|
if (Array.isArray(tmp?.idWhitelist)) {
|
|
137
144
|
const { idWhitelist } = tmp;
|
|
138
145
|
opts.idWhitelistRegexps = idWhitelist.map((str) => new RegExp(str, 'i'));
|
|
139
146
|
}
|
|
140
147
|
const callExpressionVisitor = (node) => checkNode(context, node, opts);
|
|
141
|
-
const parserServices =
|
|
148
|
+
const parserServices = getParserServices(context);
|
|
142
149
|
//@ts-expect-error defineTemplateBodyVisitor exists in Vue parser
|
|
143
150
|
if (parserServices?.defineTemplateBodyVisitor) {
|
|
144
151
|
//@ts-expect-error
|
|
@@ -1,9 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const icu_messageformat_parser_1 = require("@formatjs/icu-messageformat-parser");
|
|
5
|
-
const context_compat_1 = require("../context-compat");
|
|
6
|
-
const util_1 = require("../util");
|
|
1
|
+
import { TYPE, parse, } from '@formatjs/icu-messageformat-parser';
|
|
2
|
+
import { getParserServices } from '../context-compat.js';
|
|
3
|
+
import { extractMessages, getSettings } from '../util.js';
|
|
7
4
|
function collectPlaceholderNames(ast) {
|
|
8
5
|
const placeholderNames = new Set();
|
|
9
6
|
_traverse(ast);
|
|
@@ -11,15 +8,15 @@ function collectPlaceholderNames(ast) {
|
|
|
11
8
|
function _traverse(ast) {
|
|
12
9
|
for (const element of ast) {
|
|
13
10
|
switch (element.type) {
|
|
14
|
-
case
|
|
15
|
-
case
|
|
11
|
+
case TYPE.literal:
|
|
12
|
+
case TYPE.pound:
|
|
16
13
|
break;
|
|
17
|
-
case
|
|
14
|
+
case TYPE.tag:
|
|
18
15
|
placeholderNames.add(element.value);
|
|
19
16
|
_traverse(element.children);
|
|
20
17
|
break;
|
|
21
|
-
case
|
|
22
|
-
case
|
|
18
|
+
case TYPE.plural:
|
|
19
|
+
case TYPE.select:
|
|
23
20
|
placeholderNames.add(element.value);
|
|
24
21
|
for (const { value } of Object.values(element.options)) {
|
|
25
22
|
_traverse(value);
|
|
@@ -33,8 +30,8 @@ function collectPlaceholderNames(ast) {
|
|
|
33
30
|
}
|
|
34
31
|
}
|
|
35
32
|
function checkNode(context, node) {
|
|
36
|
-
const settings =
|
|
37
|
-
const msgs =
|
|
33
|
+
const settings = getSettings(context);
|
|
34
|
+
const msgs = extractMessages(node, {
|
|
38
35
|
excludeMessageDeclCalls: true,
|
|
39
36
|
...settings,
|
|
40
37
|
});
|
|
@@ -65,7 +62,7 @@ function checkNode(context, node) {
|
|
|
65
62
|
}
|
|
66
63
|
let ast;
|
|
67
64
|
try {
|
|
68
|
-
ast =
|
|
65
|
+
ast = parse(defaultMessage, { ignoreTag: settings.ignoreTag });
|
|
69
66
|
}
|
|
70
67
|
catch (e) {
|
|
71
68
|
context.report({
|
|
@@ -101,8 +98,8 @@ function checkNode(context, node) {
|
|
|
101
98
|
});
|
|
102
99
|
}
|
|
103
100
|
}
|
|
104
|
-
|
|
105
|
-
|
|
101
|
+
export const name = 'enforce-placeholders';
|
|
102
|
+
export const rule = {
|
|
106
103
|
meta: {
|
|
107
104
|
type: 'problem',
|
|
108
105
|
docs: {
|
|
@@ -132,7 +129,7 @@ exports.rule = {
|
|
|
132
129
|
defaultOptions: [],
|
|
133
130
|
create(context) {
|
|
134
131
|
const callExpressionVisitor = (node) => checkNode(context, node);
|
|
135
|
-
const parserServices =
|
|
132
|
+
const parserServices = getParserServices(context);
|
|
136
133
|
//@ts-expect-error defineTemplateBodyVisitor exists in Vue parser
|
|
137
134
|
if (parserServices?.defineTemplateBodyVisitor) {
|
|
138
135
|
//@ts-expect-error
|
|
@@ -1,9 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const icu_messageformat_parser_1 = require("@formatjs/icu-messageformat-parser");
|
|
5
|
-
const context_compat_1 = require("../context-compat");
|
|
6
|
-
const util_1 = require("../util");
|
|
1
|
+
import { isPluralElement, parse, } from '@formatjs/icu-messageformat-parser';
|
|
2
|
+
import { getParserServices } from '../context-compat.js';
|
|
3
|
+
import { extractMessages, getSettings } from '../util.js';
|
|
7
4
|
var LDML;
|
|
8
5
|
(function (LDML) {
|
|
9
6
|
LDML["zero"] = "zero";
|
|
@@ -16,7 +13,7 @@ var LDML;
|
|
|
16
13
|
function verifyAst(plConfig, ast) {
|
|
17
14
|
const errors = [];
|
|
18
15
|
for (const el of ast) {
|
|
19
|
-
if (
|
|
16
|
+
if (isPluralElement(el)) {
|
|
20
17
|
const rules = Object.keys(plConfig);
|
|
21
18
|
for (const rule of rules) {
|
|
22
19
|
if (plConfig[rule] && !el.options[rule]) {
|
|
@@ -35,8 +32,8 @@ function verifyAst(plConfig, ast) {
|
|
|
35
32
|
return errors;
|
|
36
33
|
}
|
|
37
34
|
function checkNode(context, node) {
|
|
38
|
-
const settings =
|
|
39
|
-
const msgs =
|
|
35
|
+
const settings = getSettings(context);
|
|
36
|
+
const msgs = extractMessages(node, settings);
|
|
40
37
|
if (!msgs.length) {
|
|
41
38
|
return;
|
|
42
39
|
}
|
|
@@ -48,7 +45,7 @@ function checkNode(context, node) {
|
|
|
48
45
|
if (!defaultMessage || !messageNode) {
|
|
49
46
|
continue;
|
|
50
47
|
}
|
|
51
|
-
const errors = verifyAst(plConfig,
|
|
48
|
+
const errors = verifyAst(plConfig, parse(defaultMessage, {
|
|
52
49
|
ignoreTag: settings.ignoreTag,
|
|
53
50
|
}));
|
|
54
51
|
for (const error of errors) {
|
|
@@ -59,8 +56,8 @@ function checkNode(context, node) {
|
|
|
59
56
|
}
|
|
60
57
|
}
|
|
61
58
|
}
|
|
62
|
-
|
|
63
|
-
|
|
59
|
+
export const name = 'enforce-plural-rules';
|
|
60
|
+
export const rule = {
|
|
64
61
|
meta: {
|
|
65
62
|
type: 'problem',
|
|
66
63
|
docs: {
|
|
@@ -88,7 +85,7 @@ exports.rule = {
|
|
|
88
85
|
defaultOptions: [],
|
|
89
86
|
create(context) {
|
|
90
87
|
const callExpressionVisitor = (node) => checkNode(context, node);
|
|
91
|
-
const parserServices =
|
|
88
|
+
const parserServices = getParserServices(context);
|
|
92
89
|
//@ts-expect-error defineTemplateBodyVisitor exists in Vue parser
|
|
93
90
|
if (parserServices?.defineTemplateBodyVisitor) {
|
|
94
91
|
//@ts-expect-error
|