UNPKG

@jqassistant/ts-lce

Version:

Tool to extract language concepts from a TypeScript codebase and export them to a JSON file.

83 lines (82 loc) 4.84 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ReactComponentPostProcessor = void 0; const post_processor_1 = require("../../core/post-processor"); const react_component_concept_1 = require("../concepts/react-component.concept"); const function_declaration_concept_1 = require("../../core/concepts/function-declaration.concept"); const variable_declaration_concept_1 = require("../../core/concepts/variable-declaration.concept"); const class_declaration_concept_1 = require("../../core/concepts/class-declaration.concept"); const type_concept_1 = require("../../core/concepts/type.concept"); const jsx_dependency_processor_1 = require("../processors/jsx-dependency.processor"); class ReactComponentPostProcessor extends post_processor_1.PostProcessor { postProcess(projects) { for (const project of projects) { const concepts = project.concepts; const reactComponents = []; // Function Components (standard functions) const allFunctions = (concepts.get(function_declaration_concept_1.LCEFunctionDeclaration.conceptId) ?? []); for (const func of allFunctions) { if (isComponentReturnType(func.returnType)) { const component = new react_component_concept_1.LCEReactComponent(func.fqn, func.functionName, []); if (func.metadata.has(jsx_dependency_processor_1.JSXDependencyContextProcessor.JSX_DEPENDENCY_METADATA)) { component.renderedElements.push(...func.metadata.get(jsx_dependency_processor_1.JSXDependencyContextProcessor.JSX_DEPENDENCY_METADATA)); } reactComponents.push(component); } } // Function Components (function expression) const allVariables = (concepts.get(variable_declaration_concept_1.LCEVariableDeclaration.conceptId) ?? []); for (const variable of allVariables) { if ((variable.type instanceof type_concept_1.LCETypeFunction && isComponentReturnType(variable.type.returnType)) || (variable.type instanceof type_concept_1.LCETypeDeclared && isReactFunctionComponentType(variable.type.fqn.globalFqn))) { const component = new react_component_concept_1.LCEReactComponent(variable.fqn, variable.variableName, []); if (variable.metadata.has(jsx_dependency_processor_1.JSXDependencyContextProcessor.JSX_DEPENDENCY_METADATA)) { component.renderedElements.push(...variable.metadata.get(jsx_dependency_processor_1.JSXDependencyContextProcessor.JSX_DEPENDENCY_METADATA)); } reactComponents.push(component); } } // Class Components const allClasses = (concepts.get(class_declaration_concept_1.LCEClassDeclaration.conceptId) ?? []); for (const clss of allClasses) { if (clss.extendsClass && clss.extendsClass.fqn.globalFqn === '"react".React.Component') { const component = new react_component_concept_1.LCEReactComponent(clss.fqn, clss.className, []); if (clss.metadata.has(jsx_dependency_processor_1.JSXDependencyContextProcessor.JSX_DEPENDENCY_METADATA)) { component.renderedElements.push(...clss.metadata.get(jsx_dependency_processor_1.JSXDependencyContextProcessor.JSX_DEPENDENCY_METADATA)); } reactComponents.push(component); } } concepts.set(react_component_concept_1.LCEReactComponent.conceptId, [...reactComponents.values()]); } } } exports.ReactComponentPostProcessor = ReactComponentPostProcessor; /** * returns whether the provided fqn is a return type that indicates that a function is a React component */ function isComponentReturnType(type) { const validTypeFqns = ['"react".React.ReactNode', '"react".React.JSX.Element', '"react".JSX.Element']; if (type instanceof type_concept_1.LCETypeDeclared) { return validTypeFqns.includes(type.fqn.globalFqn); } else if (type instanceof type_concept_1.LCETypeUnion) { return !!type.types.find((t) => t instanceof type_concept_1.LCETypeDeclared && validTypeFqns.includes(t.fqn.globalFqn)); } else { return false; } } /** * returns whether the provided fqn belongs to an interface/type describing a React function component */ function isReactFunctionComponentType(globalFqn) { return [ '"react".React.FC', '"react".React.ExoticComponent', '"react".React.NamedExoticComponent', '"react".React.ForwardRefExoticComponent', '"react".React.MemoExoticComponent', ].includes(globalFqn); }