core/plugins/syntax.event.plugin.ts

core/plugins/syntax.event.plugin.ts is a file in GovLab Docs. 47 lines of code and 13 definitions.

import type { CalleeParts, Recognizer } from "#types/code.types";
import { hookLabel } from "#configuration/strings/graph.strings";
import ts from "typescript";

const LISTENER_METHOD = "addEventListener";
const SUBSCRIBE_METHODS: ReadonlySet<string> = new Set(["add", "on"]);
const EVENT_OWNERS: readonly string[] = ["event", "manager", "bus"];

const ownerName = function ownerName(target: ts.Expression): string {
    if (ts.isIdentifier(target)) {
        return target.text;
    }
    return ts.isPropertyAccessExpression(target) ? target.name.text : "";
};

const calleeParts = function calleeParts(node: ts.CallExpression): CalleeParts | null {
    if (!ts.isPropertyAccessExpression(node.expression)) {
        return null;
    }
    return { method: node.expression.name.text, owner: ownerName(node.expression.expression).toLowerCase() };
};

const isHookCall = function isHookCall(parts: CalleeParts): boolean {
    if (parts.method === LISTENER_METHOD) {
        return true;
    }
    return SUBSCRIBE_METHODS.has(parts.method) && EVENT_OWNERS.some((owner) => parts.owner.includes(owner));
};

const eventName = function eventName(node: ts.CallExpression, method: string): string {
    const [first] = node.arguments;
    return first && ts.isStringLiteralLike(first) ? first.text : method;
};

export const recognizer: Recognizer = {
    classify(node, context) {
        if (!ts.isCallExpression(node)) {
            return null;
        }
        const parts = calleeParts(node);
        if (parts === null || !isHookCall(parts)) {
            return null;
        }
        const event = eventName(node, parts.method);
        const id = context.mkNodeId(node);
        return {
            edges: [{ from: context.currentId, kind: "hook-register", label: event, to: id }],
            nodes: [{ id, kind: "hook", label: hookLabel(event), source: context.sourceOf(node) }],
        };
    },
    emits: { edges: ["hook-register"], nodes: ["hook"] },
    name: "event-hook",
};