- 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."
136 lines
3.9 KiB
JavaScript
136 lines
3.9 KiB
JavaScript
'use strict';
|
|
|
|
var utils = require('../utils.js');
|
|
var picomatch = require('picomatch');
|
|
require('eslint-visitor-keys');
|
|
require('espree');
|
|
require('estraverse');
|
|
|
|
function testDigit(char) {
|
|
const charCode = char.charCodeAt(0);
|
|
return charCode >= 48 && charCode <= 57;
|
|
}
|
|
function testUpperCase(char) {
|
|
const upperCase = char.toUpperCase();
|
|
return char === upperCase && upperCase !== char.toLowerCase();
|
|
}
|
|
function testLowerCase(char) {
|
|
const lowerCase = char.toLowerCase();
|
|
return char === lowerCase && lowerCase !== char.toUpperCase();
|
|
}
|
|
function testPascalCase(name) {
|
|
if (!testUpperCase(name.charAt(0)))
|
|
return false;
|
|
const anyNonAlphaNumeric = Array.prototype.some.call(
|
|
name.slice(1),
|
|
(char) => char.toLowerCase() === char.toUpperCase() && !testDigit(char)
|
|
);
|
|
if (anyNonAlphaNumeric)
|
|
return false;
|
|
return Array.prototype.some.call(
|
|
name.slice(1),
|
|
(char) => testLowerCase(char) || testDigit(char)
|
|
);
|
|
}
|
|
function testAllCaps(name) {
|
|
const firstChar = name.charAt(0);
|
|
if (!(testUpperCase(firstChar) || testDigit(firstChar)))
|
|
return false;
|
|
for (let i = 1; i < name.length - 1; i += 1) {
|
|
const char = name.charAt(i);
|
|
if (!(testUpperCase(char) || testDigit(char) || char === "_"))
|
|
return false;
|
|
}
|
|
const lastChar = name.charAt(name.length - 1);
|
|
if (!(testUpperCase(lastChar) || testDigit(lastChar)))
|
|
return false;
|
|
return true;
|
|
}
|
|
const messages = {
|
|
usePascalCase: "Imported JSX component {{name}} must be in PascalCase",
|
|
usePascalOrSnakeCase: "Imported JSX component {{name}} must be in PascalCase or SCREAMING_SNAKE_CASE"
|
|
};
|
|
var jsxPascalCase = utils.createRule({
|
|
name: "jsx-pascal-case",
|
|
package: "jsx",
|
|
meta: {
|
|
type: "suggestion",
|
|
docs: {
|
|
description: "Enforce PascalCase for user-defined JSX components"
|
|
// category: 'Stylistic Issues',
|
|
},
|
|
messages,
|
|
schema: [{
|
|
type: "object",
|
|
properties: {
|
|
allowAllCaps: {
|
|
type: "boolean"
|
|
},
|
|
allowLeadingUnderscore: {
|
|
type: "boolean"
|
|
},
|
|
allowNamespace: {
|
|
type: "boolean"
|
|
},
|
|
ignore: {
|
|
items: {
|
|
type: "string"
|
|
},
|
|
type: "array",
|
|
uniqueItems: true
|
|
}
|
|
},
|
|
additionalProperties: false
|
|
}]
|
|
},
|
|
create(context) {
|
|
const configuration = context.options[0] || {};
|
|
const {
|
|
allowAllCaps = false,
|
|
allowLeadingUnderscore = false,
|
|
allowNamespace = false,
|
|
ignore = []
|
|
} = configuration;
|
|
const isMatchIgnore = picomatch(ignore, { noglobstar: true });
|
|
function ignoreCheck(name) {
|
|
return isMatchIgnore(name) || ignore.includes(name);
|
|
}
|
|
return {
|
|
JSXOpeningElement(node) {
|
|
const isCompatTag = utils.isDOMComponent(node);
|
|
if (isCompatTag)
|
|
return;
|
|
const name = utils.getElementType(node);
|
|
let checkNames = [name];
|
|
let index = 0;
|
|
if (name.includes(":"))
|
|
checkNames = name.split(":");
|
|
else if (name.includes("."))
|
|
checkNames = name.split(".");
|
|
do {
|
|
const splitName = checkNames[index];
|
|
if (splitName.length === 1)
|
|
return;
|
|
const isIgnored = ignoreCheck(splitName);
|
|
const checkName = allowLeadingUnderscore && splitName.startsWith("_") ? splitName.slice(1) : splitName;
|
|
const isPascalCase = testPascalCase(checkName);
|
|
const isAllowedAllCaps = allowAllCaps && testAllCaps(checkName);
|
|
if (!isPascalCase && !isAllowedAllCaps && !isIgnored) {
|
|
const messageId = allowAllCaps ? "usePascalOrSnakeCase" : "usePascalCase";
|
|
context.report({
|
|
messageId,
|
|
node,
|
|
data: {
|
|
name: splitName
|
|
}
|
|
});
|
|
break;
|
|
}
|
|
index += 1;
|
|
} while (index < checkNames.length && !allowNamespace);
|
|
}
|
|
};
|
|
}
|
|
});
|
|
|
|
module.exports = jsxPascalCase;
|