prefer-formatValues.js 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. /**
  2. * @fileoverview Reject multiple calls to document.l10n.formatValue in the same
  3. * code block.
  4. *
  5. * This Source Code Form is subject to the terms of the Mozilla Public
  6. * License, v. 2.0. If a copy of the MPL was not distributed with this
  7. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  8. */
  9. "use strict";
  10. function isIdentifier(node, id) {
  11. return node && node.type === "Identifier" && node.name === id;
  12. }
  13. /**
  14. * As we enter blocks new sets are pushed onto this stack and then popped when
  15. * we exit the block.
  16. */
  17. const BlockStack = [];
  18. module.exports = {
  19. meta: {
  20. docs: {
  21. description: "disallow multiple document.l10n.formatValue calls",
  22. url:
  23. "https://firefox-source-docs.mozilla.org/code-quality/lint/linters/eslint-plugin-mozilla/prefer-formatValues.html",
  24. },
  25. type: "problem",
  26. },
  27. create(context) {
  28. function enterBlock() {
  29. BlockStack.push(new Set());
  30. }
  31. function exitBlock() {
  32. let calls = BlockStack.pop();
  33. if (calls.size > 1) {
  34. for (let callNode of calls) {
  35. context.report(
  36. callNode,
  37. "prefer to use a single document.l10n.formatValues call instead " +
  38. "of multiple calls to document.l10n.formatValue or document.l10n.formatValues"
  39. );
  40. }
  41. }
  42. }
  43. return {
  44. Program: enterBlock,
  45. "Program:exit": exitBlock,
  46. BlockStatement: enterBlock,
  47. "BlockStatement:exit": exitBlock,
  48. CallExpression(node) {
  49. if (!BlockStack.length) {
  50. context.report(node, "call expression found outside of known block");
  51. }
  52. let callee = node.callee;
  53. if (callee.type !== "MemberExpression") {
  54. return;
  55. }
  56. if (
  57. !isIdentifier(callee.property, "formatValue") &&
  58. !isIdentifier(callee.property, "formatValues")
  59. ) {
  60. return;
  61. }
  62. if (callee.object.type !== "MemberExpression") {
  63. return;
  64. }
  65. if (
  66. !isIdentifier(callee.object.object, "document") ||
  67. !isIdentifier(callee.object.property, "l10n")
  68. ) {
  69. return;
  70. }
  71. let calls = BlockStack[BlockStack.length - 1];
  72. calls.add(node);
  73. },
  74. };
  75. },
  76. };