website refactor
This commit is contained in:
@@ -140,63 +140,122 @@ module.exports = {
|
||||
},
|
||||
},
|
||||
create(context) {
|
||||
// Helper to recursively check if type contains ViewData
|
||||
function typeContainsViewData(typeNode) {
|
||||
if (!typeNode) return false;
|
||||
|
||||
// Check direct type name
|
||||
if (typeNode.type === 'TSTypeReference' &&
|
||||
typeNode.typeName &&
|
||||
typeNode.typeName.name &&
|
||||
typeNode.typeName.name.includes('ViewData')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check nested in object type
|
||||
if (typeNode.type === 'TSTypeLiteral' && typeNode.members) {
|
||||
for (const member of typeNode.members) {
|
||||
if (member.type === 'TSPropertySignature' &&
|
||||
member.typeAnnotation &&
|
||||
typeContainsViewData(member.typeAnnotation.typeAnnotation)) {
|
||||
return true;
|
||||
const sourceCode = context.getSourceCode();
|
||||
|
||||
function isTemplateExportFunction(node) {
|
||||
const functionName = node.id && node.id.type === 'Identifier' ? node.id.name : null;
|
||||
if (!functionName || !functionName.endsWith('Template')) return false;
|
||||
|
||||
// Only enforce for exported template component functions.
|
||||
return node.parent && node.parent.type === 'ExportNamedDeclaration';
|
||||
}
|
||||
|
||||
function getTypeReferenceName(typeNode) {
|
||||
if (!typeNode || typeNode.type !== 'TSTypeReference') return null;
|
||||
const typeName = typeNode.typeName;
|
||||
if (!typeName || typeName.type !== 'Identifier') return null;
|
||||
return typeName.name;
|
||||
}
|
||||
|
||||
function findLocalTypeDeclaration(typeName) {
|
||||
const programBody = sourceCode.ast && sourceCode.ast.body ? sourceCode.ast.body : [];
|
||||
|
||||
for (const stmt of programBody) {
|
||||
if (!stmt) continue;
|
||||
|
||||
// interface Foo { ... }
|
||||
if (stmt.type === 'TSInterfaceDeclaration' && stmt.id && stmt.id.type === 'Identifier') {
|
||||
if (stmt.id.name === typeName) return stmt;
|
||||
}
|
||||
|
||||
// type Foo = ...
|
||||
if (stmt.type === 'TSTypeAliasDeclaration' && stmt.id && stmt.id.type === 'Identifier') {
|
||||
if (stmt.id.name === typeName) return stmt;
|
||||
}
|
||||
|
||||
// export interface/type Foo ...
|
||||
if (stmt.type === 'ExportNamedDeclaration' && stmt.declaration) {
|
||||
const decl = stmt.declaration;
|
||||
if (decl.type === 'TSInterfaceDeclaration' && decl.id && decl.id.type === 'Identifier' && decl.id.name === typeName) {
|
||||
return decl;
|
||||
}
|
||||
if (decl.type === 'TSTypeAliasDeclaration' && decl.id && decl.id.type === 'Identifier' && decl.id.name === typeName) {
|
||||
return decl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check union/intersection types
|
||||
if (typeNode.type === 'TSUnionType' || typeNode.type === 'TSIntersectionType') {
|
||||
return typeNode.types.some(t => typeContainsViewData(t));
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// Helper to recursively check if type contains ViewData (including by resolving local interface/type aliases).
|
||||
function typeContainsViewData(typeNode, seenTypeNames = new Set()) {
|
||||
if (!typeNode) return false;
|
||||
|
||||
// Direct type name includes ViewData (e.g. ProfileViewData)
|
||||
if (typeNode.type === 'TSTypeReference' && typeNode.typeName && typeNode.typeName.type === 'Identifier') {
|
||||
const name = typeNode.typeName.name;
|
||||
if (name.includes('ViewData')) return true;
|
||||
|
||||
// If the param is typed as a local Props interface/type, resolve it and inspect its members.
|
||||
if (!seenTypeNames.has(name)) {
|
||||
seenTypeNames.add(name);
|
||||
const decl = findLocalTypeDeclaration(name);
|
||||
if (decl && decl.type === 'TSInterfaceDeclaration') {
|
||||
for (const member of decl.body.body || []) {
|
||||
if (member.type === 'TSPropertySignature' && member.typeAnnotation) {
|
||||
if (typeContainsViewData(member.typeAnnotation.typeAnnotation, seenTypeNames)) return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (decl && decl.type === 'TSTypeAliasDeclaration') {
|
||||
if (typeContainsViewData(decl.typeAnnotation, seenTypeNames)) return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Nested in object type
|
||||
if (typeNode.type === 'TSTypeLiteral' && typeNode.members) {
|
||||
for (const member of typeNode.members) {
|
||||
if (member.type === 'TSPropertySignature' && member.typeAnnotation) {
|
||||
if (typeContainsViewData(member.typeAnnotation.typeAnnotation, seenTypeNames)) return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Union/intersection types
|
||||
if (typeNode.type === 'TSUnionType' || typeNode.type === 'TSIntersectionType') {
|
||||
return typeNode.types.some((t) => typeContainsViewData(t, seenTypeNames));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
return {
|
||||
FunctionDeclaration(node) {
|
||||
if (!isTemplateExportFunction(node)) return;
|
||||
|
||||
if (node.params.length === 0) {
|
||||
context.report({
|
||||
node,
|
||||
messageId: 'message',
|
||||
});
|
||||
context.report({ node, messageId: 'message' });
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const firstParam = node.params[0];
|
||||
|
||||
// `function FooTemplate({ ... }: Props)` -> the type annotation is on the parameter, not on the destructured properties.
|
||||
if (!firstParam.typeAnnotation || !firstParam.typeAnnotation.typeAnnotation) {
|
||||
context.report({
|
||||
node,
|
||||
messageId: 'message',
|
||||
});
|
||||
context.report({ node, messageId: 'message' });
|
||||
return;
|
||||
}
|
||||
|
||||
const typeAnnotation = firstParam.typeAnnotation.typeAnnotation;
|
||||
|
||||
if (!typeContainsViewData(typeAnnotation)) {
|
||||
context.report({
|
||||
node,
|
||||
messageId: 'message',
|
||||
});
|
||||
|
||||
const firstParamType = firstParam.typeAnnotation.typeAnnotation;
|
||||
|
||||
// If it's a reference to a local type/interface, we handle it in typeContainsViewData().
|
||||
const refName = getTypeReferenceName(firstParamType);
|
||||
if (refName && refName.includes('ViewData')) return;
|
||||
|
||||
if (!typeContainsViewData(firstParamType)) {
|
||||
context.report({ node, messageId: 'message' });
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user