no-new-array.js 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. 'use strict';
  2. const {isParenthesized, getStaticValue} = require('eslint-utils');
  3. const needsSemicolon = require('./utils/needs-semicolon.js');
  4. const {newExpressionSelector} = require('./selectors/index.js');
  5. const MESSAGE_ID_ERROR = 'error';
  6. const MESSAGE_ID_LENGTH = 'array-length';
  7. const MESSAGE_ID_ONLY_ELEMENT = 'only-element';
  8. const MESSAGE_ID_SPREAD = 'spread';
  9. const messages = {
  10. [MESSAGE_ID_ERROR]: 'Do not use `new Array()`.',
  11. [MESSAGE_ID_LENGTH]: 'The argument is the length of array.',
  12. [MESSAGE_ID_ONLY_ELEMENT]: 'The argument is the only element of array.',
  13. [MESSAGE_ID_SPREAD]: 'Spread the argument.',
  14. };
  15. const newArraySelector = newExpressionSelector({
  16. name: 'Array',
  17. argumentsLength: 1,
  18. allowSpreadElement: true,
  19. });
  20. function getProblem(context, node) {
  21. const problem = {
  22. node,
  23. messageId: MESSAGE_ID_ERROR,
  24. };
  25. const [argumentNode] = node.arguments;
  26. const sourceCode = context.getSourceCode();
  27. let text = sourceCode.getText(argumentNode);
  28. if (isParenthesized(argumentNode, sourceCode)) {
  29. text = `(${text})`;
  30. }
  31. const maybeSemiColon = needsSemicolon(sourceCode.getTokenBefore(node), sourceCode, '[')
  32. ? ';'
  33. : '';
  34. // We are not sure how many `arguments` passed
  35. if (argumentNode.type === 'SpreadElement') {
  36. problem.suggest = [
  37. {
  38. messageId: MESSAGE_ID_SPREAD,
  39. fix: fixer => fixer.replaceText(node, `${maybeSemiColon}[${text}]`),
  40. },
  41. ];
  42. return problem;
  43. }
  44. const result = getStaticValue(argumentNode, context.getScope());
  45. const fromLengthText = `Array.from(${text === 'length' ? '{length}' : `{length: ${text}}`})`;
  46. const onlyElementText = `${maybeSemiColon}[${text}]`;
  47. // We don't know the argument is number or not
  48. if (result === null) {
  49. problem.suggest = [
  50. {
  51. messageId: MESSAGE_ID_LENGTH,
  52. fix: fixer => fixer.replaceText(node, fromLengthText),
  53. },
  54. {
  55. messageId: MESSAGE_ID_ONLY_ELEMENT,
  56. fix: fixer => fixer.replaceText(node, onlyElementText),
  57. },
  58. ];
  59. return problem;
  60. }
  61. problem.fix = fixer => fixer.replaceText(
  62. node,
  63. typeof result.value === 'number' ? fromLengthText : onlyElementText,
  64. );
  65. return problem;
  66. }
  67. /** @param {import('eslint').Rule.RuleContext} context */
  68. const create = context => ({
  69. [newArraySelector](node) {
  70. return getProblem(context, node);
  71. },
  72. });
  73. /** @type {import('eslint').Rule.RuleModule} */
  74. module.exports = {
  75. create,
  76. meta: {
  77. type: 'suggestion',
  78. docs: {
  79. description: 'Disallow `new Array()`.',
  80. },
  81. fixable: 'code',
  82. hasSuggestions: true,
  83. messages,
  84. },
  85. };