eslint-plugin-formatjs
Advanced tools
Comparing version 4.11.3 to 4.12.0
@@ -1,24 +0,4 @@ | ||
declare const plugin: { | ||
rules: { | ||
'blocklist-elements': import("eslint").Rule.RuleModule; | ||
'enforce-default-message': import("eslint").Rule.RuleModule; | ||
'enforce-description': import("eslint").Rule.RuleModule; | ||
'enforce-id': import("eslint").Rule.RuleModule; | ||
'enforce-placeholders': import("eslint").Rule.RuleModule; | ||
'enforce-plural-rules': import("eslint").Rule.RuleModule; | ||
'no-camel-case': import("eslint").Rule.RuleModule; | ||
'no-complex-selectors': import("eslint").Rule.RuleModule; | ||
'no-emoji': import("eslint").Rule.RuleModule; | ||
'no-id': import("eslint").Rule.RuleModule; | ||
'no-invalid-icu': import("eslint").Rule.RuleModule; | ||
'no-literal-string-in-jsx': import("eslint").Rule.RuleModule; | ||
'no-multiple-plurals': import("eslint").Rule.RuleModule; | ||
'no-multiple-whitespaces': import("eslint").Rule.RuleModule; | ||
'no-offset': import("eslint").Rule.RuleModule; | ||
'no-useless-message': import("eslint").Rule.RuleModule; | ||
'prefer-formatted-message': import("eslint").Rule.RuleModule; | ||
'prefer-pound-in-plural': import("eslint").Rule.RuleModule; | ||
}; | ||
import { RuleModule } from '@typescript-eslint/utils/ts-eslint'; | ||
export type Plugin = { | ||
rules: Record<string, RuleModule<string, readonly unknown[]>>; | ||
}; | ||
export type Plugin = typeof plugin; | ||
export {}; |
73
index.js
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const tslib_1 = require("tslib"); | ||
const blocklist_elements_1 = tslib_1.__importDefault(require("./rules/blocklist-elements")); | ||
const enforce_default_message_1 = tslib_1.__importDefault(require("./rules/enforce-default-message")); | ||
const enforce_description_1 = tslib_1.__importDefault(require("./rules/enforce-description")); | ||
const enforce_id_1 = tslib_1.__importDefault(require("./rules/enforce-id")); | ||
const enforce_placeholders_1 = tslib_1.__importDefault(require("./rules/enforce-placeholders")); | ||
const no_invalid_icu_1 = tslib_1.__importDefault(require("./rules/no-invalid-icu")); | ||
const enforce_plural_rules_1 = tslib_1.__importDefault(require("./rules/enforce-plural-rules")); | ||
const no_camel_case_1 = tslib_1.__importDefault(require("./rules/no-camel-case")); | ||
const no_complex_selectors_1 = tslib_1.__importDefault(require("./rules/no-complex-selectors")); | ||
const no_emoji_1 = tslib_1.__importDefault(require("./rules/no-emoji")); | ||
const no_id_1 = tslib_1.__importDefault(require("./rules/no-id")); | ||
const no_multiple_plurals_1 = tslib_1.__importDefault(require("./rules/no-multiple-plurals")); | ||
const no_multiple_whitespaces_1 = tslib_1.__importDefault(require("./rules/no-multiple-whitespaces")); | ||
const no_offset_1 = tslib_1.__importDefault(require("./rules/no-offset")); | ||
const no_literal_string_in_jsx_1 = tslib_1.__importDefault(require("./rules/no-literal-string-in-jsx")); | ||
const no_useless_message_1 = tslib_1.__importDefault(require("./rules/no-useless-message")); | ||
const prefer_formatted_message_1 = tslib_1.__importDefault(require("./rules/prefer-formatted-message")); | ||
const prefer_pound_in_plural_1 = tslib_1.__importDefault(require("./rules/prefer-pound-in-plural")); | ||
const blocklist_elements_1 = require("./rules/blocklist-elements"); | ||
const enforce_default_message_1 = require("./rules/enforce-default-message"); | ||
const enforce_description_1 = require("./rules/enforce-description"); | ||
const enforce_id_1 = require("./rules/enforce-id"); | ||
const enforce_placeholders_1 = require("./rules/enforce-placeholders"); | ||
const no_invalid_icu_1 = require("./rules/no-invalid-icu"); | ||
const enforce_plural_rules_1 = require("./rules/enforce-plural-rules"); | ||
const no_camel_case_1 = require("./rules/no-camel-case"); | ||
const no_complex_selectors_1 = require("./rules/no-complex-selectors"); | ||
const no_emoji_1 = require("./rules/no-emoji"); | ||
const no_id_1 = require("./rules/no-id"); | ||
const no_multiple_plurals_1 = require("./rules/no-multiple-plurals"); | ||
const no_multiple_whitespaces_1 = require("./rules/no-multiple-whitespaces"); | ||
const no_offset_1 = require("./rules/no-offset"); | ||
const no_literal_string_in_jsx_1 = require("./rules/no-literal-string-in-jsx"); | ||
const no_useless_message_1 = require("./rules/no-useless-message"); | ||
const prefer_formatted_message_1 = require("./rules/prefer-formatted-message"); | ||
const prefer_pound_in_plural_1 = require("./rules/prefer-pound-in-plural"); | ||
const plugin = { | ||
rules: { | ||
'blocklist-elements': blocklist_elements_1.default, | ||
'enforce-default-message': enforce_default_message_1.default, | ||
'enforce-description': enforce_description_1.default, | ||
'enforce-id': enforce_id_1.default, | ||
'enforce-placeholders': enforce_placeholders_1.default, | ||
'enforce-plural-rules': enforce_plural_rules_1.default, | ||
'no-camel-case': no_camel_case_1.default, | ||
'no-complex-selectors': no_complex_selectors_1.default, | ||
'no-emoji': no_emoji_1.default, | ||
'no-id': no_id_1.default, | ||
'no-invalid-icu': no_invalid_icu_1.default, | ||
'no-literal-string-in-jsx': no_literal_string_in_jsx_1.default, | ||
'no-multiple-plurals': no_multiple_plurals_1.default, | ||
'no-multiple-whitespaces': no_multiple_whitespaces_1.default, | ||
'no-offset': no_offset_1.default, | ||
'no-useless-message': no_useless_message_1.default, | ||
'prefer-formatted-message': prefer_formatted_message_1.default, | ||
'prefer-pound-in-plural': prefer_pound_in_plural_1.default, | ||
[blocklist_elements_1.name]: blocklist_elements_1.rule, | ||
[enforce_default_message_1.name]: enforce_default_message_1.rule, | ||
[enforce_description_1.name]: enforce_description_1.rule, | ||
[enforce_id_1.name]: enforce_id_1.rule, | ||
[enforce_placeholders_1.name]: enforce_placeholders_1.rule, | ||
[enforce_plural_rules_1.name]: enforce_plural_rules_1.rule, | ||
[no_camel_case_1.name]: no_camel_case_1.rule, | ||
[no_complex_selectors_1.name]: no_complex_selectors_1.rule, | ||
[no_emoji_1.name]: no_emoji_1.rule, | ||
[no_id_1.name]: no_id_1.rule, | ||
[no_invalid_icu_1.name]: no_invalid_icu_1.rule, | ||
[no_literal_string_in_jsx_1.name]: no_literal_string_in_jsx_1.rule, | ||
[no_multiple_plurals_1.name]: no_multiple_plurals_1.rule, | ||
[no_multiple_whitespaces_1.name]: no_multiple_whitespaces_1.rule, | ||
[no_offset_1.name]: no_offset_1.rule, | ||
[no_useless_message_1.name]: no_useless_message_1.rule, | ||
[prefer_formatted_message_1.name]: prefer_formatted_message_1.rule, | ||
[prefer_pound_in_plural_1.name]: prefer_pound_in_plural_1.rule, | ||
}, | ||
}; | ||
module.exports = plugin; |
{ | ||
"name": "eslint-plugin-formatjs", | ||
"version": "4.11.3", | ||
"version": "4.12.0", | ||
"description": "ESLint plugin for formatjs", | ||
@@ -25,3 +25,3 @@ "main": "index.js", | ||
"@types/picomatch": "^2.3.0", | ||
"@typescript-eslint/utils": "^6.5.0", | ||
"@typescript-eslint/utils": "^6.18.1", | ||
"emoji-regex": "^10.2.1", | ||
@@ -32,5 +32,5 @@ "magic-string": "^0.30.0", | ||
"typescript": "5", | ||
"unicode-emoji-utils": "^1.1.1", | ||
"@formatjs/icu-messageformat-parser": "2.7.3", | ||
"@formatjs/ts-transformer": "3.13.9" | ||
"unicode-emoji-utils": "^1.2.0", | ||
"@formatjs/ts-transformer": "3.13.10", | ||
"@formatjs/icu-messageformat-parser": "2.7.4" | ||
}, | ||
@@ -37,0 +37,0 @@ "peerDependencies": { |
@@ -1,3 +0,17 @@ | ||
import { Rule } from 'eslint'; | ||
declare const rule: Rule.RuleModule; | ||
export default rule; | ||
import { RuleModule, RuleListener } from '@typescript-eslint/utils/ts-eslint'; | ||
type MessageIds = 'blocklist'; | ||
type Options = [Element[]?]; | ||
export declare const name = "blocklist-elements"; | ||
export declare enum Element { | ||
literal = "literal", | ||
argument = "argument", | ||
number = "number", | ||
date = "date", | ||
time = "time", | ||
select = "select", | ||
selectordinal = "selectordinal", | ||
plural = "plural", | ||
tag = "tag" | ||
} | ||
export declare const rule: RuleModule<MessageIds, Options, RuleListener>; | ||
export {}; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.rule = exports.Element = exports.name = void 0; | ||
const icu_messageformat_parser_1 = require("@formatjs/icu-messageformat-parser"); | ||
const util_1 = require("../util"); | ||
class BlacklistElement extends Error { | ||
constructor(type) { | ||
super(); | ||
this.message = `${type} element is blocklisted`; | ||
} | ||
exports.name = 'blocklist-elements'; | ||
function getMessage(type) { | ||
return { | ||
messageId: 'blocklist', | ||
data: { type }, | ||
}; | ||
} | ||
@@ -22,33 +24,34 @@ var Element; | ||
Element["tag"] = "tag"; | ||
})(Element || (Element = {})); | ||
})(Element || (exports.Element = Element = {})); | ||
function verifyAst(blocklist, ast) { | ||
const errors = []; | ||
for (const el of ast) { | ||
if ((0, icu_messageformat_parser_1.isLiteralElement)(el) && blocklist.includes(Element.literal)) { | ||
throw new BlacklistElement(Element.literal); | ||
errors.push(getMessage(Element.literal)); | ||
} | ||
if ((0, icu_messageformat_parser_1.isArgumentElement)(el) && blocklist.includes(Element.argument)) { | ||
throw new BlacklistElement(Element.argument); | ||
errors.push(getMessage(Element.argument)); | ||
} | ||
if ((0, icu_messageformat_parser_1.isNumberElement)(el) && blocklist.includes(Element.number)) { | ||
throw new BlacklistElement(Element.number); | ||
errors.push(getMessage(Element.number)); | ||
} | ||
if ((0, icu_messageformat_parser_1.isDateElement)(el) && blocklist.includes(Element.date)) { | ||
throw new BlacklistElement(Element.date); | ||
errors.push(getMessage(Element.date)); | ||
} | ||
if ((0, icu_messageformat_parser_1.isTimeElement)(el) && blocklist.includes(Element.time)) { | ||
throw new BlacklistElement(Element.time); | ||
errors.push(getMessage(Element.time)); | ||
} | ||
if ((0, icu_messageformat_parser_1.isSelectElement)(el) && blocklist.includes(Element.select)) { | ||
throw new BlacklistElement(Element.select); | ||
errors.push(getMessage(Element.select)); | ||
} | ||
if ((0, icu_messageformat_parser_1.isTagElement)(el) && blocklist.includes(Element.tag)) { | ||
throw new BlacklistElement(Element.tag); | ||
errors.push(getMessage(Element.tag)); | ||
} | ||
if ((0, icu_messageformat_parser_1.isPluralElement)(el)) { | ||
if (blocklist.includes(Element.plural)) { | ||
throw new BlacklistElement(Element.argument); | ||
errors.push(getMessage(Element.argument)); | ||
} | ||
if (el.pluralType === 'ordinal' && | ||
blocklist.includes(Element.selectordinal)) { | ||
throw new BlacklistElement(Element.selectordinal); | ||
errors.push(getMessage(Element.selectordinal)); | ||
} | ||
@@ -63,2 +66,3 @@ } | ||
} | ||
return errors; | ||
} | ||
@@ -79,11 +83,9 @@ function checkNode(context, node) { | ||
} | ||
try { | ||
verifyAst(context.options[0], (0, icu_messageformat_parser_1.parse)(defaultMessage, { | ||
ignoreTag: settings.ignoreTag, | ||
})); | ||
} | ||
catch (e) { | ||
const errors = verifyAst(blocklist, (0, icu_messageformat_parser_1.parse)(defaultMessage, { | ||
ignoreTag: settings.ignoreTag, | ||
})); | ||
for (const error of errors) { | ||
context.report({ | ||
node: messageNode, | ||
message: e instanceof Error ? e.message : String(e), | ||
node, | ||
...error, | ||
}); | ||
@@ -93,3 +95,19 @@ } | ||
} | ||
const rule = { | ||
const create = (context) => { | ||
const callExpressionVisitor = (node) => checkNode(context, node); | ||
//@ts-expect-error defineTemplateBodyVisitor exists in Vue parser | ||
if (context.parserServices?.defineTemplateBodyVisitor) { | ||
//@ts-expect-error | ||
return context.parserServices.defineTemplateBodyVisitor({ | ||
CallExpression: callExpressionVisitor, | ||
}, { | ||
CallExpression: callExpressionVisitor, | ||
}); | ||
} | ||
return { | ||
JSXOpeningElement: (node) => checkNode(context, node), | ||
CallExpression: callExpressionVisitor, | ||
}; | ||
}; | ||
exports.rule = { | ||
meta: { | ||
@@ -99,4 +117,2 @@ type: 'problem', | ||
description: 'Disallow specific elements in ICU message format', | ||
category: 'Errors', | ||
recommended: false, | ||
url: 'https://formatjs.io/docs/tooling/linter#blocklist-elements', | ||
@@ -108,26 +124,14 @@ }, | ||
type: 'array', | ||
properties: { | ||
items: { | ||
type: 'string', | ||
enum: Object.keys(Element), | ||
}, | ||
items: { | ||
type: 'string', | ||
enum: Object.keys(Element), | ||
}, | ||
}, | ||
], | ||
messages: { | ||
blocklist: `{{type}} element is blocklisted`, | ||
}, | ||
}, | ||
create(context) { | ||
const callExpressionVisitor = (node) => checkNode(context, node); | ||
if (context.parserServices.defineTemplateBodyVisitor) { | ||
return context.parserServices.defineTemplateBodyVisitor({ | ||
CallExpression: callExpressionVisitor, | ||
}, { | ||
CallExpression: callExpressionVisitor, | ||
}); | ||
} | ||
return { | ||
JSXOpeningElement: (node) => checkNode(context, node), | ||
CallExpression: callExpressionVisitor, | ||
}; | ||
}, | ||
defaultOptions: [], | ||
create, | ||
}; | ||
exports.default = rule; |
@@ -1,3 +0,10 @@ | ||
import { Rule } from 'eslint'; | ||
declare const rule: Rule.RuleModule; | ||
export default rule; | ||
import { RuleModule, RuleListener } from '@typescript-eslint/utils/ts-eslint'; | ||
export declare enum Option { | ||
literal = "literal", | ||
anything = "anything" | ||
} | ||
type MessageIds = 'defaultMessage' | 'defaultMessageLiteral'; | ||
type Options = [`${Option}`?]; | ||
export declare const name = "enforce-default-message"; | ||
export declare const rule: RuleModule<MessageIds, Options, RuleListener>; | ||
export {}; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.rule = exports.name = exports.Option = void 0; | ||
const util_1 = require("../util"); | ||
var Option; | ||
(function (Option) { | ||
Option["literal"] = "literal"; | ||
Option["anything"] = "anything"; | ||
})(Option || (exports.Option = Option = {})); | ||
exports.name = 'enforce-default-message'; | ||
function checkNode(context, node) { | ||
@@ -12,5 +19,3 @@ const msgs = (0, util_1.extractMessages)(node, (0, util_1.getSettings)(context)); | ||
node: messageNode, | ||
message: `"defaultMessage" must be: | ||
- a string literal or | ||
- template literal without variable`, | ||
messageId: 'defaultMessageLiteral', | ||
}); | ||
@@ -21,3 +26,3 @@ } | ||
node: node, | ||
message: '`defaultMessage` has to be specified in message descriptor', | ||
messageId: 'defaultMessage', | ||
}); | ||
@@ -28,3 +33,3 @@ } | ||
} | ||
const rule = { | ||
exports.rule = { | ||
meta: { | ||
@@ -34,4 +39,2 @@ type: 'problem', | ||
description: 'Enforce defaultMessage in message descriptor', | ||
category: 'Errors', | ||
recommended: false, | ||
url: 'https://formatjs.io/docs/tooling/linter#enforce-default-message', | ||
@@ -42,9 +45,19 @@ }, | ||
{ | ||
enum: ['literal', 'anything'], | ||
type: 'string', | ||
enum: Object.keys(Option), | ||
}, | ||
], | ||
messages: { | ||
defaultMessageLiteral: `"defaultMessage" must be: | ||
- a string literal or | ||
- template literal without variable`, | ||
defaultMessage: '`defaultMessage` has to be specified in message descriptor', | ||
}, | ||
}, | ||
defaultOptions: [], | ||
create(context) { | ||
const callExpressionVisitor = (node) => checkNode(context, node); | ||
//@ts-expect-error defineTemplateBodyVisitor exists in Vue parser | ||
if (context.parserServices.defineTemplateBodyVisitor) { | ||
//@ts-expect-error | ||
return context.parserServices.defineTemplateBodyVisitor({ | ||
@@ -62,2 +75,1 @@ CallExpression: callExpressionVisitor, | ||
}; | ||
exports.default = rule; |
@@ -1,3 +0,10 @@ | ||
import { Rule } from 'eslint'; | ||
declare const _default: Rule.RuleModule; | ||
export default _default; | ||
import { RuleModule, RuleListener } from '@typescript-eslint/utils/ts-eslint'; | ||
export declare enum Option { | ||
literal = "literal", | ||
anything = "anything" | ||
} | ||
type MessageIds = 'enforceDescription' | 'enforceDescriptionLiteral'; | ||
type Options = [`${Option}`?]; | ||
export declare const name = "enforce-description"; | ||
export declare const rule: RuleModule<MessageIds, Options, RuleListener>; | ||
export {}; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.rule = exports.name = exports.Option = void 0; | ||
const util_1 = require("../util"); | ||
var Option; | ||
(function (Option) { | ||
Option["literal"] = "literal"; | ||
Option["anything"] = "anything"; | ||
})(Option || (exports.Option = Option = {})); | ||
function checkNode(context, node) { | ||
@@ -12,3 +18,3 @@ const msgs = (0, util_1.extractMessages)(node, (0, util_1.getSettings)(context)); | ||
node: descriptionNode, | ||
message: '`description` has to be a string literal (not function call or variable)', | ||
messageId: 'enforceDescriptionLiteral', | ||
}); | ||
@@ -19,3 +25,3 @@ } | ||
node: node, | ||
message: '`description` has to be specified in message descriptor', | ||
messageId: 'enforceDescription', | ||
}); | ||
@@ -26,3 +32,4 @@ } | ||
} | ||
exports.default = { | ||
exports.name = 'enforce-description'; | ||
exports.rule = { | ||
meta: { | ||
@@ -32,4 +39,2 @@ type: 'problem', | ||
description: 'Enforce description in message descriptor', | ||
category: 'Errors', | ||
recommended: false, | ||
url: 'https://formatjs.io/docs/tooling/linter#enforce-description', | ||
@@ -40,9 +45,17 @@ }, | ||
{ | ||
enum: ['literal', 'anything'], | ||
type: 'string', | ||
enum: Object.keys(Option), | ||
}, | ||
], | ||
messages: { | ||
enforceDescription: '`description` has to be specified in message descriptor', | ||
enforceDescriptionLiteral: '`description` has to be a string literal (not function call or variable)', | ||
}, | ||
}, | ||
defaultOptions: [], | ||
create(context) { | ||
const callExpressionVisitor = (node) => checkNode(context, node); | ||
//@ts-expect-error defineTemplateBodyVisitor exists in Vue parser | ||
if (context.parserServices.defineTemplateBodyVisitor) { | ||
//@ts-expect-error | ||
return context.parserServices.defineTemplateBodyVisitor({ | ||
@@ -49,0 +62,0 @@ CallExpression: callExpressionVisitor, |
@@ -1,3 +0,10 @@ | ||
import { Rule } from 'eslint'; | ||
declare const _default: Rule.RuleModule; | ||
export default _default; | ||
import { RuleModule, RuleListener } from '@typescript-eslint/utils/ts-eslint'; | ||
export type Option = { | ||
idInterpolationPattern: string; | ||
idWhitelist?: string[]; | ||
}; | ||
type MessageIds = 'enforceId' | 'enforceIdDefaultMessage' | 'enforceIdDescription' | 'enforceIdMatching' | 'enforceIdMatchingAllowlisted'; | ||
type Options = [Option]; | ||
export declare const name = "enforce-id"; | ||
export declare const rule: RuleModule<MessageIds, Options, RuleListener>; | ||
export {}; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.rule = exports.name = void 0; | ||
const ts_transformer_1 = require("@formatjs/ts-transformer"); | ||
const util_1 = require("../util"); | ||
function checkNode(context, node, { idInterpolationPattern, idWhitelistRegexps }) { | ||
function checkNode(context, node, { idInterpolationPattern, idWhitelistRegexps, }) { | ||
const msgs = (0, util_1.extractMessages)(node, (0, util_1.getSettings)(context)); | ||
@@ -10,4 +11,4 @@ for (const [{ message: { defaultMessage, description, id }, idPropNode, descriptionNode, messagePropNode, },] of msgs) { | ||
context.report({ | ||
node: node, | ||
message: `id must be specified`, | ||
node, | ||
messageId: 'enforceId', | ||
}); | ||
@@ -18,4 +19,4 @@ } | ||
context.report({ | ||
node: node, | ||
message: `defaultMessage must be a string literal to calculate generated IDs`, | ||
node, | ||
messageId: 'enforceIdDefaultMessage', | ||
}); | ||
@@ -25,4 +26,4 @@ } | ||
context.report({ | ||
node: node, | ||
message: `description must be a string literal to calculate generated IDs`, | ||
node, | ||
messageId: 'enforceIdDescription', | ||
}); | ||
@@ -45,13 +46,21 @@ } | ||
if (id !== correctId) { | ||
let message = `"id" does not match with hash pattern ${idInterpolationPattern}`; | ||
let messageId = 'enforceIdMatching'; | ||
let messageData = { | ||
idInterpolationPattern, | ||
expected: correctId, | ||
actual: id, | ||
}; | ||
if (idWhitelistRegexps) { | ||
message += ` or allowlisted patterns ["${idWhitelistRegexps | ||
.map(r => r.toString()) | ||
.join('", "')}"]`; | ||
messageId = 'enforceIdMatchingAllowlisted'; | ||
messageData = { | ||
...messageData, | ||
idWhitelist: idWhitelistRegexps | ||
.map(r => `"${r.toString()}"`) | ||
.join(', '), | ||
}; | ||
} | ||
context.report({ | ||
node: node, | ||
message: `${message}. | ||
Expected: ${correctId} | ||
Actual: ${id}`, | ||
node, | ||
messageId, | ||
data: messageData, | ||
fix(fixer) { | ||
@@ -64,7 +73,10 @@ if (idPropNode) { | ||
} | ||
// Insert after default message node | ||
if (messagePropNode.type === 'JSXAttribute') { | ||
return fixer.insertTextAfter(messagePropNode, ` id="${correctId}"`); | ||
if (messagePropNode) { | ||
// Insert after default message node | ||
if (messagePropNode.type === 'JSXAttribute') { | ||
return fixer.insertTextAfter(messagePropNode, ` id="${correctId}"`); | ||
} | ||
return fixer.insertTextAfter(messagePropNode, `, id: '${correctId}'`); | ||
} | ||
return fixer.insertTextAfter(messagePropNode, `, id: '${correctId}'`); | ||
return null; | ||
}, | ||
@@ -77,3 +89,4 @@ }); | ||
} | ||
exports.default = { | ||
exports.name = 'enforce-id'; | ||
exports.rule = { | ||
meta: { | ||
@@ -83,4 +96,2 @@ type: 'problem', | ||
description: 'Enforce (generated) ID in message descriptor', | ||
category: 'Errors', | ||
recommended: false, | ||
url: 'https://formatjs.io/docs/tooling/linter#enforce-id', | ||
@@ -109,6 +120,22 @@ }, | ||
], | ||
messages: { | ||
enforceId: `id must be specified`, | ||
enforceIdDefaultMessage: `defaultMessage must be a string literal to calculate generated IDs`, | ||
enforceIdDescription: `description must be a string literal to calculate generated IDs`, | ||
enforceIdMatching: `"id" does not match with hash pattern {{idInterpolationPattern}}. | ||
Expected: {{expected}} | ||
Actual: {{actual}}`, | ||
enforceIdMatchingAllowlisted: `"id" does not match with hash pattern {{idInterpolationPattern}} or allowlisted patterns {{idWhitelist}}. | ||
Expected: {{expected}} | ||
Actual: {{actual}}`, | ||
}, | ||
}, | ||
defaultOptions: [ | ||
{ | ||
idInterpolationPattern: '[sha512:contenthash:base64:6]', | ||
}, | ||
], | ||
create(context) { | ||
const tmp = context?.options?.[0]; | ||
const opts = { | ||
const tmp = context.options[0]; | ||
let opts = { | ||
idInterpolationPattern: tmp?.idInterpolationPattern, | ||
@@ -121,3 +148,5 @@ }; | ||
const callExpressionVisitor = (node) => checkNode(context, node, opts); | ||
//@ts-expect-error defineTemplateBodyVisitor exists in Vue parser | ||
if (context.parserServices.defineTemplateBodyVisitor) { | ||
//@ts-expect-error | ||
return context.parserServices.defineTemplateBodyVisitor({ | ||
@@ -124,0 +153,0 @@ CallExpression: callExpressionVisitor, |
@@ -1,3 +0,8 @@ | ||
import { Rule } from 'eslint'; | ||
declare const rule: Rule.RuleModule; | ||
export default rule; | ||
import { RuleModule, RuleListener } from '@typescript-eslint/utils/ts-eslint'; | ||
type MessageIds = 'parserError' | 'missingValue' | 'unusedValue'; | ||
type Options = [{ | ||
ignoreList: string[]; | ||
}?]; | ||
export declare const name = "enforce-placeholders"; | ||
export declare const rule: RuleModule<MessageIds, Options, RuleListener>; | ||
export {}; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.rule = exports.name = void 0; | ||
const icu_messageformat_parser_1 = require("@formatjs/icu-messageformat-parser"); | ||
@@ -71,3 +72,4 @@ const util_1 = require("../util"); | ||
node: messageNode, | ||
message: e instanceof Error ? e.message : String(e), | ||
messageId: 'parserError', | ||
data: { message: e instanceof Error ? e.message : String(e) }, | ||
}); | ||
@@ -86,3 +88,6 @@ continue; | ||
node: messageNode, | ||
message: `Missing value(s) for the following placeholder(s): ${missingPlaceholders.join(', ')}.`, | ||
messageId: 'missingValue', | ||
data: { | ||
list: missingPlaceholders.join(', '), | ||
}, | ||
}); | ||
@@ -94,3 +99,3 @@ } | ||
node: element, | ||
message: 'Value not used by the message.', | ||
messageId: 'unusedValue', | ||
}); | ||
@@ -101,3 +106,4 @@ } | ||
} | ||
const rule = { | ||
exports.name = 'enforce-placeholders'; | ||
exports.rule = { | ||
meta: { | ||
@@ -107,4 +113,2 @@ type: 'problem', | ||
description: 'Enforce that all messages with placeholders have enough passed-in values', | ||
category: 'Errors', | ||
recommended: true, | ||
url: 'https://formatjs.io/docs/tooling/linter#enforce-placeholders', | ||
@@ -126,6 +130,14 @@ }, | ||
], | ||
messages: { | ||
parserError: '{{message}}', | ||
missingValue: 'Missing value(s) for the following placeholder(s): {{list}}.', | ||
unusedValue: 'Value not used by the message.', | ||
}, | ||
}, | ||
defaultOptions: [], | ||
create(context) { | ||
const callExpressionVisitor = (node) => checkNode(context, node); | ||
//@ts-expect-error defineTemplateBodyVisitor exists in Vue parser | ||
if (context.parserServices.defineTemplateBodyVisitor) { | ||
//@ts-expect-error | ||
return context.parserServices.defineTemplateBodyVisitor({ | ||
@@ -143,2 +155,1 @@ CallExpression: callExpressionVisitor, | ||
}; | ||
exports.default = rule; |
@@ -1,3 +0,17 @@ | ||
import { Rule } from 'eslint'; | ||
declare const rule: Rule.RuleModule; | ||
export default rule; | ||
import { RuleModule, RuleListener } from '@typescript-eslint/utils/ts-eslint'; | ||
declare enum LDML { | ||
zero = "zero", | ||
one = "one", | ||
two = "two", | ||
few = "few", | ||
many = "many", | ||
other = "other" | ||
} | ||
type PluralConfig = { | ||
[key in LDML]?: boolean; | ||
}; | ||
export type Options = [PluralConfig?]; | ||
type MessageIds = 'missingPlural' | 'forbidden'; | ||
export declare const name = "enforce-plural-rules"; | ||
export declare const rule: RuleModule<MessageIds, Options, RuleListener>; | ||
export {}; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.rule = exports.name = void 0; | ||
const icu_messageformat_parser_1 = require("@formatjs/icu-messageformat-parser"); | ||
const util_1 = require("../util"); | ||
class PluralRulesEnforcement extends Error { | ||
constructor(message) { | ||
super(); | ||
this.message = message; | ||
} | ||
} | ||
var LDML; | ||
@@ -21,2 +16,3 @@ (function (LDML) { | ||
function verifyAst(plConfig, ast) { | ||
const errors = []; | ||
for (const el of ast) { | ||
@@ -27,6 +23,6 @@ if ((0, icu_messageformat_parser_1.isPluralElement)(el)) { | ||
if (plConfig[rule] && !el.options[rule]) { | ||
throw new PluralRulesEnforcement(`Missing plural rule "${rule}"`); | ||
errors.push({ messageId: 'missingPlural', data: { rule } }); | ||
} | ||
if (!plConfig[rule] && el.options[rule]) { | ||
throw new PluralRulesEnforcement(`Plural rule "${rule}" is forbidden`); | ||
errors.push({ messageId: 'forbidden', data: { rule } }); | ||
} | ||
@@ -36,6 +32,7 @@ } | ||
for (const selector of Object.keys(options)) { | ||
verifyAst(plConfig, options[selector].value); | ||
errors.push(...verifyAst(plConfig, options[selector].value)); | ||
} | ||
} | ||
} | ||
return errors; | ||
} | ||
@@ -56,11 +53,9 @@ function checkNode(context, node) { | ||
} | ||
try { | ||
verifyAst(context.options[0], (0, icu_messageformat_parser_1.parse)(defaultMessage, { | ||
ignoreTag: settings.ignoreTag, | ||
})); | ||
} | ||
catch (e) { | ||
const errors = verifyAst(plConfig, (0, icu_messageformat_parser_1.parse)(defaultMessage, { | ||
ignoreTag: settings.ignoreTag, | ||
})); | ||
for (const error of errors) { | ||
context.report({ | ||
node: messageNode, | ||
message: e instanceof Error ? e.message : String(e), | ||
...error, | ||
}); | ||
@@ -70,3 +65,4 @@ } | ||
} | ||
const rule = { | ||
exports.name = 'enforce-plural-rules'; | ||
exports.rule = { | ||
meta: { | ||
@@ -76,4 +72,2 @@ type: 'problem', | ||
description: 'Enforce plural rules to always specify certain categories like `one`/`other`', | ||
category: 'Errors', | ||
recommended: false, | ||
url: 'https://formatjs.io/docs/tooling/linter#enforce-plural-rules', | ||
@@ -94,6 +88,13 @@ }, | ||
], | ||
messages: { | ||
missingPlural: `Missing plural rule "{{rule}}"`, | ||
forbidden: `Plural rule "{{rule}}" is forbidden`, | ||
}, | ||
}, | ||
defaultOptions: [], | ||
create(context) { | ||
const callExpressionVisitor = (node) => checkNode(context, node); | ||
//@ts-expect-error defineTemplateBodyVisitor exists in Vue parser | ||
if (context.parserServices.defineTemplateBodyVisitor) { | ||
//@ts-expect-error | ||
return context.parserServices.defineTemplateBodyVisitor({ | ||
@@ -111,2 +112,1 @@ CallExpression: callExpressionVisitor, | ||
}; | ||
exports.default = rule; |
@@ -1,3 +0,6 @@ | ||
import { Rule } from 'eslint'; | ||
declare const rule: Rule.RuleModule; | ||
export default rule; | ||
import { RuleModule, RuleListener } from '@typescript-eslint/utils/ts-eslint'; | ||
type MessageIds = 'camelcase'; | ||
type Options = [Element[]?]; | ||
export declare const name = "no-camel-case"; | ||
export declare const rule: RuleModule<MessageIds, Options, RuleListener>; | ||
export {}; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.rule = exports.name = void 0; | ||
const icu_messageformat_parser_1 = require("@formatjs/icu-messageformat-parser"); | ||
const util_1 = require("../util"); | ||
exports.name = 'no-camel-case'; | ||
const CAMEL_CASE_REGEX = /[A-Z]/; | ||
class CamelCase extends Error { | ||
constructor() { | ||
super(...arguments); | ||
this.message = 'Camel case arguments are not allowed'; | ||
} | ||
} | ||
function verifyAst(ast) { | ||
const errors = []; | ||
for (const el of ast) { | ||
if ((0, icu_messageformat_parser_1.isArgumentElement)(el)) { | ||
if (CAMEL_CASE_REGEX.test(el.value)) { | ||
throw new CamelCase(); | ||
errors.push({ messageId: 'camelcase', data: {} }); | ||
} | ||
@@ -22,10 +19,11 @@ continue; | ||
if (CAMEL_CASE_REGEX.test(el.value)) { | ||
throw new CamelCase(); | ||
errors.push({ messageId: 'camelcase', data: {} }); | ||
} | ||
const { options } = el; | ||
for (const selector of Object.keys(options)) { | ||
verifyAst(options[selector].value); | ||
errors.push(...verifyAst(options[selector].value)); | ||
} | ||
} | ||
} | ||
return errors; | ||
} | ||
@@ -39,11 +37,9 @@ function checkNode(context, node) { | ||
} | ||
try { | ||
verifyAst((0, icu_messageformat_parser_1.parse)(defaultMessage, { | ||
ignoreTag: settings.ignoreTag, | ||
})); | ||
} | ||
catch (e) { | ||
const errors = verifyAst((0, icu_messageformat_parser_1.parse)(defaultMessage, { | ||
ignoreTag: settings.ignoreTag, | ||
})); | ||
for (const error of errors) { | ||
context.report({ | ||
node: messageNode, | ||
message: e instanceof Error ? e.message : String(e), | ||
...error, | ||
}); | ||
@@ -53,3 +49,3 @@ } | ||
} | ||
const rule = { | ||
exports.rule = { | ||
meta: { | ||
@@ -59,11 +55,16 @@ type: 'problem', | ||
description: 'Disallow camel case placeholders in message', | ||
category: 'Errors', | ||
recommended: false, | ||
url: 'https://formatjs.io/docs/tooling/linter#no-camel-case', | ||
}, | ||
fixable: 'code', | ||
schema: [], | ||
messages: { | ||
camelcase: 'Camel case arguments are not allowed', | ||
}, | ||
}, | ||
defaultOptions: [], | ||
create(context) { | ||
const callExpressionVisitor = (node) => checkNode(context, node); | ||
//@ts-expect-error defineTemplateBodyVisitor exists in Vue parser | ||
if (context.parserServices.defineTemplateBodyVisitor) { | ||
//@ts-expect-error | ||
return context.parserServices.defineTemplateBodyVisitor({ | ||
@@ -81,2 +82,1 @@ CallExpression: callExpressionVisitor, | ||
}; | ||
exports.default = rule; |
@@ -1,3 +0,9 @@ | ||
import { Rule } from 'eslint'; | ||
declare const rule: Rule.RuleModule; | ||
export default rule; | ||
import { RuleModule, RuleListener } from '@typescript-eslint/utils/ts-eslint'; | ||
interface Config { | ||
limit: number; | ||
} | ||
type MessageIds = 'tooComplex' | 'parserError'; | ||
type Options = [Config?]; | ||
export declare const name = "no-complex-selectors"; | ||
export declare const rule: RuleModule<MessageIds, Options, RuleListener>; | ||
export {}; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.rule = exports.name = void 0; | ||
const icu_messageformat_parser_1 = require("@formatjs/icu-messageformat-parser"); | ||
@@ -68,20 +69,16 @@ const util_1 = require("../util"); | ||
node: messageNode, | ||
message: e instanceof Error ? e.message : String(e), | ||
messageId: 'parserError', | ||
data: { message: e instanceof Error ? e.message : String(e) }, | ||
}); | ||
return; | ||
} | ||
let complexity = 0; | ||
try { | ||
complexity = calculateComplexity(ast); | ||
} | ||
catch (e) { | ||
context.report({ | ||
node: messageNode, | ||
message: e instanceof Error ? e.message : e, | ||
}); | ||
} | ||
const complexity = calculateComplexity(ast); | ||
if (complexity > config.limit) { | ||
context.report({ | ||
node: messageNode, | ||
message: `Message complexity is too high (${complexity} vs limit at ${config.limit})`, | ||
messageId: 'tooComplex', | ||
data: { | ||
complexity, | ||
limit: config.limit, | ||
}, | ||
}); | ||
@@ -91,3 +88,4 @@ } | ||
} | ||
const rule = { | ||
exports.name = 'no-complex-selectors'; | ||
exports.rule = { | ||
meta: { | ||
@@ -105,4 +103,2 @@ type: 'problem', | ||
`, | ||
category: 'Errors', | ||
recommended: false, | ||
url: 'https://formatjs.io/docs/tooling/linter#no-complex-selectors', | ||
@@ -122,6 +118,13 @@ }, | ||
fixable: 'code', | ||
messages: { | ||
tooComplex: `Message complexity is too high ({{complexity}} vs limit at {{limit}})`, | ||
parserError: '{{meesage}}', | ||
}, | ||
}, | ||
defaultOptions: [{ limit: 20 }], | ||
create(context) { | ||
const callExpressionVisitor = (node) => checkNode(context, node); | ||
//@ts-expect-error defineTemplateBodyVisitor exists in Vue parser | ||
if (context.parserServices.defineTemplateBodyVisitor) { | ||
//@ts-expect-error | ||
return context.parserServices.defineTemplateBodyVisitor({ | ||
@@ -139,2 +142,1 @@ CallExpression: callExpressionVisitor, | ||
}; | ||
exports.default = rule; |
@@ -1,3 +0,9 @@ | ||
import { Rule } from 'eslint'; | ||
declare const rule: Rule.RuleModule; | ||
export default rule; | ||
import { RuleModule, RuleListener } from '@typescript-eslint/utils/ts-eslint'; | ||
export declare const name = "no-emoji"; | ||
type MessageIds = 'notAllowed' | 'notAllowedAboveVersion'; | ||
type NoEmojiConfig = { | ||
versionAbove: string; | ||
}; | ||
export type Options = [NoEmojiConfig?]; | ||
export declare const rule: RuleModule<MessageIds, Options, RuleListener>; | ||
export {}; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.rule = exports.name = void 0; | ||
const unicode_emoji_utils_1 = require("unicode-emoji-utils"); | ||
const util_1 = require("../util"); | ||
exports.name = 'no-emoji'; | ||
function checkNode(context, node) { | ||
@@ -61,3 +63,3 @@ const msgs = (0, util_1.extractMessages)(node, (0, util_1.getSettings)(context)); | ||
]; | ||
const rule = { | ||
exports.rule = { | ||
meta: { | ||
@@ -67,4 +69,2 @@ type: 'problem', | ||
description: 'Disallow emojis in message', | ||
category: 'Errors', | ||
recommended: false, | ||
url: 'https://formatjs.io/docs/tooling/linter#no-emoji', | ||
@@ -85,5 +85,8 @@ }, | ||
}, | ||
defaultOptions: [], | ||
create(context) { | ||
const callExpressionVisitor = (node) => checkNode(context, node); | ||
//@ts-expect-error defineTemplateBodyVisitor exists in Vue parser | ||
if (context.parserServices.defineTemplateBodyVisitor) { | ||
//@ts-expect-error | ||
return context.parserServices.defineTemplateBodyVisitor({ | ||
@@ -101,2 +104,1 @@ CallExpression: callExpressionVisitor, | ||
}; | ||
exports.default = rule; |
@@ -1,3 +0,6 @@ | ||
import { Rule } from 'eslint'; | ||
declare const _default: Rule.RuleModule; | ||
export default _default; | ||
import { RuleModule, RuleListener } from '@typescript-eslint/utils/ts-eslint'; | ||
type MessageIds = 'noId'; | ||
type Options = []; | ||
export declare const name = "no-id"; | ||
export declare const rule: RuleModule<MessageIds, Options, RuleListener>; | ||
export {}; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.rule = exports.name = void 0; | ||
const util_1 = require("../util"); | ||
@@ -7,2 +8,3 @@ function isComment(token) { | ||
} | ||
exports.name = 'no-id'; | ||
function checkNode(context, node) { | ||
@@ -14,3 +16,3 @@ const msgs = (0, util_1.extractMessages)(node, (0, util_1.getSettings)(context)); | ||
node: idPropNode, | ||
message: 'Manual `id` are not allowed in message descriptor', | ||
messageId: 'noId', | ||
fix(fixer) { | ||
@@ -29,3 +31,3 @@ const src = context.getSourceCode(); | ||
} | ||
exports.default = { | ||
exports.rule = { | ||
meta: { | ||
@@ -35,11 +37,16 @@ type: 'problem', | ||
description: 'Ban explicit ID from MessageDescriptor', | ||
category: 'Errors', | ||
recommended: false, | ||
url: 'https://formatjs.io/docs/tooling/linter#no-id', | ||
}, | ||
fixable: 'code', | ||
schema: [], | ||
messages: { | ||
noId: 'Manual `id` are not allowed in message descriptor', | ||
}, | ||
}, | ||
defaultOptions: [], | ||
create(context) { | ||
const callExpressionVisitor = (node) => checkNode(context, node); | ||
//@ts-expect-error defineTemplateBodyVisitor exists in Vue parser | ||
if (context.parserServices.defineTemplateBodyVisitor) { | ||
//@ts-expect-error | ||
return context.parserServices.defineTemplateBodyVisitor({ | ||
@@ -46,0 +53,0 @@ CallExpression: callExpressionVisitor, |
@@ -1,3 +0,6 @@ | ||
import { Rule } from 'eslint'; | ||
declare const rule: Rule.RuleModule; | ||
export default rule; | ||
import { RuleModule, RuleListener } from '@typescript-eslint/utils/ts-eslint'; | ||
type MessageIds = 'icuError'; | ||
type Options = []; | ||
export declare const name = "no-invalid-icu"; | ||
export declare const rule: RuleModule<MessageIds, Options, RuleListener>; | ||
export {}; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.rule = exports.name = void 0; | ||
const icu_messageformat_parser_1 = require("@formatjs/icu-messageformat-parser"); | ||
const util_1 = require("../util"); | ||
exports.name = 'no-invalid-icu'; | ||
function checkNode(context, node) { | ||
@@ -24,3 +26,4 @@ const settings = (0, util_1.getSettings)(context); | ||
node: messageNode, | ||
message: `Error parsing ICU string: ${msg}`, | ||
messageId: 'icuError', | ||
data: { message: `Error parsing ICU string: ${msg}` }, | ||
}); | ||
@@ -30,3 +33,3 @@ } | ||
} | ||
const rule = { | ||
exports.rule = { | ||
meta: { | ||
@@ -36,10 +39,15 @@ type: 'problem', | ||
description: `Make sure ICU messages are formatted correctly with no bad select statements, plurals, etc.`, | ||
category: 'Errors', | ||
recommended: true, | ||
}, | ||
fixable: 'code', | ||
schema: [], | ||
messages: { | ||
icuError: 'Invalid ICU Message format: {{message}}', | ||
}, | ||
}, | ||
defaultOptions: [], | ||
create(context) { | ||
const callExpressionVisitor = (node) => checkNode(context, node); | ||
//@ts-expect-error defineTemplateBodyVisitor exists in Vue parser | ||
if (context.parserServices.defineTemplateBodyVisitor) { | ||
//@ts-expect-error | ||
return context.parserServices.defineTemplateBodyVisitor({ | ||
@@ -57,2 +65,1 @@ CallExpression: callExpressionVisitor, | ||
}; | ||
exports.default = rule; |
@@ -1,3 +0,13 @@ | ||
import type { Rule } from 'eslint'; | ||
declare const rule: Rule.RuleModule; | ||
export default rule; | ||
import { RuleModule, RuleListener } from '@typescript-eslint/utils/ts-eslint'; | ||
type PropMatcher = readonly [TagNamePattern: string, PropNamePattern: string][]; | ||
type Config = { | ||
props?: { | ||
include?: PropMatcher; | ||
exclude?: PropMatcher; | ||
}; | ||
}; | ||
type MessageIds = 'noLiteralStringInJsx'; | ||
type Options = [Config?]; | ||
export declare const name = "no-literal-string-in-jsx"; | ||
export declare const rule: RuleModule<MessageIds, Options, RuleListener>; | ||
export {}; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.rule = exports.name = void 0; | ||
const tslib_1 = require("tslib"); | ||
@@ -37,3 +38,4 @@ const utils_1 = require("@typescript-eslint/utils"); | ||
} | ||
const rule = { | ||
exports.name = 'no-literal-string-in-jsx'; | ||
exports.rule = { | ||
meta: { | ||
@@ -43,4 +45,2 @@ type: 'problem', | ||
description: 'Disallow untranslated literal strings without translation.', | ||
category: 'Errors', | ||
recommended: false, | ||
url: 'https://formatjs.io/docs/tooling/linter#no-literal-string-in-jsx', | ||
@@ -66,3 +66,7 @@ }, | ||
], | ||
messages: { | ||
noLiteralStringInJsx: 'Cannot have untranslated text in JSX', | ||
}, | ||
}, | ||
defaultOptions: [], | ||
// TODO: Vue support | ||
@@ -115,3 +119,3 @@ create(context) { | ||
node: node, | ||
message: 'Cannot have untranslated text in JSX', | ||
messageId: 'noLiteralStringInJsx', | ||
}); | ||
@@ -157,3 +161,3 @@ } | ||
node: node, | ||
message: 'Cannot have untranslated text in JSX', | ||
messageId: 'noLiteralStringInJsx', | ||
}); | ||
@@ -173,3 +177,3 @@ } | ||
node: node, | ||
message: 'Cannot have untranslated text in JSX', | ||
messageId: 'noLiteralStringInJsx', | ||
}); | ||
@@ -186,2 +190,1 @@ }, | ||
}; | ||
exports.default = rule; |
@@ -1,3 +0,6 @@ | ||
import { Rule } from 'eslint'; | ||
declare const rule: Rule.RuleModule; | ||
export default rule; | ||
import { RuleModule, RuleListener } from '@typescript-eslint/utils/ts-eslint'; | ||
type MessageIds = 'noMultiplePlurals'; | ||
type Options = []; | ||
export declare const name = "no-multiple-plurals"; | ||
export declare const rule: RuleModule<MessageIds, Options, RuleListener>; | ||
export {}; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.rule = exports.name = void 0; | ||
const icu_messageformat_parser_1 = require("@formatjs/icu-messageformat-parser"); | ||
const util_1 = require("../util"); | ||
class MultiplePlurals extends Error { | ||
constructor() { | ||
super(...arguments); | ||
this.message = 'Cannot specify more than 1 plural rules'; | ||
} | ||
} | ||
function verifyAst(ast, pluralCount = { count: 0 }) { | ||
const errors = []; | ||
for (const el of ast) { | ||
@@ -16,10 +12,11 @@ if ((0, icu_messageformat_parser_1.isPluralElement)(el)) { | ||
if (pluralCount.count > 1) { | ||
throw new MultiplePlurals(); | ||
errors.push({ messageId: 'noMultiplePlurals', data: {} }); | ||
} | ||
const { options } = el; | ||
for (const selector of Object.keys(options)) { | ||
verifyAst(options[selector].value, pluralCount); | ||
errors.push(...verifyAst(options[selector].value, pluralCount)); | ||
} | ||
} | ||
} | ||
return errors; | ||
} | ||
@@ -33,11 +30,9 @@ function checkNode(context, node) { | ||
} | ||
try { | ||
verifyAst((0, icu_messageformat_parser_1.parse)(defaultMessage, { | ||
ignoreTag: settings.ignoreTag, | ||
})); | ||
} | ||
catch (e) { | ||
const errors = verifyAst((0, icu_messageformat_parser_1.parse)(defaultMessage, { | ||
ignoreTag: settings.ignoreTag, | ||
})); | ||
for (const error of errors) { | ||
context.report({ | ||
node: messageNode, | ||
message: e instanceof Error ? e.message : String(e), | ||
node, | ||
...error, | ||
}); | ||
@@ -47,3 +42,4 @@ } | ||
} | ||
const rule = { | ||
exports.name = 'no-multiple-plurals'; | ||
exports.rule = { | ||
meta: { | ||
@@ -53,11 +49,16 @@ type: 'problem', | ||
description: 'Disallow multiple plural rules in the same message', | ||
category: 'Errors', | ||
recommended: false, | ||
url: 'https://formatjs.io/docs/tooling/linter#no-multiple-plurals', | ||
}, | ||
fixable: 'code', | ||
schema: [], | ||
messages: { | ||
noMultiplePlurals: 'Multiple plural rules in the same message', | ||
}, | ||
}, | ||
defaultOptions: [], | ||
create(context) { | ||
const callExpressionVisitor = (node) => checkNode(context, node); | ||
//@ts-expect-error defineTemplateBodyVisitor exists in Vue parser | ||
if (context.parserServices.defineTemplateBodyVisitor) { | ||
//@ts-expect-error | ||
return context.parserServices.defineTemplateBodyVisitor({ | ||
@@ -75,2 +76,1 @@ CallExpression: callExpressionVisitor, | ||
}; | ||
exports.default = rule; |
@@ -1,3 +0,6 @@ | ||
import { Rule } from 'eslint'; | ||
declare const rule: Rule.RuleModule; | ||
export default rule; | ||
import { RuleModule, RuleListener } from '@typescript-eslint/utils/ts-eslint'; | ||
type MessageIds = 'noMultipleWhitespaces' | 'parserError'; | ||
type Options = []; | ||
export declare const name = "no-multiple-whitespaces"; | ||
export declare const rule: RuleModule<MessageIds, Options, RuleListener>; | ||
export {}; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.rule = exports.name = void 0; | ||
const icu_messageformat_parser_1 = require("@formatjs/icu-messageformat-parser"); | ||
@@ -92,3 +93,4 @@ const util_1 = require("../util"); | ||
node: messageNode, | ||
message: e instanceof Error ? e.message : String(e), | ||
messageId: 'parserError', | ||
data: { message: e instanceof Error ? e.message : String(e) }, | ||
}); | ||
@@ -109,3 +111,4 @@ return; | ||
} | ||
const rule = { | ||
exports.name = 'no-multiple-whitespaces'; | ||
exports.rule = { | ||
meta: { | ||
@@ -115,4 +118,2 @@ type: 'problem', | ||
description: 'Prevents usage of multiple consecutive whitespaces in message', | ||
category: 'Errors', | ||
recommended: false, | ||
url: 'https://formatjs.io/docs/tooling/linter#no-multiple-whitespaces', | ||
@@ -122,8 +123,13 @@ }, | ||
noMultipleWhitespaces: 'Multiple consecutive whitespaces are not allowed', | ||
parserError: '{{message}}', | ||
}, | ||
fixable: 'code', | ||
schema: [], | ||
}, | ||
defaultOptions: [], | ||
create(context) { | ||
const callExpressionVisitor = (node) => checkNode(context, node); | ||
//@ts-expect-error defineTemplateBodyVisitor exists in Vue parser | ||
if (context.parserServices.defineTemplateBodyVisitor) { | ||
//@ts-expect-error | ||
return context.parserServices.defineTemplateBodyVisitor({ | ||
@@ -141,2 +147,1 @@ CallExpression: callExpressionVisitor, | ||
}; | ||
exports.default = rule; |
@@ -1,3 +0,6 @@ | ||
import { Rule } from 'eslint'; | ||
declare const rule: Rule.RuleModule; | ||
export default rule; | ||
import { RuleModule, RuleListener } from '@typescript-eslint/utils/ts-eslint'; | ||
type MessageIds = 'noOffset'; | ||
type Options = []; | ||
export declare const name = "no-offset"; | ||
export declare const rule: RuleModule<MessageIds, Options, RuleListener>; | ||
export {}; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.rule = exports.name = void 0; | ||
const icu_messageformat_parser_1 = require("@formatjs/icu-messageformat-parser"); | ||
const util_1 = require("../util"); | ||
class NoOffsetError extends Error { | ||
constructor() { | ||
super(...arguments); | ||
this.message = 'offset are not allowed in plural rules'; | ||
} | ||
} | ||
function verifyAst(ast) { | ||
const errors = []; | ||
for (const el of ast) { | ||
if ((0, icu_messageformat_parser_1.isPluralElement)(el)) { | ||
if (el.offset) { | ||
throw new NoOffsetError(); | ||
errors.push({ messageId: 'noOffset', data: {} }); | ||
} | ||
const { options } = el; | ||
for (const selector of Object.keys(options)) { | ||
verifyAst(options[selector].value); | ||
errors.push(...verifyAst(options[selector].value)); | ||
} | ||
} | ||
} | ||
return errors; | ||
} | ||
@@ -31,11 +28,9 @@ function checkNode(context, node) { | ||
} | ||
try { | ||
verifyAst((0, icu_messageformat_parser_1.parse)(defaultMessage, { | ||
ignoreTag: settings.ignoreTag, | ||
})); | ||
} | ||
catch (e) { | ||
const errors = verifyAst((0, icu_messageformat_parser_1.parse)(defaultMessage, { | ||
ignoreTag: settings.ignoreTag, | ||
})); | ||
for (const error of errors) { | ||
context.report({ | ||
node: messageNode, | ||
message: e.message, | ||
...error, | ||
}); | ||
@@ -45,3 +40,4 @@ } | ||
} | ||
const rule = { | ||
exports.name = 'no-offset'; | ||
exports.rule = { | ||
meta: { | ||
@@ -51,11 +47,16 @@ type: 'problem', | ||
description: 'Disallow offset in plural rules', | ||
category: 'Errors', | ||
recommended: false, | ||
url: 'https://formatjs.io/docs/tooling/linter#no-offset', | ||
}, | ||
fixable: 'code', | ||
messages: { | ||
noOffset: 'offset is not allowed', | ||
}, | ||
schema: [], | ||
}, | ||
defaultOptions: [], | ||
create(context) { | ||
const callExpressionVisitor = (node) => checkNode(context, node); | ||
//@ts-expect-error defineTemplateBodyVisitor exists in Vue parser | ||
if (context.parserServices.defineTemplateBodyVisitor) { | ||
//@ts-expect-error | ||
return context.parserServices.defineTemplateBodyVisitor({ | ||
@@ -73,2 +74,1 @@ CallExpression: callExpressionVisitor, | ||
}; | ||
exports.default = rule; |
@@ -1,3 +0,6 @@ | ||
import { Rule } from 'eslint'; | ||
declare const rule: Rule.RuleModule; | ||
export default rule; | ||
import { RuleModule, RuleListener } from '@typescript-eslint/utils/ts-eslint'; | ||
type MessageIds = 'unnecessaryFormat' | 'unnecessaryFormatNumber' | 'unnecessaryFormatDate' | 'unnecessaryFormatTime'; | ||
type Options = []; | ||
export declare const name = "no-useless-message"; | ||
export declare const rule: RuleModule<MessageIds, Options, RuleListener>; | ||
export {}; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.rule = exports.name = void 0; | ||
const icu_messageformat_parser_1 = require("@formatjs/icu-messageformat-parser"); | ||
const util_1 = require("../util"); | ||
class JustArgument extends Error { | ||
constructor() { | ||
super(...arguments); | ||
this.message = 'Unnecessary formatted message.'; | ||
} | ||
} | ||
class JustNumber extends Error { | ||
constructor() { | ||
super(...arguments); | ||
this.message = 'Unnecessary formatted message: just use FormattedNumber or intl.formatNumber.'; | ||
} | ||
} | ||
class JustDate extends Error { | ||
constructor() { | ||
super(...arguments); | ||
this.message = 'Unnecessary formatted message: just use FormattedDate or intl.formatDate.'; | ||
} | ||
} | ||
class JustTime extends Error { | ||
constructor() { | ||
super(...arguments); | ||
this.message = 'Unnecessary formatted message: just use FormattedTime or intl.formatTime.'; | ||
} | ||
} | ||
function verifyAst(ast) { | ||
@@ -35,9 +12,9 @@ if (ast.length !== 1) { | ||
case icu_messageformat_parser_1.TYPE.argument: | ||
throw new JustArgument(); | ||
return 'unnecessaryFormat'; | ||
case icu_messageformat_parser_1.TYPE.number: | ||
throw new JustNumber(); | ||
return 'unnecessaryFormatNumber'; | ||
case icu_messageformat_parser_1.TYPE.date: | ||
throw new JustDate(); | ||
return 'unnecessaryFormatDate'; | ||
case icu_messageformat_parser_1.TYPE.time: | ||
throw new JustTime(); | ||
return 'unnecessaryFormatTime'; | ||
} | ||
@@ -52,16 +29,14 @@ } | ||
} | ||
try { | ||
verifyAst((0, icu_messageformat_parser_1.parse)(defaultMessage, { | ||
ignoreTag: settings.ignoreTag, | ||
})); | ||
} | ||
catch (e) { | ||
const messageId = verifyAst((0, icu_messageformat_parser_1.parse)(defaultMessage, { | ||
ignoreTag: settings.ignoreTag, | ||
})); | ||
if (messageId) | ||
context.report({ | ||
node: messageNode, | ||
message: e instanceof Error ? e.message : String(e), | ||
messageId, | ||
}); | ||
} | ||
} | ||
} | ||
const rule = { | ||
exports.name = 'no-useless-message'; | ||
exports.rule = { | ||
meta: { | ||
@@ -71,10 +46,20 @@ type: 'problem', | ||
description: 'Disallow unnecessary formatted message', | ||
recommended: true, | ||
recommended: 'recommended', | ||
url: 'https://formatjs.io/docs/tooling/linter#no-useless-message', | ||
}, | ||
fixable: 'code', | ||
schema: [], | ||
messages: { | ||
unnecessaryFormat: 'Unnecessary formatted message.', | ||
unnecessaryFormatNumber: 'Unnecessary formatted message: just use FormattedNumber or intl.formatNumber.', | ||
unnecessaryFormatDate: 'Unnecessary formatted message: just use FormattedDate or intl.formatDate.', | ||
unnecessaryFormatTime: 'Unnecessary formatted message: just use FormattedTime or intl.formatTime.', | ||
}, | ||
}, | ||
defaultOptions: [], | ||
create(context) { | ||
const callExpressionVisitor = (node) => checkNode(context, node); | ||
//@ts-expect-error defineTemplateBodyVisitor exists in Vue parser | ||
if (context.parserServices.defineTemplateBodyVisitor) { | ||
//@ts-expect-error | ||
return context.parserServices.defineTemplateBodyVisitor({ | ||
@@ -92,2 +77,1 @@ CallExpression: callExpressionVisitor, | ||
}; | ||
exports.default = rule; |
@@ -1,3 +0,6 @@ | ||
import type { Rule } from 'eslint'; | ||
declare const rule: Rule.RuleModule; | ||
export default rule; | ||
import { RuleModule, RuleListener } from '@typescript-eslint/utils/ts-eslint'; | ||
type MessageIds = 'jsxChildren'; | ||
type Options = []; | ||
export declare const name = "prefer-formatted-message"; | ||
export declare const rule: RuleModule<MessageIds, Options, RuleListener>; | ||
export {}; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.rule = exports.name = void 0; | ||
const util_1 = require("../util"); | ||
const rule = { | ||
exports.name = 'prefer-formatted-message'; | ||
exports.rule = { | ||
meta: { | ||
@@ -9,3 +11,2 @@ type: 'suggestion', | ||
description: 'Prefer `FormattedMessage` component over `intl.formatMessage` if applicable.', | ||
recommended: false, | ||
url: 'https://formatjs.io/docs/tooling/linter#prefer-formatted-message', | ||
@@ -16,3 +17,5 @@ }, | ||
}, | ||
schema: [], | ||
}, | ||
defaultOptions: [], | ||
// TODO: Vue support | ||
@@ -36,2 +39,1 @@ create(context) { | ||
}; | ||
exports.default = rule; |
@@ -1,3 +0,6 @@ | ||
import type { Rule } from 'eslint'; | ||
declare const rule: Rule.RuleModule; | ||
export default rule; | ||
import { RuleModule, RuleListener } from '@typescript-eslint/utils/ts-eslint'; | ||
type MessageIds = 'preferPoundInPlurals' | 'parseError'; | ||
type Options = []; | ||
export declare const name = "prefer-pound-in-plural"; | ||
export declare const rule: RuleModule<MessageIds, Options, RuleListener>; | ||
export {}; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.rule = exports.name = void 0; | ||
const tslib_1 = require("tslib"); | ||
@@ -151,3 +152,4 @@ const icu_messageformat_parser_1 = require("@formatjs/icu-messageformat-parser"); | ||
node: messageNode, | ||
message: e instanceof Error ? e.message : String(e), | ||
messageId: 'parseError', | ||
data: { message: e instanceof Error ? e.message : String(e) }, | ||
}); | ||
@@ -159,3 +161,4 @@ return; | ||
} | ||
const rule = { | ||
exports.name = 'prefer-pound-in-plural'; | ||
exports.rule = { | ||
meta: { | ||
@@ -165,3 +168,2 @@ type: 'suggestion', | ||
description: 'Prefer using # to reference the count in the plural argument.', | ||
recommended: false, | ||
url: 'https://formatjs.io/docs/tooling/linter#prefer-pound-in-plurals', | ||
@@ -171,9 +173,14 @@ }, | ||
preferPoundInPlurals: 'Prefer using # to reference the count in the plural argument instead of repeating the argument.', | ||
parseError: '{{message}}', | ||
}, | ||
fixable: 'code', | ||
schema: [], | ||
}, | ||
defaultOptions: [], | ||
// TODO: Vue support | ||
create(context) { | ||
const callExpressionVisitor = (node) => checkNode(context, node); | ||
//@ts-expect-error defineTemplateBodyVisitor exists in Vue parser | ||
if (context.parserServices.defineTemplateBodyVisitor) { | ||
//@ts-expect-error | ||
return context.parserServices.defineTemplateBodyVisitor({ | ||
@@ -191,2 +198,1 @@ CallExpression: callExpressionVisitor, | ||
}; | ||
exports.default = rule; |
import { MessageFormatElement } from '@formatjs/icu-messageformat-parser'; | ||
import { TSESTree } from '@typescript-eslint/utils'; | ||
import { Rule } from 'eslint'; | ||
import { RuleContext } from '@typescript-eslint/utils/ts-eslint'; | ||
export interface MessageDescriptor { | ||
@@ -23,3 +23,3 @@ id?: string; | ||
} | ||
export declare function getSettings({ settings }: Rule.RuleContext): Settings; | ||
export declare function getSettings<TMessageIds extends string, TOptions extends readonly unknown[]>({ settings }: RuleContext<TMessageIds, TOptions>): Settings; | ||
export declare function isIntlFormatMessageCall(node: TSESTree.Node): node is TSESTree.CallExpression; | ||
@@ -26,0 +26,0 @@ export declare function extractMessageDescriptor(node?: TSESTree.Expression): MessageDescriptorNodeInfo | undefined; |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
92323
2378
+ Added@formatjs/ecma402-abstract@1.18.1(transitive)
+ Added@formatjs/icu-messageformat-parser@2.7.4(transitive)
+ Added@formatjs/icu-skeleton-parser@1.7.1(transitive)
+ Added@formatjs/intl-localematcher@0.5.3(transitive)
+ Added@formatjs/ts-transformer@3.13.10(transitive)
- Removed@formatjs/ecma402-abstract@1.18.0(transitive)
- Removed@formatjs/icu-messageformat-parser@2.7.3(transitive)
- Removed@formatjs/icu-skeleton-parser@1.7.0(transitive)
- Removed@formatjs/intl-localematcher@0.5.2(transitive)
- Removed@formatjs/ts-transformer@3.13.9(transitive)
Updatedunicode-emoji-utils@^1.2.0