source: imaps-frontend/node_modules/eslint-plugin-react/lib/rules/jsx-props-no-multi-spaces.js

main
Last change on this file was d565449, checked in by stefan toskovski <stefantoska84@…>, 4 weeks ago

Update repo after prototype presentation

  • Property mode set to 100644
File size: 3.7 KB
RevLine 
[d565449]1/**
2 * @fileoverview Disallow multiple spaces between inline JSX props
3 * @author Adrian Moennich
4 */
5
6'use strict';
7
8const docsUrl = require('../util/docsUrl');
9const eslintUtil = require('../util/eslint');
10const report = require('../util/report');
11
12const getSourceCode = eslintUtil.getSourceCode;
13const getText = eslintUtil.getText;
14
15// ------------------------------------------------------------------------------
16// Rule Definition
17// ------------------------------------------------------------------------------
18
19const messages = {
20 noLineGap: 'Expected no line gap between “{{prop1}}” and “{{prop2}}”',
21 onlyOneSpace: 'Expected only one space between “{{prop1}}” and “{{prop2}}”',
22};
23
24/** @type {import('eslint').Rule.RuleModule} */
25module.exports = {
26 meta: {
27 docs: {
28 description: 'Disallow multiple spaces between inline JSX props',
29 category: 'Stylistic Issues',
30 recommended: false,
31 url: docsUrl('jsx-props-no-multi-spaces'),
32 },
33 fixable: 'code',
34
35 messages,
36
37 schema: [],
38 },
39
40 create(context) {
41 const sourceCode = getSourceCode(context);
42
43 function getPropName(propNode) {
44 switch (propNode.type) {
45 case 'JSXSpreadAttribute':
46 return getText(context, propNode.argument);
47 case 'JSXIdentifier':
48 return propNode.name;
49 case 'JSXMemberExpression':
50 return `${getPropName(propNode.object)}.${propNode.property.name}`;
51 default:
52 return propNode.name
53 ? propNode.name.name
54 : `${getText(context, propNode.object)}.${propNode.property.name}`; // needed for typescript-eslint parser
55 }
56 }
57
58 // First and second must be adjacent nodes
59 function hasEmptyLines(first, second) {
60 const comments = sourceCode.getCommentsBefore ? sourceCode.getCommentsBefore(second) : [];
61 const nodes = [].concat(first, comments, second);
62
63 for (let i = 1; i < nodes.length; i += 1) {
64 const prev = nodes[i - 1];
65 const curr = nodes[i];
66 if (curr.loc.start.line - prev.loc.end.line >= 2) {
67 return true;
68 }
69 }
70
71 return false;
72 }
73
74 function checkSpacing(prev, node) {
75 if (hasEmptyLines(prev, node)) {
76 report(context, messages.noLineGap, 'noLineGap', {
77 node,
78 data: {
79 prop1: getPropName(prev),
80 prop2: getPropName(node),
81 },
82 });
83 }
84
85 if (prev.loc.end.line !== node.loc.end.line) {
86 return;
87 }
88
89 const between = getSourceCode(context).text.slice(prev.range[1], node.range[0]);
90
91 if (between !== ' ') {
92 report(context, messages.onlyOneSpace, 'onlyOneSpace', {
93 node,
94 data: {
95 prop1: getPropName(prev),
96 prop2: getPropName(node),
97 },
98 fix(fixer) {
99 return fixer.replaceTextRange([prev.range[1], node.range[0]], ' ');
100 },
101 });
102 }
103 }
104
105 function containsGenericType(node) {
106 const nodeTypeParams = node.typeParameters;
107 if (typeof nodeTypeParams === 'undefined') {
108 return false;
109 }
110
111 return nodeTypeParams.type === 'TSTypeParameterInstantiation';
112 }
113
114 function getGenericNode(node) {
115 const name = node.name;
116 if (containsGenericType(node)) {
117 const type = node.typeParameters;
118
119 return Object.assign(
120 {},
121 node,
122 {
123 range: [
124 name.range[0],
125 type.range[1],
126 ],
127 }
128 );
129 }
130
131 return name;
132 }
133
134 return {
135 JSXOpeningElement(node) {
136 node.attributes.reduce((prev, prop) => {
137 checkSpacing(prev, prop);
138 return prop;
139 }, getGenericNode(node));
140 },
141 };
142 },
143};
Note: See TracBrowser for help on using the repository browser.