@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
JavaScript
;
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);
}