ifc-language-server/node_modules/@stylistic/eslint-plugin/dist/rules/jsx-self-closing-comp.js
Ryan Schultz 8afacf268a Implemented a working Language Server Protocol (LSP) for IFC files with:
- Hover provider showing entity information and type
- Go-to-definition (F12) for entity references
- Basic IFC file validation (ISO-10303-21 header check)
- Entity parsing with regex-based detection
- Proper CommonJS module system (avoiding ES module issues)

This replaces the broken baseline from ifc-developer-tools which had:
- Non-functional ES module configuration
- Circular dependency issues
- Parser crashes
- Non-working PositionVisitor

Built on Microsoft's LSP example template for a clean, maintainable foundation.

Next: Add hierarchical entity dependency tree in hover tooltip."
2025-12-07 10:20:07 -06:00

73 lines
2.3 KiB
JavaScript

'use strict';
var utils = require('../utils.js');
require('eslint-visitor-keys');
require('espree');
require('estraverse');
const optionDefaults = { component: true, html: true };
const messages = {
notSelfClosing: "Empty components are self-closing"
};
var jsxSelfClosingComp = utils.createRule({
name: "jsx-self-closing-comp",
package: "jsx",
meta: {
type: "layout",
docs: {
description: "Disallow extra closing tags for components without children"
},
fixable: "code",
messages,
schema: [
{
type: "object",
properties: {
component: {
default: optionDefaults.component,
type: "boolean"
},
html: {
default: optionDefaults.html,
type: "boolean"
}
},
additionalProperties: false
}
]
},
create(context) {
function isComponent(node) {
return node.name && (node.name.type === "JSXIdentifier" || node.name.type === "JSXMemberExpression") && !utils.isDOMComponent(node);
}
function childrenIsEmpty(node) {
return node.parent.children.length === 0;
}
function childrenIsMultilineSpaces(node) {
const childrens = node.parent.children;
return childrens.length === 1 && childrens[0].type === "JSXText" && childrens[0].value.includes("\n") && childrens[0].value.replace(/(?!\xA0)\s/g, "") === "";
}
function isShouldBeSelfClosed(node) {
const configuration = Object.assign({}, optionDefaults, context.options[0]);
return (configuration.component && isComponent(node) || configuration.html && utils.isDOMComponent(node)) && !node.selfClosing && (childrenIsEmpty(node) || childrenIsMultilineSpaces(node));
}
return {
JSXOpeningElement(node) {
if (!isShouldBeSelfClosed(node))
return;
context.report({
messageId: "notSelfClosing",
node,
fix(fixer) {
const openingElementEnding = node.range[1] - 1;
const closingElementEnding = node.parent.closingElement?.range[1] ?? NaN;
const range = [openingElementEnding, closingElementEnding];
return fixer.replaceTextRange(range, " />");
}
});
}
};
}
});
module.exports = jsxSelfClosingComp;