mirror of
https://github.com/HeyPuter/puter.git
synced 2025-11-01 07:07:19 +00:00
The custom eslint pluggin for the formatting rule I have for the
expressions in control structures isn't a good fit when the condition is
a single variable named by a single character. This happens a lot with
`catch`. `catch ( e ) {` has too much spacing, but `catch (e) {` looks
relatively normal.
204 lines
8.2 KiB
JavaScript
204 lines
8.2 KiB
JavaScript
export default {
|
|
meta: {
|
|
type: 'layout',
|
|
docs: {
|
|
description: 'enforce spacing inside parentheses for control structures only',
|
|
category: 'Stylistic Issues',
|
|
},
|
|
fixable: 'whitespace',
|
|
schema: [],
|
|
messages: {
|
|
missingSpaceAfterOpen: 'Missing space after opening parenthesis in control structure.',
|
|
missingSpaceBeforeClose: 'Missing space before closing parenthesis in control structure.',
|
|
unexpectedSpaceAfterOpen: 'Unexpected space after opening parenthesis in function call.',
|
|
unexpectedSpaceBeforeClose: 'Unexpected space before closing parenthesis in function call.',
|
|
},
|
|
},
|
|
|
|
create(context) {
|
|
const sourceCode = context.getSourceCode();
|
|
|
|
function checkControlStructureSpacing(node) {
|
|
// For control structures, we need to find the parentheses around the condition/test
|
|
let conditionNode;
|
|
|
|
if ( node.type === 'IfStatement' || node.type === 'WhileStatement' || node.type === 'DoWhileStatement' ) {
|
|
conditionNode = node.test;
|
|
} else if ( node.type === 'ForStatement' || node.type === 'ForInStatement' || node.type === 'ForOfStatement' ) {
|
|
// For loops, we want the parentheses around the entire for clause
|
|
conditionNode = node;
|
|
} else if ( node.type === 'SwitchStatement' ) {
|
|
conditionNode = node.discriminant;
|
|
} else if ( node.type === 'CatchClause' ) {
|
|
conditionNode = node.param;
|
|
}
|
|
|
|
if ( !conditionNode ) return;
|
|
|
|
// Find the opening paren - it should be right before the condition starts
|
|
const openParen = sourceCode.getTokenBefore(conditionNode, token => token.value === '(');
|
|
if ( !openParen || openParen.value !== '(' ) return;
|
|
|
|
// Find the closing paren - it should be right after the condition ends
|
|
const closeParen = sourceCode.getTokenAfter(conditionNode, token => token.value === ')');
|
|
if ( !closeParen || closeParen.value !== ')' ) return;
|
|
|
|
const afterOpen = sourceCode.getTokenAfter(openParen);
|
|
const beforeClose = sourceCode.getTokenBefore(closeParen);
|
|
|
|
{
|
|
const contentBetweenParens = sourceCode.getText().slice(openParen.range[1], closeParen.range[0]);
|
|
const isSingleCharVariable = /^\s*[a-zA-Z_$]\s*$/.test(contentBetweenParens);
|
|
|
|
// Skip spacing requirements for single character variables
|
|
if ( isSingleCharVariable ) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Control structures should have spacing
|
|
if ( afterOpen && openParen.range[1] === afterOpen.range[0] ) {
|
|
context.report({
|
|
node,
|
|
loc: openParen.loc,
|
|
messageId: 'missingSpaceAfterOpen',
|
|
fix(fixer) {
|
|
return fixer.insertTextAfter(openParen, ' ');
|
|
},
|
|
});
|
|
}
|
|
|
|
if ( beforeClose && beforeClose.range[1] === closeParen.range[0] ) {
|
|
context.report({
|
|
node,
|
|
loc: closeParen.loc,
|
|
messageId: 'missingSpaceBeforeClose',
|
|
fix(fixer) {
|
|
return fixer.insertTextBefore(closeParen, ' ');
|
|
},
|
|
});
|
|
}
|
|
}
|
|
|
|
function checkForLoopSpacing(node) {
|
|
// For loops are special - we need to find the opening paren after the 'for' keyword
|
|
// and the closing paren before the body
|
|
const forKeyword = sourceCode.getFirstToken(node);
|
|
if ( !forKeyword || forKeyword.value !== 'for' ) return;
|
|
|
|
const openParen = sourceCode.getTokenAfter(forKeyword, token => token.value === '(');
|
|
if ( !openParen ) return;
|
|
|
|
// The closing paren should be right before the body
|
|
const closeParen = sourceCode.getTokenBefore(node.body, token => token.value === ')');
|
|
if ( !closeParen ) return;
|
|
|
|
const afterOpen = sourceCode.getTokenAfter(openParen);
|
|
const beforeClose = sourceCode.getTokenBefore(closeParen);
|
|
|
|
if ( afterOpen && openParen.range[1] === afterOpen.range[0] ) {
|
|
context.report({
|
|
node,
|
|
loc: openParen.loc,
|
|
messageId: 'missingSpaceAfterOpen',
|
|
fix(fixer) {
|
|
return fixer.insertTextAfter(openParen, ' ');
|
|
},
|
|
});
|
|
}
|
|
|
|
if ( beforeClose && beforeClose.range[1] === closeParen.range[0] ) {
|
|
context.report({
|
|
node,
|
|
loc: closeParen.loc,
|
|
messageId: 'missingSpaceBeforeClose',
|
|
fix(fixer) {
|
|
return fixer.insertTextBefore(closeParen, ' ');
|
|
},
|
|
});
|
|
}
|
|
}
|
|
|
|
function checkFunctionCallSpacing(node) {
|
|
// Find the opening parenthesis for this function call
|
|
const openParen = sourceCode.getFirstToken(node, token => token.value === '(');
|
|
const closeParen = sourceCode.getLastToken(node, token => token.value === ')');
|
|
|
|
if ( !openParen || !closeParen ) return;
|
|
|
|
const afterOpen = sourceCode.getTokenAfter(openParen);
|
|
const beforeClose = sourceCode.getTokenBefore(closeParen);
|
|
|
|
// Function calls should NOT have spacing
|
|
if ( afterOpen && openParen.range[1] !== afterOpen.range[0] ) {
|
|
const spaceAfter = sourceCode.getText().slice(openParen.range[1], afterOpen.range[0]);
|
|
if ( /^\s+$/.test(spaceAfter) ) {
|
|
context.report({
|
|
node,
|
|
loc: openParen.loc,
|
|
messageId: 'unexpectedSpaceAfterOpen',
|
|
fix(fixer) {
|
|
return fixer.removeRange([openParen.range[1], afterOpen.range[0]]);
|
|
},
|
|
});
|
|
}
|
|
}
|
|
|
|
if ( beforeClose && beforeClose.range[1] !== closeParen.range[0] ) {
|
|
const spaceBefore = sourceCode.getText().slice(beforeClose.range[1], closeParen.range[0]);
|
|
if ( /^\s+$/.test(spaceBefore) ) {
|
|
context.report({
|
|
node,
|
|
loc: closeParen.loc,
|
|
messageId: 'unexpectedSpaceBeforeClose',
|
|
fix(fixer) {
|
|
return fixer.removeRange([beforeClose.range[1], closeParen.range[0]]);
|
|
},
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
return {
|
|
// Control structures that should have spacing
|
|
IfStatement(node) {
|
|
checkControlStructureSpacing(node);
|
|
},
|
|
WhileStatement(node) {
|
|
checkControlStructureSpacing(node);
|
|
},
|
|
DoWhileStatement(node) {
|
|
checkControlStructureSpacing(node);
|
|
},
|
|
SwitchStatement(node) {
|
|
checkControlStructureSpacing(node);
|
|
},
|
|
CatchClause(node) {
|
|
if ( node.param ) {
|
|
checkControlStructureSpacing(node);
|
|
}
|
|
},
|
|
|
|
// For loops need special handling
|
|
ForStatement(node) {
|
|
checkForLoopSpacing(node);
|
|
},
|
|
ForInStatement(node) {
|
|
checkForLoopSpacing(node);
|
|
},
|
|
ForOfStatement(node) {
|
|
checkForLoopSpacing(node);
|
|
},
|
|
|
|
// Function calls that should NOT have spacing
|
|
CallExpression(node) {
|
|
checkFunctionCallSpacing(node);
|
|
},
|
|
NewExpression(node) {
|
|
if ( node.arguments.length > 0 || sourceCode.getLastToken(node).value === ')' ) {
|
|
checkFunctionCallSpacing(node);
|
|
}
|
|
},
|
|
};
|
|
},
|
|
}; |