@jqassistant/ts-lce
Version:
Tool to extract language concepts from a TypeScript codebase and export them to a JSON file.
212 lines (211 loc) • 7.06 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.JSXDependencyProcessor = exports.JSXDependencyContextProcessor = void 0;
const utils_1 = require("@typescript-eslint/utils");
const context_1 = require("../../core/context");
const execution_condition_1 = require("../../core/execution-condition");
const processor_1 = require("../../core/processor");
const react_jsx_dependency_1 = require("../concepts/react-jsx-dependency");
const dependency_resolution_processor_1 = require("../../core/processors/dependency-resolution.processor");
const class_declaration_concept_1 = require("../../core/concepts/class-declaration.concept");
const variable_declaration_concept_1 = require("../../core/concepts/variable-declaration.concept");
const function_declaration_concept_1 = require("../../core/concepts/function-declaration.concept");
const variable_declaration_processor_1 = require("../../core/processors/variable-declaration.processor");
const context_keys_1 = require("../context.keys");
const log_utils_1 = require("../../core/utils/log.utils");
class JSXDependencyContextProcessor extends processor_1.Processor {
static JSX_DEPENDENCY_METADATA;
executionCondition = new execution_condition_1.ExecutionCondition([
utils_1.AST_NODE_TYPES.VariableDeclarator,
utils_1.AST_NODE_TYPES.FunctionDeclaration,
utils_1.AST_NODE_TYPES.ArrowFunctionExpression,
utils_1.AST_NODE_TYPES.ClassDeclaration,
], ({ localContexts, node }) => !!localContexts.parentContexts?.get(variable_declaration_processor_1.VariableDeclarationProcessor.VARIABLE_DECLARATION_KIND_CONTEXT) ||
(!!node.parent &&
(node.parent.type === utils_1.AST_NODE_TYPES.ExportNamedDeclaration ||
node.parent.type === utils_1.AST_NODE_TYPES.ExportDefaultDeclaration ||
node.parent.type === utils_1.AST_NODE_TYPES.Program)));
preChildrenProcessing(processingContext) {
processingContext.localContexts.currentContexts.set(context_keys_1.ReactContextKeys.JSX_DEPENDENCIES, new Array());
}
postChildrenProcessing({ localContexts, metadataAssignments }) {
const jsxContext = localContexts.getNextContext(context_keys_1.ReactContextKeys.JSX_DEPENDENCIES)[0];
const aggregatedDependencies = new Map();
for (const dep of jsxContext) {
if (aggregatedDependencies.has(dep.fqn.globalFqn)) {
aggregatedDependencies.get(dep.fqn.globalFqn).cardinality++;
}
else {
aggregatedDependencies.set(dep.fqn.globalFqn, dep);
}
}
metadataAssignments.push(new context_1.MetadataAssignmentRule((c) => {
return c instanceof class_declaration_concept_1.LCEClassDeclaration || c instanceof variable_declaration_concept_1.LCEVariableDeclaration || c instanceof function_declaration_concept_1.LCEFunctionDeclaration;
}, new Map([[JSXDependencyContextProcessor.JSX_DEPENDENCY_METADATA, [...aggregatedDependencies.values()]]])));
return new Map();
}
}
exports.JSXDependencyContextProcessor = JSXDependencyContextProcessor;
class JSXDependencyProcessor extends processor_1.Processor {
executionCondition = new execution_condition_1.ExecutionCondition([utils_1.AST_NODE_TYPES.JSXOpeningElement], () => true);
postChildrenProcessing({ node, localContexts, globalContext }) {
if (node.type === utils_1.AST_NODE_TYPES.JSXOpeningElement) {
let name = "";
// try to determine name of the tag, abort processing, if not possible
if (node.name.type === utils_1.AST_NODE_TYPES.JSXIdentifier) {
name = node.name.name;
}
else if (node.name.type === utils_1.AST_NODE_TYPES.JSXMemberExpression) {
let depth = 0;
name = node.name.property.name;
let currentExpression = node.name.object;
while (currentExpression.type === utils_1.AST_NODE_TYPES.JSXMemberExpression) {
if (depth > 20) {
(0, log_utils_1.debug)(`ERROR: Could not resolve JSX member expression: ${name}`);
return new Map();
}
name = currentExpression.property.name + "." + name;
currentExpression = currentExpression.object;
depth++;
}
if (currentExpression.type === utils_1.AST_NODE_TYPES.JSXIdentifier) {
name = currentExpression.name + "." + name;
}
else {
name = currentExpression.namespace.name + "." + name;
}
}
else {
return new Map();
}
const dep = new react_jsx_dependency_1.LCEJSXDependency(new context_1.FQN(name), name, 1);
if (!STANDARD_HTML_ELEMENTS.includes(name)) {
// Custom Element: try to resolve reference and register dependency
dependency_resolution_processor_1.DependencyResolutionProcessor.scheduleFqnResolution(localContexts, name, dep);
dependency_resolution_processor_1.DependencyResolutionProcessor.registerDependency(localContexts, name);
}
const jsxDependencyContext = localContexts.getNextContext(context_keys_1.ReactContextKeys.JSX_DEPENDENCIES);
if (jsxDependencyContext) {
jsxDependencyContext[0].push(dep);
}
}
return new Map();
}
}
exports.JSXDependencyProcessor = JSXDependencyProcessor;
const STANDARD_HTML_ELEMENTS = [
"a",
"abbr",
"address",
"area",
"article",
"aside",
"audio",
"b",
"base",
"bdi",
"bdo",
"blockquote",
"body",
"br",
"button",
"canvas",
"caption",
"cite",
"code",
"col",
"colgroup",
"data",
"datalist",
"dd",
"del",
"details",
"dfn",
"dialog",
"div",
"dl",
"dt",
"em",
"embed",
"fieldset",
"figcaption",
"figure",
"footer",
"form",
"h1",
"h2",
"h3",
"h4",
"h5",
"h6",
"head",
"header",
"hgroup",
"hr",
"html",
"i",
"iframe",
"img",
"input",
"ins",
"kbd",
"label",
"legend",
"li",
"link",
"main",
"map",
"mark",
"math",
"menu",
"meta",
"meter",
"nav",
"noscript",
"object",
"ol",
"optgroup",
"option",
"output",
"p",
"picture",
"pre",
"progress",
"q",
"rp",
"rt",
"ruby",
"s",
"samp",
"script",
"search",
"section",
"select",
"slot",
"small",
"source",
"span",
"strong",
"style",
"sub",
"summary",
"sup",
"svg",
"table",
"tbody",
"td",
"template",
"textarea",
"tfoot",
"th",
"thead",
"time",
"title",
"tr",
"track",
"u",
"ul",
"var",
"video",
"wbr",
];