no-unescaped-entities.js 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. /**
  2. * @fileoverview HTML special characters should be escaped.
  3. * @author Patrick Hayes
  4. */
  5. 'use strict';
  6. const docsUrl = require('../util/docsUrl');
  7. // ------------------------------------------------------------------------------
  8. // Rule Definition
  9. // ------------------------------------------------------------------------------
  10. // NOTE: '<' and '{' are also problematic characters, but they do not need
  11. // to be included here because it is a syntax error when these characters are
  12. // included accidentally.
  13. const DEFAULTS = ['>', '"', '\'', '}'];
  14. module.exports = {
  15. meta: {
  16. docs: {
  17. description: 'Detect unescaped HTML entities, which might represent malformed tags',
  18. category: 'Possible Errors',
  19. recommended: true,
  20. url: docsUrl('no-unescaped-entities')
  21. },
  22. schema: [{
  23. type: 'object',
  24. properties: {
  25. forbid: {
  26. type: 'array',
  27. items: {
  28. type: 'string'
  29. }
  30. }
  31. },
  32. additionalProperties: false
  33. }]
  34. },
  35. create: function(context) {
  36. function reportInvalidEntity(node) {
  37. const configuration = context.options[0] || {};
  38. const entities = configuration.forbid || DEFAULTS;
  39. // HTML entites are already escaped in node.value (as well as node.raw),
  40. // so pull the raw text from context.getSourceCode()
  41. for (let i = node.loc.start.line; i <= node.loc.end.line; i++) {
  42. let rawLine = context.getSourceCode().lines[i - 1];
  43. let start = 0;
  44. let end = rawLine.length;
  45. if (i === node.loc.start.line) {
  46. start = node.loc.start.column;
  47. }
  48. if (i === node.loc.end.line) {
  49. end = node.loc.end.column;
  50. }
  51. rawLine = rawLine.substring(start, end);
  52. for (let j = 0; j < entities.length; j++) {
  53. for (let index = 0; index < rawLine.length; index++) {
  54. const c = rawLine[index];
  55. if (c === entities[j]) {
  56. context.report({
  57. loc: {line: i, column: start + index},
  58. message: 'HTML entities must be escaped.',
  59. node: node
  60. });
  61. }
  62. }
  63. }
  64. }
  65. }
  66. return {
  67. Literal: function(node) {
  68. if (node.parent.type === 'JSXElement') {
  69. reportInvalidEntity(node);
  70. }
  71. },
  72. JSXText: function(node) {
  73. if (node.parent.type === 'JSXElement') {
  74. reportInvalidEntity(node);
  75. }
  76. }
  77. };
  78. }
  79. };