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

main
Last change on this file since 0c6b92a was 0c6b92a, checked in by stefan toskovski <stefantoska84@…>, 5 weeks ago

Pred finalna verzija

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