Files
gridpilot.gg/apps/website/eslint-rules/no-raw-html-in-app.js
2026-01-13 12:10:15 +01:00

80 lines
2.5 KiB
JavaScript

/**
* ESLint rule to forbid raw HTML in app/ directory
*
* All HTML must be encapsulated in React components from components/ or ui/
*
* Rationale:
* - app/ should only contain page/layout components
* - Raw HTML with styling violates separation of concerns
* - UI logic belongs in components/ui layers
*/
module.exports = {
meta: {
type: 'problem',
docs: {
description: 'Forbid raw HTML with styling in app/ directory',
category: 'Architecture',
recommended: true,
},
fixable: null,
schema: [],
messages: {
noRawHtml: 'Raw HTML with styling is forbidden in app/. Use a component from components/ or ui/.',
},
},
create(context) {
const filename = context.getFilename();
const isInApp = filename.includes('/app/');
if (!isInApp) return {};
// HTML tags that should be wrapped in components
const htmlTags = [
'div', 'span', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
'p', 'button', 'input', 'form', 'label', 'select', 'textarea',
'ul', 'ol', 'li', 'table', 'tr', 'td', 'th', 'thead', 'tbody',
'section', 'article', 'header', 'footer', 'nav', 'aside',
'main', 'aside', 'figure', 'figcaption', 'blockquote', 'code',
'pre', 'a', 'img', 'svg', 'path', 'g', 'rect', 'circle'
];
return {
JSXElement(node) {
const openingElement = node.openingElement;
if (openingElement.name.type !== 'JSXIdentifier') return;
const tagName = openingElement.name.name;
// Check if it's a raw HTML element (lowercase)
if (htmlTags.includes(tagName) && tagName[0] === tagName[0].toLowerCase()) {
// Check for styling attributes
const hasClassName = openingElement.attributes.some(
attr => attr.type === 'JSXAttribute' && attr.name.name === 'className'
);
const hasStyle = openingElement.attributes.some(
attr => attr.type === 'JSXAttribute' && attr.name.name === 'style'
);
// Check for inline event handlers (also a concern)
const hasInlineHandlers = openingElement.attributes.some(
attr => attr.type === 'JSXAttribute' &&
attr.name.name &&
attr.name.name.startsWith('on')
);
if (hasClassName || hasStyle || hasInlineHandlers) {
context.report({
node,
messageId: 'noRawHtml',
});
}
}
},
};
},
};