norminette-mcp
Version:
MCP server for 42 School norminette coding standard checker
120 lines (119 loc) • 5.21 kB
JavaScript
import { Token, TokenType } from "../../../lexer/token.js";
// SPACE_REPLACE_TAB: Convert spaces to tabs in variable declarations
export const spaceReplaceTabRule = {
name: "SPACE_REPLACE_TAB",
errorCodes: ["SPACE_REPLACE_TAB"],
priority: 1,
canFix(tokens, error) {
// Find tokens on the error line
const lineTokens = tokens.filter(token => token.lineno === error.line);
// Pattern 1: TYPE SPACE IDENTIFIER (int x, char *ptr)
// Pattern 2: TYPE SPACE MULT (int *, char **)
// Pattern 3: RBRACE SPACE IDENTIFIER (} t_mystruct)
// Pattern 4: CONST SPACE TYPE (const int)
for (let i = 0; i < lineTokens.length - 2; i++) {
const prevToken = lineTokens[i];
const spaceToken = lineTokens[i + 1];
const nextToken = lineTokens[i + 2];
if (spaceToken.type === TokenType.SPACE) {
// Pattern 1: TYPE SPACE IDENTIFIER/MULT
if ((prevToken.type === TokenType.IDENTIFIER ||
prevToken.type === 'INT' ||
prevToken.type === 'CHAR' ||
prevToken.type === 'VOID' ||
prevToken.type === 'CONST') &&
(nextToken.type === TokenType.IDENTIFIER ||
nextToken.type === TokenType.MULT ||
nextToken.type === TokenType.LPARENTHESIS)) {
return true;
}
// Pattern 3: RBRACE SPACE IDENTIFIER (} t_mystruct)
if (prevToken.type === TokenType.RBRACE &&
nextToken.type === TokenType.IDENTIFIER) {
return true;
}
}
}
return false;
},
apply(tokens, error) {
const result = [...tokens];
// Find and replace space tokens with tabs based on patterns
for (let i = 0; i < result.length - 2; i++) {
const prevToken = result[i];
const spaceToken = result[i + 1];
const nextToken = result[i + 2];
if (prevToken.lineno === error.line &&
spaceToken.type === TokenType.SPACE) {
// Pattern 1: TYPE SPACE IDENTIFIER/MULT/LPARENTHESIS
if ((prevToken.type === TokenType.IDENTIFIER ||
prevToken.type === 'INT' ||
prevToken.type === 'CHAR' ||
prevToken.type === 'VOID' ||
prevToken.type === 'CONST') &&
(nextToken.type === TokenType.IDENTIFIER ||
nextToken.type === TokenType.MULT ||
nextToken.type === TokenType.LPARENTHESIS)) {
result[i + 1] = new Token(TokenType.TAB, spaceToken.pos, '\t');
break;
}
// Pattern 3: RBRACE SPACE IDENTIFIER
if (prevToken.type === TokenType.RBRACE &&
nextToken.type === TokenType.IDENTIFIER) {
result[i + 1] = new Token(TokenType.TAB, spaceToken.pos, '\t');
break;
}
}
}
return result;
}
};
// SPACE_BEFORE_FUNC: Add tab between return type and function name
export const spaceBeforeFuncRule = {
name: "SPACE_BEFORE_FUNC",
errorCodes: ["SPACE_BEFORE_FUNC"],
priority: 1,
canFix(tokens, error) {
// Find tokens on the error line
const lineTokens = tokens.filter(token => token.lineno === error.line);
// Look for pattern: TYPE SPACE IDENTIFIER LPARENTHESIS
for (let i = 0; i < lineTokens.length - 3; i++) {
const typeToken = lineTokens[i];
const spaceToken = lineTokens[i + 1];
const funcToken = lineTokens[i + 2];
const parenToken = lineTokens[i + 3];
if ((typeToken.type === TokenType.IDENTIFIER || typeToken.type === 'INT') &&
spaceToken.type === TokenType.SPACE &&
funcToken.type === TokenType.IDENTIFIER &&
parenToken.type === TokenType.LPARENTHESIS) {
return true;
}
}
return false;
},
apply(tokens, error) {
const result = [...tokens];
// Find and replace space tokens between return type and function name
for (let i = 0; i < result.length - 3; i++) {
const typeToken = result[i];
const spaceToken = result[i + 1];
const funcToken = result[i + 2];
const parenToken = result[i + 3];
if (typeToken.lineno === error.line &&
(typeToken.type === TokenType.IDENTIFIER || typeToken.type === 'INT') &&
spaceToken.type === TokenType.SPACE &&
funcToken.type === TokenType.IDENTIFIER &&
parenToken.type === TokenType.LPARENTHESIS) {
// Replace space with tab
result[i + 1] = new Token(TokenType.TAB, spaceToken.pos, '\t');
break;
}
}
return result;
}
};
// Export all available rules
export const defaultFormattingRules = [
spaceReplaceTabRule,
spaceBeforeFuncRule
];