eslint-plugin-formatjs 6.6.2 → 6.7.0-rc.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/index.js +591 -124
- package/index.js.map +1 -1
- package/package.json +3 -3
package/index.js
CHANGED
|
@@ -16,6 +16,56 @@ var __exportAll = (all, no_symbols) => {
|
|
|
16
16
|
return target;
|
|
17
17
|
};
|
|
18
18
|
//#endregion
|
|
19
|
+
//#region packages/eslint-plugin-formatjs/message-types.ts
|
|
20
|
+
function collectMessageArguments(ast) {
|
|
21
|
+
const argumentsByName = /* @__PURE__ */ new Map();
|
|
22
|
+
function visit(elements) {
|
|
23
|
+
for (const element of elements) {
|
|
24
|
+
if (element.type === TYPE.literal || element.type === TYPE.pound) continue;
|
|
25
|
+
const types = argumentsByName.get(element.value) ?? /* @__PURE__ */ new Set();
|
|
26
|
+
argumentsByName.set(element.value, types);
|
|
27
|
+
switch (element.type) {
|
|
28
|
+
case TYPE.argument: break;
|
|
29
|
+
case TYPE.number:
|
|
30
|
+
case TYPE.plural:
|
|
31
|
+
types.add("number");
|
|
32
|
+
break;
|
|
33
|
+
case TYPE.date:
|
|
34
|
+
case TYPE.time:
|
|
35
|
+
types.add("date");
|
|
36
|
+
break;
|
|
37
|
+
case TYPE.select:
|
|
38
|
+
types.add("select");
|
|
39
|
+
break;
|
|
40
|
+
case TYPE.tag:
|
|
41
|
+
types.add("tag");
|
|
42
|
+
visit(element.children);
|
|
43
|
+
}
|
|
44
|
+
if (element.type === TYPE.select || element.type === TYPE.plural) for (const option of Object.values(element.options)) visit(option.value);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
visit(ast);
|
|
48
|
+
return argumentsByName;
|
|
49
|
+
}
|
|
50
|
+
/** Derive one contract from the runtime parser's AST, including every branch. */
|
|
51
|
+
function messageTypes(ast, module, ignoreList = []) {
|
|
52
|
+
const argumentsByName = collectMessageArguments(ast);
|
|
53
|
+
const ignored = new Set(ignoreList);
|
|
54
|
+
for (const name of ignored) if (!argumentsByName.has(name)) argumentsByName.set(name, /* @__PURE__ */ new Set());
|
|
55
|
+
const fields = [...argumentsByName].sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([name, types]) => {
|
|
56
|
+
let type;
|
|
57
|
+
if (!types.size) type = `import(${JSON.stringify(module)}).MessageValue`;
|
|
58
|
+
else if (types.size === 2 && types.has("number") && types.has("date")) type = "number";
|
|
59
|
+
else if (types.size > 1) throw new Error(`Incompatible uses of argument ${JSON.stringify(name)}`);
|
|
60
|
+
else if (types.has("number")) type = "number | bigint";
|
|
61
|
+
else if (types.has("date")) type = "number | Date";
|
|
62
|
+
else if (types.has("select")) type = "string";
|
|
63
|
+
else type = `import(${JSON.stringify(module)}).MessageTag`;
|
|
64
|
+
return `${JSON.stringify(name)}${ignored.has(name) ? "?" : ""}: ${type}`;
|
|
65
|
+
});
|
|
66
|
+
return fields.length ? `{ ${fields.join("; ")} }` : "{}";
|
|
67
|
+
}
|
|
68
|
+
//#endregion
|
|
19
69
|
//#region packages/eslint-plugin-formatjs/util.ts
|
|
20
70
|
const FORMAT_FUNCTION_NAMES = /* @__PURE__ */ new Set([
|
|
21
71
|
"$formatMessage",
|
|
@@ -220,11 +270,530 @@ function patchMessage(messageNode, ast, patcher) {
|
|
|
220
270
|
return null;
|
|
221
271
|
}
|
|
222
272
|
//#endregion
|
|
273
|
+
//#region packages/eslint-plugin-formatjs/placeholder-checks.ts
|
|
274
|
+
function messageIgnoreTag(context, node) {
|
|
275
|
+
let ignoreTag = getSettings(context).ignoreTag ?? false;
|
|
276
|
+
if (node.type !== "CallExpression" || !node.arguments[2]) return ignoreTag;
|
|
277
|
+
const options = node.arguments[2];
|
|
278
|
+
if (options.type !== "ObjectExpression") return;
|
|
279
|
+
for (const property of options.properties) {
|
|
280
|
+
if (property.type !== "Property" || property.computed || property.method || property.kind !== "init") return;
|
|
281
|
+
if ((property.key.type === "Identifier" ? property.key.name : property.key.type === "Literal" ? property.key.value : void 0) !== "ignoreTag") continue;
|
|
282
|
+
if (property.value.type !== "Literal" || typeof property.value.value !== "boolean") return;
|
|
283
|
+
ignoreTag = property.value.value;
|
|
284
|
+
}
|
|
285
|
+
return ignoreTag;
|
|
286
|
+
}
|
|
287
|
+
function checkPlaceholders(context, node) {
|
|
288
|
+
const settings = getSettings(context);
|
|
289
|
+
const ignoreTag = messageIgnoreTag(context, node);
|
|
290
|
+
if (ignoreTag === void 0) return;
|
|
291
|
+
const msgs = extractMessages(node, {
|
|
292
|
+
excludeMessageDeclCalls: true,
|
|
293
|
+
...settings
|
|
294
|
+
});
|
|
295
|
+
const { options: [opt] } = context;
|
|
296
|
+
const ignoreList = new Set(opt?.ignoreList || []);
|
|
297
|
+
for (const [{ message: { defaultMessage }, messageNode }, values] of msgs) {
|
|
298
|
+
if (!defaultMessage || !messageNode) continue;
|
|
299
|
+
if (values && values.type !== "ObjectExpression") continue;
|
|
300
|
+
if (values?.properties.find((prop) => prop.type === "SpreadElement")) continue;
|
|
301
|
+
const literalElementByLiteralKey = /* @__PURE__ */ new Map();
|
|
302
|
+
if (values) {
|
|
303
|
+
for (const prop of values.properties) if (prop.type === "Property" && !prop.computed) {
|
|
304
|
+
const name = prop.key.type === "Identifier" ? prop.key.name : String(prop.key.value);
|
|
305
|
+
literalElementByLiteralKey.set(name, prop);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
let ast;
|
|
309
|
+
try {
|
|
310
|
+
ast = parse(defaultMessage, { ignoreTag });
|
|
311
|
+
} catch (e) {
|
|
312
|
+
context.report({
|
|
313
|
+
node: messageNode,
|
|
314
|
+
messageId: "parseError",
|
|
315
|
+
data: { error: e instanceof Error ? e.message : String(e) }
|
|
316
|
+
});
|
|
317
|
+
continue;
|
|
318
|
+
}
|
|
319
|
+
const placeholderNames = new Set(collectMessageArguments(ast).keys());
|
|
320
|
+
const missingPlaceholders = [];
|
|
321
|
+
placeholderNames.forEach((name) => {
|
|
322
|
+
if (!ignoreList.has(name) && !literalElementByLiteralKey.has(name)) missingPlaceholders.push(name);
|
|
323
|
+
});
|
|
324
|
+
if (missingPlaceholders.length > 0) context.report({
|
|
325
|
+
node: messageNode,
|
|
326
|
+
messageId: "missingValue",
|
|
327
|
+
data: { list: missingPlaceholders.join(", ") }
|
|
328
|
+
});
|
|
329
|
+
literalElementByLiteralKey.forEach((element, key) => {
|
|
330
|
+
if (!ignoreList.has(key) && !placeholderNames.has(key)) context.report({
|
|
331
|
+
node: element,
|
|
332
|
+
messageId: "unusedValue"
|
|
333
|
+
});
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
//#endregion
|
|
223
338
|
//#region packages/eslint-plugin-formatjs/messages.ts
|
|
224
339
|
const CORE_MESSAGES = { parseError: `Failed to parse message string {{error}}` };
|
|
225
340
|
//#endregion
|
|
341
|
+
//#region packages/eslint-plugin-formatjs/rules/enforce-placeholders.ts
|
|
342
|
+
const name$23 = "enforce-placeholders";
|
|
343
|
+
const rule$21 = {
|
|
344
|
+
meta: {
|
|
345
|
+
type: "problem",
|
|
346
|
+
docs: {
|
|
347
|
+
description: "Enforce that all messages with placeholders have enough passed-in values",
|
|
348
|
+
url: "https://formatjs.github.io/docs/tooling/linter#enforce-placeholders"
|
|
349
|
+
},
|
|
350
|
+
schema: [{
|
|
351
|
+
type: "object",
|
|
352
|
+
properties: { ignoreList: {
|
|
353
|
+
type: "array",
|
|
354
|
+
items: { type: "string" }
|
|
355
|
+
} },
|
|
356
|
+
additionalProperties: false
|
|
357
|
+
}],
|
|
358
|
+
messages: {
|
|
359
|
+
...CORE_MESSAGES,
|
|
360
|
+
missingValue: "Missing value(s) for the following placeholder(s): {{list}}.",
|
|
361
|
+
unusedValue: "Value not used by the message."
|
|
362
|
+
}
|
|
363
|
+
},
|
|
364
|
+
create(context) {
|
|
365
|
+
const callExpressionVisitor = (node) => checkPlaceholders(context, node);
|
|
366
|
+
const parserServices = context.sourceCode.parserServices;
|
|
367
|
+
if (parserServices?.defineTemplateBodyVisitor) return parserServices.defineTemplateBodyVisitor({ CallExpression: callExpressionVisitor }, { CallExpression: callExpressionVisitor });
|
|
368
|
+
return {
|
|
369
|
+
JSXOpeningElement: (node) => checkPlaceholders(context, node),
|
|
370
|
+
CallExpression: callExpressionVisitor
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
};
|
|
374
|
+
//#endregion
|
|
375
|
+
//#region packages/eslint-plugin-formatjs/rules/enforce-message-types.ts
|
|
376
|
+
const name$22 = "enforce-message-types";
|
|
377
|
+
const modules = /* @__PURE__ */ new Set([
|
|
378
|
+
"@formatjs/intl",
|
|
379
|
+
"react-intl",
|
|
380
|
+
"react-intl/server",
|
|
381
|
+
"intl-messageformat"
|
|
382
|
+
]);
|
|
383
|
+
function staticObject(node) {
|
|
384
|
+
return node?.type === "ObjectExpression" && node.properties.every((property) => property.type === "Property" && !property.computed && property.kind === "init" && !property.method);
|
|
385
|
+
}
|
|
386
|
+
function staticMessage(node) {
|
|
387
|
+
if (!node) return false;
|
|
388
|
+
if (node.type === "Literal") return typeof node.value === "string";
|
|
389
|
+
if (node.type === "TemplateLiteral") return node.expressions.length === 0;
|
|
390
|
+
if (node.type === "BinaryExpression") return node.operator === "+" && staticMessage(node.left) && staticMessage(node.right);
|
|
391
|
+
const wrapper = node;
|
|
392
|
+
if ([
|
|
393
|
+
"TSAsExpression",
|
|
394
|
+
"TSSatisfiesExpression",
|
|
395
|
+
"TSNonNullExpression",
|
|
396
|
+
"TSTypeAssertion"
|
|
397
|
+
].includes(wrapper.type)) return staticMessage(wrapper.expression);
|
|
398
|
+
return false;
|
|
399
|
+
}
|
|
400
|
+
function importedHelper(context, node) {
|
|
401
|
+
const callee = node.callee;
|
|
402
|
+
const identifier = callee.type === "Identifier" ? callee : callee.type === "MemberExpression" && !callee.computed && callee.object.type === "Identifier" ? callee.object : void 0;
|
|
403
|
+
if (!identifier) return;
|
|
404
|
+
let scope = context.sourceCode.getScope(node);
|
|
405
|
+
while (scope) {
|
|
406
|
+
const variable = scope.set.get(identifier.name);
|
|
407
|
+
if (variable) {
|
|
408
|
+
const definition = variable.defs[0];
|
|
409
|
+
if (definition?.type !== "ImportBinding") return;
|
|
410
|
+
const module = definition.parent.source.value;
|
|
411
|
+
if (typeof module !== "string" || !modules.has(module)) return;
|
|
412
|
+
const specifier = definition.node;
|
|
413
|
+
let helper;
|
|
414
|
+
if (callee.type === "Identifier" && specifier.type === "ImportSpecifier") helper = specifier.imported.type === "Identifier" ? specifier.imported.name : String(specifier.imported.value);
|
|
415
|
+
else if (callee.type === "MemberExpression" && callee.property.type === "Identifier" && specifier.type === "ImportNamespaceSpecifier") helper = callee.property.name;
|
|
416
|
+
if (node.type === "NewExpression" && module === "intl-messageformat") {
|
|
417
|
+
if (callee.type === "Identifier" && specifier.type === "ImportDefaultSpecifier" || helper === "IntlMessageFormat" || helper === "default") return {
|
|
418
|
+
module,
|
|
419
|
+
helper: "IntlMessageFormat"
|
|
420
|
+
};
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
423
|
+
if (module === "intl-messageformat") return;
|
|
424
|
+
if (helper === "defineMessage" || helper === "defineMessages") return {
|
|
425
|
+
module,
|
|
426
|
+
helper
|
|
427
|
+
};
|
|
428
|
+
return;
|
|
429
|
+
}
|
|
430
|
+
scope = scope.upper;
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
function staticString(node) {
|
|
434
|
+
if (!node) return;
|
|
435
|
+
if (node.type === "Literal") return typeof node.value === "string" ? node.value : void 0;
|
|
436
|
+
if (node.type === "TemplateLiteral" && node.expressions.length === 0) return node.quasis[0].value.cooked ?? void 0;
|
|
437
|
+
if (node.type === "BinaryExpression" && node.operator === "+") {
|
|
438
|
+
const left = staticString(node.left);
|
|
439
|
+
const right = staticString(node.right);
|
|
440
|
+
if (left !== void 0 && right !== void 0) return left + right;
|
|
441
|
+
}
|
|
442
|
+
const wrapper = node;
|
|
443
|
+
if ([
|
|
444
|
+
"TSAsExpression",
|
|
445
|
+
"TSSatisfiesExpression",
|
|
446
|
+
"TSNonNullExpression",
|
|
447
|
+
"TSTypeAssertion"
|
|
448
|
+
].includes(wrapper.type)) return staticString(wrapper.expression);
|
|
449
|
+
}
|
|
450
|
+
function renderType(node) {
|
|
451
|
+
if (!node) return;
|
|
452
|
+
const keywords = {
|
|
453
|
+
TSNumberKeyword: "number",
|
|
454
|
+
TSBigIntKeyword: "bigint",
|
|
455
|
+
TSStringKeyword: "string"
|
|
456
|
+
};
|
|
457
|
+
if (keywords[node.type]) return keywords[node.type];
|
|
458
|
+
if (node.type === "TSTypeReference" && node.typeName?.type === "Identifier") return node.typeName.name;
|
|
459
|
+
if (node.type === "TSUnionType") {
|
|
460
|
+
const types = node.types?.map(renderType);
|
|
461
|
+
if (types?.every((type) => type !== void 0)) return types.join(" | ");
|
|
462
|
+
}
|
|
463
|
+
if (node.type === "TSImportType" && node.qualifier?.type === "Identifier") {
|
|
464
|
+
const module = node.source?.value ?? node.argument?.literal?.value ?? node.argument?.value;
|
|
465
|
+
if (typeof module === "string") return `import(${JSON.stringify(module)}).${node.qualifier.name}`;
|
|
466
|
+
}
|
|
467
|
+
if (node.type === "TSTypeLiteral" && node.members) {
|
|
468
|
+
const fields = [];
|
|
469
|
+
for (const member of node.members) {
|
|
470
|
+
if (member.type !== "TSPropertySignature" || member.readonly || member.computed) return;
|
|
471
|
+
const key = member.key?.type === "Identifier" ? member.key.name : member.key?.value;
|
|
472
|
+
const type = renderType(member.typeAnnotation?.typeAnnotation);
|
|
473
|
+
if (key === void 0 || type === void 0) return;
|
|
474
|
+
fields.push(`${JSON.stringify(String(key))}${member.optional ? "?" : ""}: ${type}`);
|
|
475
|
+
}
|
|
476
|
+
return fields.length ? `{ ${fields.join("; ")} }` : "{}";
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
function hoistTypes(context, node, contract) {
|
|
480
|
+
const source = context.sourceCode;
|
|
481
|
+
const imports = /* @__PURE__ */ new Map();
|
|
482
|
+
const occupied = new Set(source.scopeManager?.scopes.flatMap((scope) => scope.variables.map((variable) => variable.name)));
|
|
483
|
+
const resolved = /* @__PURE__ */ new Map();
|
|
484
|
+
return {
|
|
485
|
+
text: contract.replace(/import\(("(?:[^"\\]|\\.)*")\)\.(MessageTag|MessageValue)/g, (reference, quotedModule, imported) => {
|
|
486
|
+
if (resolved.has(reference)) return resolved.get(reference);
|
|
487
|
+
const module = JSON.parse(quotedModule);
|
|
488
|
+
for (const declaration of source.ast.body) {
|
|
489
|
+
if (declaration.type !== "ImportDeclaration" || declaration.source.value !== module) continue;
|
|
490
|
+
for (const specifier of declaration.specifiers) {
|
|
491
|
+
if (specifier.type !== "ImportSpecifier") continue;
|
|
492
|
+
if ((specifier.imported.type === "Identifier" ? specifier.imported.name : specifier.imported.value) !== imported) continue;
|
|
493
|
+
let scope = source.getScope(node);
|
|
494
|
+
while (scope && !scope.set.has(specifier.local.name)) scope = scope.upper;
|
|
495
|
+
if (scope?.set.get(specifier.local.name)?.defs.some((def) => def.node === specifier)) {
|
|
496
|
+
resolved.set(reference, specifier.local.name);
|
|
497
|
+
return specifier.local.name;
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
let local = imported;
|
|
502
|
+
for (let suffix = 1; occupied.has(local); suffix++) local = imported + suffix;
|
|
503
|
+
occupied.add(local);
|
|
504
|
+
const specifiers = imports.get(quotedModule) ?? [];
|
|
505
|
+
specifiers.push(imported + (local === imported ? "" : " as " + local));
|
|
506
|
+
imports.set(quotedModule, specifiers);
|
|
507
|
+
resolved.set(reference, local);
|
|
508
|
+
return local;
|
|
509
|
+
}),
|
|
510
|
+
fix(fixer) {
|
|
511
|
+
if (!imports.size) return [];
|
|
512
|
+
let anchor = source.ast.body.filter((statement) => statement.type === "ImportDeclaration").at(-1);
|
|
513
|
+
if (!anchor) for (const statement of source.ast.body) {
|
|
514
|
+
if (statement.type !== "ExpressionStatement" || statement.expression.type !== "Literal" || typeof statement.expression.value !== "string") break;
|
|
515
|
+
anchor = statement;
|
|
516
|
+
}
|
|
517
|
+
const block = [...imports].map(([module, specifiers]) => "import type {" + specifiers.join(", ") + "} from " + module + ";").join("\n");
|
|
518
|
+
return anchor ? [fixer.insertTextAfter(anchor, "\n" + block)] : [fixer.insertTextBefore(source.ast.body[0], block + "\n")];
|
|
519
|
+
}
|
|
520
|
+
};
|
|
521
|
+
}
|
|
522
|
+
const descriptorModules = /* @__PURE__ */ new Set([
|
|
523
|
+
"@formatjs/intl",
|
|
524
|
+
"react-intl",
|
|
525
|
+
"react-intl/server"
|
|
526
|
+
]);
|
|
527
|
+
function checkInlineMessage(context, node) {
|
|
528
|
+
if (node.type !== "CallExpression") return;
|
|
529
|
+
const settings = getSettings(context);
|
|
530
|
+
if (node.callee.type === "MemberExpression" && node.callee.computed) return;
|
|
531
|
+
if (!isIntlFormatMessageCall({
|
|
532
|
+
...node,
|
|
533
|
+
arguments: [{
|
|
534
|
+
type: "ObjectExpression",
|
|
535
|
+
properties: []
|
|
536
|
+
}]
|
|
537
|
+
}, settings.additionalFunctionNames)) return;
|
|
538
|
+
const source = context.sourceCode;
|
|
539
|
+
const call = node;
|
|
540
|
+
const generic = call.typeArguments ?? call.typeParameters;
|
|
541
|
+
if (!generic && !context.options[0]?.generateTypes) return;
|
|
542
|
+
const generated = !!generic && /^<\s*\/\* @formatjs-generated \*\//.test(source.getText(generic));
|
|
543
|
+
const descriptor = node.arguments[0];
|
|
544
|
+
if (!staticObject(descriptor)) {
|
|
545
|
+
if (generic) context.report({
|
|
546
|
+
node,
|
|
547
|
+
messageId: "dynamic"
|
|
548
|
+
});
|
|
549
|
+
return;
|
|
550
|
+
}
|
|
551
|
+
const existingModule = source.ast.body.find((statement) => statement.type === "ImportDeclaration" && typeof statement.source.value === "string" && descriptorModules.has(statement.source.value));
|
|
552
|
+
const module = context.options[0]?.moduleSource ?? (existingModule?.type === "ImportDeclaration" ? String(existingModule.source.value) : "@formatjs/intl");
|
|
553
|
+
const ignoreTag = messageIgnoreTag(context, node);
|
|
554
|
+
if (ignoreTag === void 0) {
|
|
555
|
+
if (generic) context.report({
|
|
556
|
+
node,
|
|
557
|
+
messageId: "dynamic"
|
|
558
|
+
});
|
|
559
|
+
return !!generic;
|
|
560
|
+
}
|
|
561
|
+
const messages = extractMessages(node, settings);
|
|
562
|
+
const message = messages[0]?.[0];
|
|
563
|
+
if (messages.length !== 1 || !message || typeof message.message.defaultMessage !== "string" || !staticMessage(message.messageNode ?? void 0)) {
|
|
564
|
+
if (generic) context.report({
|
|
565
|
+
node,
|
|
566
|
+
messageId: "dynamic"
|
|
567
|
+
});
|
|
568
|
+
return;
|
|
569
|
+
}
|
|
570
|
+
let contract;
|
|
571
|
+
try {
|
|
572
|
+
contract = messageTypes(parse(message.message.defaultMessage, { ignoreTag }), module, context.options[0]?.ignoreList);
|
|
573
|
+
} catch (error) {
|
|
574
|
+
context.report({
|
|
575
|
+
node,
|
|
576
|
+
messageId: "invalid",
|
|
577
|
+
data: { error: error instanceof Error ? error.message : String(error) }
|
|
578
|
+
});
|
|
579
|
+
return true;
|
|
580
|
+
}
|
|
581
|
+
const imports = hoistTypes(context, node, contract);
|
|
582
|
+
contract = imports.text;
|
|
583
|
+
const parameters = generic?.params;
|
|
584
|
+
if (parameters && parameters.length >= 1 && parameters.length <= 2 && renderType(parameters[0]) === contract && !generated) return true;
|
|
585
|
+
if (generic && (!parameters || parameters.length > 2)) {
|
|
586
|
+
context.report({
|
|
587
|
+
node: generic,
|
|
588
|
+
messageId: "manual"
|
|
589
|
+
});
|
|
590
|
+
return true;
|
|
591
|
+
}
|
|
592
|
+
context.report({
|
|
593
|
+
node,
|
|
594
|
+
messageId: "contract",
|
|
595
|
+
fix(fixer) {
|
|
596
|
+
return [...imports.fix(fixer), generic && parameters?.[0] ? fixer.replaceTextRange([generic.range[0] + 1, parameters[0].range[1]], contract) : fixer.insertTextAfter(node.optional ? source.getTokenAfter(node.callee) : node.callee, "<" + contract + ">")];
|
|
597
|
+
}
|
|
598
|
+
});
|
|
599
|
+
return true;
|
|
600
|
+
}
|
|
601
|
+
const rule$20 = {
|
|
602
|
+
meta: {
|
|
603
|
+
type: "problem",
|
|
604
|
+
docs: { description: "Check ICU placeholders and optionally generate TypeScript argument contracts" },
|
|
605
|
+
fixable: "code",
|
|
606
|
+
schema: [{
|
|
607
|
+
type: "object",
|
|
608
|
+
properties: {
|
|
609
|
+
generateTypes: { type: "boolean" },
|
|
610
|
+
ignoreList: {
|
|
611
|
+
type: "array",
|
|
612
|
+
items: { type: "string" }
|
|
613
|
+
},
|
|
614
|
+
moduleSource: {
|
|
615
|
+
type: "string",
|
|
616
|
+
enum: [...descriptorModules]
|
|
617
|
+
}
|
|
618
|
+
},
|
|
619
|
+
additionalProperties: false
|
|
620
|
+
}],
|
|
621
|
+
messages: {
|
|
622
|
+
...rule$21.meta.messages,
|
|
623
|
+
contract: "Generate or refresh the ICU argument contract.",
|
|
624
|
+
invalid: "Cannot generate message types: {{error}}.",
|
|
625
|
+
manual: "Unsupported number of generic arguments; update the call manually.",
|
|
626
|
+
dynamic: "Typed messages require static message strings and parser options for contract verification."
|
|
627
|
+
}
|
|
628
|
+
},
|
|
629
|
+
create(context) {
|
|
630
|
+
const listeners = {
|
|
631
|
+
JSXOpeningElement(node) {
|
|
632
|
+
checkPlaceholders(context, node);
|
|
633
|
+
},
|
|
634
|
+
NewExpression(node) {
|
|
635
|
+
if (node.type !== "NewExpression" || !/\.[cm]?tsx?$/.test(context.filename)) return;
|
|
636
|
+
const imported = importedHelper(context, node);
|
|
637
|
+
if (imported?.helper !== "IntlMessageFormat") return;
|
|
638
|
+
const source = context.sourceCode;
|
|
639
|
+
const call = node;
|
|
640
|
+
const generic = call.typeArguments ?? call.typeParameters;
|
|
641
|
+
if (!generic && !context.options[0]?.generateTypes) return;
|
|
642
|
+
const generated = !!generic && /^<\s*\/\* @formatjs-generated \*\//.test(source.getText(generic));
|
|
643
|
+
const message = staticString(node.arguments[0]);
|
|
644
|
+
const options = node.arguments[3];
|
|
645
|
+
let ignoreTag = false;
|
|
646
|
+
if (message === void 0 || node.arguments.some((argument) => argument.type === "SpreadElement") || options && !staticObject(options)) {
|
|
647
|
+
if (generic) context.report({
|
|
648
|
+
node,
|
|
649
|
+
messageId: "dynamic"
|
|
650
|
+
});
|
|
651
|
+
return;
|
|
652
|
+
}
|
|
653
|
+
if (staticObject(options)) for (const property of options.properties) {
|
|
654
|
+
if (property.type !== "Property") continue;
|
|
655
|
+
if ((property.key.type === "Identifier" ? property.key.name : property.key.type === "Literal" ? property.key.value : void 0) !== "ignoreTag") continue;
|
|
656
|
+
if (property.value.type !== "Literal" || typeof property.value.value !== "boolean") {
|
|
657
|
+
if (generic) context.report({
|
|
658
|
+
node,
|
|
659
|
+
messageId: "dynamic"
|
|
660
|
+
});
|
|
661
|
+
return;
|
|
662
|
+
}
|
|
663
|
+
ignoreTag = property.value.value;
|
|
664
|
+
}
|
|
665
|
+
let contract;
|
|
666
|
+
try {
|
|
667
|
+
contract = messageTypes(parse(message, { ignoreTag }), imported.module, context.options[0]?.ignoreList);
|
|
668
|
+
} catch (error) {
|
|
669
|
+
context.report({
|
|
670
|
+
node,
|
|
671
|
+
messageId: "invalid",
|
|
672
|
+
data: { error: error instanceof Error ? error.message : String(error) }
|
|
673
|
+
});
|
|
674
|
+
return;
|
|
675
|
+
}
|
|
676
|
+
const imports = hoistTypes(context, node, contract);
|
|
677
|
+
contract = imports.text;
|
|
678
|
+
const parameters = generic?.params;
|
|
679
|
+
if (parameters?.length === 1 && renderType(parameters[0]) === contract && !generated) return;
|
|
680
|
+
if (generic && parameters?.length !== 1) {
|
|
681
|
+
context.report({
|
|
682
|
+
node: generic,
|
|
683
|
+
messageId: "manual"
|
|
684
|
+
});
|
|
685
|
+
return;
|
|
686
|
+
}
|
|
687
|
+
context.report({
|
|
688
|
+
node,
|
|
689
|
+
messageId: "contract",
|
|
690
|
+
fix(fixer) {
|
|
691
|
+
const expected = `<${contract}>`;
|
|
692
|
+
return [...imports.fix(fixer), generic ? fixer.replaceText(generic, expected) : fixer.insertTextAfter(node.callee, expected)];
|
|
693
|
+
}
|
|
694
|
+
});
|
|
695
|
+
},
|
|
696
|
+
CallExpression(node) {
|
|
697
|
+
if (node.type !== "CallExpression") return;
|
|
698
|
+
if (!/\.[cm]?tsx?$/.test(context.filename)) {
|
|
699
|
+
checkPlaceholders(context, node);
|
|
700
|
+
return;
|
|
701
|
+
}
|
|
702
|
+
const imported = importedHelper(context, node);
|
|
703
|
+
if (!imported) {
|
|
704
|
+
if (!checkInlineMessage(context, node)) checkPlaceholders(context, node);
|
|
705
|
+
return;
|
|
706
|
+
}
|
|
707
|
+
const source = context.sourceCode;
|
|
708
|
+
const call = node;
|
|
709
|
+
const generic = call.typeArguments ?? call.typeParameters;
|
|
710
|
+
const generated = !!generic && /^<\s*\/\* @formatjs-generated \*\//.test(source.getText(generic));
|
|
711
|
+
const options = node.arguments[1];
|
|
712
|
+
const typed = staticObject(options) && options.properties.length === 1 && options.properties.some((p) => p.type === "Property" && (p.key.type === "Identifier" ? p.key.name : p.key.type === "Literal" ? p.key.value : void 0) === "typed" && p.value.type === "Literal" && p.value.value === true);
|
|
713
|
+
if (!typed && !generated && !context.options[0]?.generateTypes) return;
|
|
714
|
+
if (!typed && generic && !generated && !context.options[0]?.generateTypes) return;
|
|
715
|
+
if (node.arguments.length > 2 || options && !typed) return;
|
|
716
|
+
const descriptor = node.arguments[0];
|
|
717
|
+
if (!staticObject(descriptor)) {
|
|
718
|
+
if (typed || generated) context.report({
|
|
719
|
+
node,
|
|
720
|
+
messageId: "dynamic"
|
|
721
|
+
});
|
|
722
|
+
return;
|
|
723
|
+
}
|
|
724
|
+
if (imported.helper === "defineMessages" && !descriptor.properties.every((p) => p.type === "Property" && staticObject(p.value))) {
|
|
725
|
+
if (typed || generated) context.report({
|
|
726
|
+
node,
|
|
727
|
+
messageId: "dynamic"
|
|
728
|
+
});
|
|
729
|
+
return;
|
|
730
|
+
}
|
|
731
|
+
const messages = extractMessages({
|
|
732
|
+
...node,
|
|
733
|
+
callee: {
|
|
734
|
+
type: "Identifier",
|
|
735
|
+
name: imported.helper
|
|
736
|
+
}
|
|
737
|
+
}, getSettings(context));
|
|
738
|
+
if (messages.some(([message]) => typeof message.message.defaultMessage !== "string" || !staticMessage(message.messageNode ?? void 0)) || messages.length !== (imported.helper === "defineMessage" ? 1 : descriptor.properties.length)) {
|
|
739
|
+
if (typed || generated) context.report({
|
|
740
|
+
node,
|
|
741
|
+
messageId: "dynamic"
|
|
742
|
+
});
|
|
743
|
+
return;
|
|
744
|
+
}
|
|
745
|
+
let contract;
|
|
746
|
+
try {
|
|
747
|
+
const types = messages.map(([message]) => messageTypes(parse(message.message.defaultMessage, { ignoreTag: getSettings(context).ignoreTag }), imported.module, context.options[0]?.ignoreList));
|
|
748
|
+
contract = imported.helper === "defineMessage" ? types[0] : descriptor.properties.length === 0 ? "{}" : `{ ${descriptor.properties.map((p, i) => {
|
|
749
|
+
if (p.type !== "Property") throw new Error("Unexpected spread");
|
|
750
|
+
const key = p.key.type === "Identifier" ? p.key.name : p.key.type === "Literal" ? String(p.key.value) : void 0;
|
|
751
|
+
if (key === void 0) throw new Error("Unsupported catalog key");
|
|
752
|
+
return `${JSON.stringify(key)}: ${types[i]}`;
|
|
753
|
+
}).join("; ")} }`;
|
|
754
|
+
} catch (error) {
|
|
755
|
+
context.report({
|
|
756
|
+
node,
|
|
757
|
+
messageId: "invalid",
|
|
758
|
+
data: { error: error instanceof Error ? error.message : String(error) }
|
|
759
|
+
});
|
|
760
|
+
return;
|
|
761
|
+
}
|
|
762
|
+
const imports = hoistTypes(context, node, contract);
|
|
763
|
+
contract = imports.text;
|
|
764
|
+
const expected = `<${contract}>`;
|
|
765
|
+
const parameters = generic?.params;
|
|
766
|
+
if (parameters?.length === 1 && renderType(parameters[0]) === contract && typed && !generated) return;
|
|
767
|
+
if (generic && parameters?.length !== 1) {
|
|
768
|
+
context.report({
|
|
769
|
+
node: generic,
|
|
770
|
+
messageId: "manual"
|
|
771
|
+
});
|
|
772
|
+
return;
|
|
773
|
+
}
|
|
774
|
+
context.report({
|
|
775
|
+
node,
|
|
776
|
+
messageId: "contract",
|
|
777
|
+
fix(fixer) {
|
|
778
|
+
const edits = [...imports.fix(fixer), generic ? fixer.replaceText(generic, expected) : fixer.insertTextAfter(node.optional ? source.getTokenAfter(node.callee) : node.callee, expected)];
|
|
779
|
+
if (!typed) {
|
|
780
|
+
const close = source.getLastToken(node);
|
|
781
|
+
const previous = source.getTokenBefore(close);
|
|
782
|
+
edits.push(fixer.insertTextBefore(close, `${previous.value === "," ? "" : ","} {typed: true}`));
|
|
783
|
+
}
|
|
784
|
+
return edits;
|
|
785
|
+
}
|
|
786
|
+
});
|
|
787
|
+
}
|
|
788
|
+
};
|
|
789
|
+
const parserServices = context.sourceCode.parserServices;
|
|
790
|
+
if (parserServices?.defineTemplateBodyVisitor) return parserServices.defineTemplateBodyVisitor({ CallExpression: listeners.CallExpression }, { CallExpression: listeners.CallExpression });
|
|
791
|
+
return listeners;
|
|
792
|
+
}
|
|
793
|
+
};
|
|
794
|
+
//#endregion
|
|
226
795
|
//#region packages/eslint-plugin-formatjs/rules/blocklist-elements.ts
|
|
227
|
-
const name$
|
|
796
|
+
const name$21 = "blocklist-elements";
|
|
228
797
|
function getMessage(type) {
|
|
229
798
|
return {
|
|
230
799
|
messageId: "blocklist",
|
|
@@ -277,7 +846,7 @@ function verifyAst$7(blocklist, ast) {
|
|
|
277
846
|
}
|
|
278
847
|
return errors;
|
|
279
848
|
}
|
|
280
|
-
function checkNode$
|
|
849
|
+
function checkNode$16(context, node) {
|
|
281
850
|
const settings = getSettings(context);
|
|
282
851
|
const msgs = extractMessages(node, settings);
|
|
283
852
|
if (!msgs.length) return;
|
|
@@ -303,7 +872,7 @@ function checkNode$17(context, node) {
|
|
|
303
872
|
});
|
|
304
873
|
}
|
|
305
874
|
}
|
|
306
|
-
const rule$
|
|
875
|
+
const rule$19 = {
|
|
307
876
|
meta: {
|
|
308
877
|
type: "problem",
|
|
309
878
|
docs: {
|
|
@@ -347,11 +916,11 @@ const rule$20 = {
|
|
|
347
916
|
}
|
|
348
917
|
},
|
|
349
918
|
create(context) {
|
|
350
|
-
const callExpressionVisitor = (node) => checkNode$
|
|
919
|
+
const callExpressionVisitor = (node) => checkNode$16(context, node);
|
|
351
920
|
const parserServices = context.sourceCode.parserServices;
|
|
352
921
|
if (parserServices?.defineTemplateBodyVisitor) return parserServices.defineTemplateBodyVisitor({ CallExpression: callExpressionVisitor }, { CallExpression: callExpressionVisitor });
|
|
353
922
|
return {
|
|
354
|
-
JSXOpeningElement: (node) => checkNode$
|
|
923
|
+
JSXOpeningElement: (node) => checkNode$16(context, node),
|
|
355
924
|
CallExpression: callExpressionVisitor
|
|
356
925
|
};
|
|
357
926
|
}
|
|
@@ -363,8 +932,8 @@ let Option$1 = /* @__PURE__ */ function(Option) {
|
|
|
363
932
|
Option["anything"] = "anything";
|
|
364
933
|
return Option;
|
|
365
934
|
}({});
|
|
366
|
-
const name$
|
|
367
|
-
function checkNode$
|
|
935
|
+
const name$20 = "enforce-default-message";
|
|
936
|
+
function checkNode$15(context, node) {
|
|
368
937
|
const msgs = extractMessages(node, getSettings(context));
|
|
369
938
|
const { options: [type] } = context;
|
|
370
939
|
for (const [{ message: { defaultMessage }, messageNode, messageDescriptorNode }] of msgs) if (!defaultMessage) {
|
|
@@ -378,7 +947,7 @@ function checkNode$16(context, node) {
|
|
|
378
947
|
});
|
|
379
948
|
}
|
|
380
949
|
}
|
|
381
|
-
const rule$
|
|
950
|
+
const rule$18 = {
|
|
382
951
|
meta: {
|
|
383
952
|
type: "problem",
|
|
384
953
|
docs: {
|
|
@@ -398,11 +967,11 @@ const rule$19 = {
|
|
|
398
967
|
}
|
|
399
968
|
},
|
|
400
969
|
create(context) {
|
|
401
|
-
const callExpressionVisitor = (node) => checkNode$
|
|
970
|
+
const callExpressionVisitor = (node) => checkNode$15(context, node);
|
|
402
971
|
const parserServices = context.sourceCode.parserServices;
|
|
403
972
|
if (parserServices?.defineTemplateBodyVisitor) return parserServices.defineTemplateBodyVisitor({ CallExpression: callExpressionVisitor }, { CallExpression: callExpressionVisitor });
|
|
404
973
|
return {
|
|
405
|
-
JSXOpeningElement: (node) => checkNode$
|
|
974
|
+
JSXOpeningElement: (node) => checkNode$15(context, node),
|
|
406
975
|
CallExpression: callExpressionVisitor
|
|
407
976
|
};
|
|
408
977
|
}
|
|
@@ -428,7 +997,7 @@ function normalizeOptions(raw) {
|
|
|
428
997
|
minLength: void 0
|
|
429
998
|
};
|
|
430
999
|
}
|
|
431
|
-
function checkNode$
|
|
1000
|
+
function checkNode$14(context, node) {
|
|
432
1001
|
const msgs = extractMessages(node, getSettings(context));
|
|
433
1002
|
const { mode: type, minLength } = normalizeOptions(context.options[0]);
|
|
434
1003
|
for (const [{ message: { description }, descriptionNode, messageDescriptorNode }] of msgs) if (!description) {
|
|
@@ -449,8 +1018,8 @@ function checkNode$15(context, node) {
|
|
|
449
1018
|
}
|
|
450
1019
|
});
|
|
451
1020
|
}
|
|
452
|
-
const name$
|
|
453
|
-
const rule$
|
|
1021
|
+
const name$19 = "enforce-description";
|
|
1022
|
+
const rule$17 = {
|
|
454
1023
|
meta: {
|
|
455
1024
|
type: "problem",
|
|
456
1025
|
docs: {
|
|
@@ -483,18 +1052,18 @@ const rule$18 = {
|
|
|
483
1052
|
}
|
|
484
1053
|
},
|
|
485
1054
|
create(context) {
|
|
486
|
-
const callExpressionVisitor = (node) => checkNode$
|
|
1055
|
+
const callExpressionVisitor = (node) => checkNode$14(context, node);
|
|
487
1056
|
const parserServices = context.sourceCode.parserServices;
|
|
488
1057
|
if (parserServices?.defineTemplateBodyVisitor) return parserServices.defineTemplateBodyVisitor({ CallExpression: callExpressionVisitor }, { CallExpression: callExpressionVisitor });
|
|
489
1058
|
return {
|
|
490
|
-
JSXOpeningElement: (node) => checkNode$
|
|
1059
|
+
JSXOpeningElement: (node) => checkNode$14(context, node),
|
|
491
1060
|
CallExpression: callExpressionVisitor
|
|
492
1061
|
};
|
|
493
1062
|
}
|
|
494
1063
|
};
|
|
495
1064
|
//#endregion
|
|
496
1065
|
//#region packages/eslint-plugin-formatjs/rules/enforce-id.ts
|
|
497
|
-
function checkNode$
|
|
1066
|
+
function checkNode$13(context, node, { idInterpolationPattern, idWhitelistRegexps, quoteStyle }) {
|
|
498
1067
|
const msgs = extractMessages(node, getSettings(context));
|
|
499
1068
|
for (const [{ message: { defaultMessage, description, id }, idPropNode, descriptionNode, messagePropNode, messageDescriptorNode }] of msgs) {
|
|
500
1069
|
if (!idInterpolationPattern && !idPropNode) {
|
|
@@ -552,8 +1121,8 @@ function checkNode$14(context, node, { idInterpolationPattern, idWhitelistRegexp
|
|
|
552
1121
|
}
|
|
553
1122
|
}
|
|
554
1123
|
}
|
|
555
|
-
const name$
|
|
556
|
-
const rule$
|
|
1124
|
+
const name$18 = "enforce-id";
|
|
1125
|
+
const rule$16 = {
|
|
557
1126
|
meta: {
|
|
558
1127
|
type: "problem",
|
|
559
1128
|
docs: {
|
|
@@ -604,114 +1173,11 @@ Actual: {{actual}}`
|
|
|
604
1173
|
const { idWhitelist } = tmp;
|
|
605
1174
|
opts.idWhitelistRegexps = idWhitelist.map((str) => new RegExp(str, "i"));
|
|
606
1175
|
}
|
|
607
|
-
const callExpressionVisitor = (node) => checkNode$
|
|
608
|
-
const parserServices = context.sourceCode.parserServices;
|
|
609
|
-
if (parserServices?.defineTemplateBodyVisitor) return parserServices.defineTemplateBodyVisitor({ CallExpression: callExpressionVisitor }, { CallExpression: callExpressionVisitor });
|
|
610
|
-
return {
|
|
611
|
-
JSXOpeningElement: (node) => checkNode$14(context, node, opts),
|
|
612
|
-
CallExpression: callExpressionVisitor
|
|
613
|
-
};
|
|
614
|
-
}
|
|
615
|
-
};
|
|
616
|
-
//#endregion
|
|
617
|
-
//#region packages/eslint-plugin-formatjs/rules/enforce-placeholders.ts
|
|
618
|
-
function collectPlaceholderNames(ast) {
|
|
619
|
-
const placeholderNames = /* @__PURE__ */ new Set();
|
|
620
|
-
_traverse(ast);
|
|
621
|
-
return placeholderNames;
|
|
622
|
-
function _traverse(ast) {
|
|
623
|
-
for (const element of ast) switch (element.type) {
|
|
624
|
-
case TYPE.literal:
|
|
625
|
-
case TYPE.pound: break;
|
|
626
|
-
case TYPE.tag:
|
|
627
|
-
placeholderNames.add(element.value);
|
|
628
|
-
_traverse(element.children);
|
|
629
|
-
break;
|
|
630
|
-
case TYPE.plural:
|
|
631
|
-
case TYPE.select:
|
|
632
|
-
placeholderNames.add(element.value);
|
|
633
|
-
for (const { value } of Object.values(element.options)) _traverse(value);
|
|
634
|
-
break;
|
|
635
|
-
default: placeholderNames.add(element.value);
|
|
636
|
-
}
|
|
637
|
-
}
|
|
638
|
-
}
|
|
639
|
-
function checkNode$13(context, node) {
|
|
640
|
-
const settings = getSettings(context);
|
|
641
|
-
const msgs = extractMessages(node, {
|
|
642
|
-
excludeMessageDeclCalls: true,
|
|
643
|
-
...settings
|
|
644
|
-
});
|
|
645
|
-
const { options: [opt] } = context;
|
|
646
|
-
const ignoreList = new Set(opt?.ignoreList || []);
|
|
647
|
-
for (const [{ message: { defaultMessage }, messageNode }, values] of msgs) {
|
|
648
|
-
if (!defaultMessage || !messageNode) continue;
|
|
649
|
-
if (values && values.type !== "ObjectExpression") continue;
|
|
650
|
-
if (values?.properties.find((prop) => prop.type === "SpreadElement")) continue;
|
|
651
|
-
const literalElementByLiteralKey = /* @__PURE__ */ new Map();
|
|
652
|
-
if (values) {
|
|
653
|
-
for (const prop of values.properties) if (prop.type === "Property" && !prop.computed) {
|
|
654
|
-
const name = prop.key.type === "Identifier" ? prop.key.name : String(prop.key.value);
|
|
655
|
-
literalElementByLiteralKey.set(name, prop);
|
|
656
|
-
}
|
|
657
|
-
}
|
|
658
|
-
let ast;
|
|
659
|
-
try {
|
|
660
|
-
ast = parse(defaultMessage, { ignoreTag: settings.ignoreTag });
|
|
661
|
-
} catch (e) {
|
|
662
|
-
context.report({
|
|
663
|
-
node: messageNode,
|
|
664
|
-
messageId: "parseError",
|
|
665
|
-
data: { error: e instanceof Error ? e.message : String(e) }
|
|
666
|
-
});
|
|
667
|
-
continue;
|
|
668
|
-
}
|
|
669
|
-
const placeholderNames = collectPlaceholderNames(ast);
|
|
670
|
-
const missingPlaceholders = [];
|
|
671
|
-
placeholderNames.forEach((name) => {
|
|
672
|
-
if (!ignoreList.has(name) && !literalElementByLiteralKey.has(name)) missingPlaceholders.push(name);
|
|
673
|
-
});
|
|
674
|
-
if (missingPlaceholders.length > 0) context.report({
|
|
675
|
-
node: messageNode,
|
|
676
|
-
messageId: "missingValue",
|
|
677
|
-
data: { list: missingPlaceholders.join(", ") }
|
|
678
|
-
});
|
|
679
|
-
literalElementByLiteralKey.forEach((element, key) => {
|
|
680
|
-
if (!ignoreList.has(key) && !placeholderNames.has(key)) context.report({
|
|
681
|
-
node: element,
|
|
682
|
-
messageId: "unusedValue"
|
|
683
|
-
});
|
|
684
|
-
});
|
|
685
|
-
}
|
|
686
|
-
}
|
|
687
|
-
const name$18 = "enforce-placeholders";
|
|
688
|
-
const rule$16 = {
|
|
689
|
-
meta: {
|
|
690
|
-
type: "problem",
|
|
691
|
-
docs: {
|
|
692
|
-
description: "Enforce that all messages with placeholders have enough passed-in values",
|
|
693
|
-
url: "https://formatjs.github.io/docs/tooling/linter#enforce-placeholders"
|
|
694
|
-
},
|
|
695
|
-
schema: [{
|
|
696
|
-
type: "object",
|
|
697
|
-
properties: { ignoreList: {
|
|
698
|
-
type: "array",
|
|
699
|
-
items: { type: "string" }
|
|
700
|
-
} },
|
|
701
|
-
additionalProperties: false
|
|
702
|
-
}],
|
|
703
|
-
messages: {
|
|
704
|
-
...CORE_MESSAGES,
|
|
705
|
-
missingValue: "Missing value(s) for the following placeholder(s): {{list}}.",
|
|
706
|
-
unusedValue: "Value not used by the message."
|
|
707
|
-
}
|
|
708
|
-
},
|
|
709
|
-
create(context) {
|
|
710
|
-
const callExpressionVisitor = (node) => checkNode$13(context, node);
|
|
1176
|
+
const callExpressionVisitor = (node) => checkNode$13(context, node, opts);
|
|
711
1177
|
const parserServices = context.sourceCode.parserServices;
|
|
712
1178
|
if (parserServices?.defineTemplateBodyVisitor) return parserServices.defineTemplateBodyVisitor({ CallExpression: callExpressionVisitor }, { CallExpression: callExpressionVisitor });
|
|
713
1179
|
return {
|
|
714
|
-
JSXOpeningElement: (node) => checkNode$13(context, node),
|
|
1180
|
+
JSXOpeningElement: (node) => checkNode$13(context, node, opts),
|
|
715
1181
|
CallExpression: callExpressionVisitor
|
|
716
1182
|
};
|
|
717
1183
|
}
|
|
@@ -4583,7 +5049,7 @@ var package_exports = /* @__PURE__ */ __exportAll({
|
|
|
4583
5049
|
version: () => version$1
|
|
4584
5050
|
});
|
|
4585
5051
|
var name$1 = "eslint-plugin-formatjs";
|
|
4586
|
-
var version$1 = "6.
|
|
5052
|
+
var version$1 = "6.7.0-rc.0";
|
|
4587
5053
|
var description = "ESLint plugin for formatjs";
|
|
4588
5054
|
var keywords = [
|
|
4589
5055
|
"eslint",
|
|
@@ -4644,6 +5110,7 @@ const plugin = {
|
|
|
4644
5110
|
[name$20]: rule$18,
|
|
4645
5111
|
[name$19]: rule$17,
|
|
4646
5112
|
[name$18]: rule$16,
|
|
5113
|
+
[name$23]: rule$21,
|
|
4647
5114
|
[name$17]: rule$15,
|
|
4648
5115
|
[name$16]: rule$14,
|
|
4649
5116
|
[name$15]: rule$13,
|