<commit_before>import * as ts from 'typescript';

import { Comment, CommentTag } from '../../models/comments/index';
import { IntrinsicType } from '../../models/types/index';
import { Reflection, ReflectionFlag, ReflectionKind, TraverseProperty,
    TypeParameterReflection, DeclarationReflection, ProjectReflection,
    SignatureReflection, ParameterReflection } from '../../models/reflections/index';
import { Component, ConverterComponent } from '../components';
import { parseComment, getRawComment } from '../factories/comment';
import { Converter } from '../converter';
import { Context } from '../context';

/**
 * Structure used by [[ContainerCommentHandler]] to store discovered module comments.
 */
interface ModuleComment {
    /**
     * The module reflection this comment is targeting.
     */
    reflection: Reflection;

    /**
     * The full text of the best matched comment.
     */
    fullText: string;

    /**
     * Has the full text been marked as being preferred?
     */
    isPreferred: boolean;
}

/**
 * A handler that parses javadoc comments and attaches [[Models.Comment]] instances to
 * the generated reflections.
 */
@Component({name: 'comment'})
export class CommentPlugin extends ConverterComponent {
    /**
     * List of discovered module comments.
     * Defined in this.onBegin
     */
    private comments!: {[id: number]: ModuleComment};

    /**
     * List of hidden reflections.
     */
    private hidden?: Reflection[];

    /**
     * Create a new CommentPlugin instance.
     */
    initialize() {
        this.listenTo(this.owner, {
            [Converter.EVENT_BEGIN]:                   this.onBegin,
            [Converter.EVENT_CREATE_DECLARATION]:      this.onDeclaration,
            [Converter.EVENT_CREATE_SIGNATURE]:        this.onDeclaration,
            [Converter.EVENT_CREATE_TYPE_PARAMETER]:   this.onCreateTypeParameter,
            [Converter.EVENT_FUNCTION_IMPLEMENTATION]: this.onFunctionImplementation,
            [Converter.EVENT_RESOLVE_BEGIN]:           this.onBeginResolve,
            [Converter.EVENT_RESOLVE]:                 this.onResolve
        });
    }

    private storeModuleComment(comment: string, reflection: Reflection) {
        const isPreferred = (comment.toLowerCase().includes('@preferred'));

        if (this.comments[reflection.id]) {
            const info = this.comments[reflection.id];
            if (!isPreferred && (info.isPreferred || info.fullText.length > comment.length)) {
                return;
            }

            info.fullText    = comment;
            info.isPreferred = isPreferred;
        } else {
            this.comments[reflection.id] = {
                reflection:  reflection,
                fullText:    comment,
                isPreferred: isPreferred
            };
        }
    }

    /**
     * Apply all comment tag modifiers to the given reflection.
     *
     * @param reflection  The reflection the modifiers should be applied to.
     * @param comment  The comment that should be searched for modifiers.
     */
    private applyModifiers(reflection: Reflection, comment: Comment) {
        if (comment.hasTag('private')) {
            reflection.setFlag(ReflectionFlag.Private);
            CommentPlugin.removeTags(comment, 'private');
        }

        if (comment.hasTag('protected')) {
            reflection.setFlag(ReflectionFlag.Protected);
            CommentPlugin.removeTags(comment, 'protected');
        }

        if (comment.hasTag('public')) {
            reflection.setFlag(ReflectionFlag.Public);
            CommentPlugin.removeTags(comment, 'public');
        }

        if (comment.hasTag('event')) {
            reflection.kind = ReflectionKind.Event;
            // reflection.setFlag(ReflectionFlag.Event);
            CommentPlugin.removeTags(comment, 'event');
        }

        if (comment.hasTag('hidden') || comment.hasTag('ignore')) {
            if (!this.hidden) {
                this.hidden = [];
            }
            this.hidden.push(reflection);
        }
    }

    /**
     * Triggered when the converter begins converting a project.
     *
     * @param context  The context object describing the current state the converter is in.
     */
    private onBegin(context: Context) {
        this.hidden = undefined;
        this.comments = {};
    }

    /**
     * Triggered when the converter has created a type parameter reflection.
     *
     * @param context  The context object describing the current state the converter is in.<commit_msg>Add `@internal` as a synonym for `@hidden`<commit_after>import * as ts from 'typescript';

import { Comment, CommentTag } from '../../models/comments/index';
import { IntrinsicType } from '../../models/types/index';
import { Reflection, ReflectionFlag, ReflectionKind, TraverseProperty,
    TypeParameterReflection, DeclarationReflection, ProjectReflection,
    SignatureReflection, ParameterReflection } from '../../models/reflections/index';
import { Component, ConverterComponent } from '../components';
import { parseComment, getRawComment } from '../factories/comment';
import { Converter } from '../converter';
import { Context } from '../context';

/**
 * Structure used by [[ContainerCommentHandler]] to store discovered module comments.
 */
interface ModuleComment {
    /**
     * The module reflection this comment is targeting.
     */
    reflection: Reflection;

    /**
     * The full text of the best matched comment.
     */
    fullText: string;

    /**
     * Has the full text been marked as being preferred?
     */
    isPreferred: boolean;
}

/**
 * A handler that parses javadoc comments and attaches [[Models.Comment]] instances to
 * the generated reflections.
 */
@Component({name: 'comment'})
export class CommentPlugin extends ConverterComponent {
    /**
     * List of discovered module comments.
     * Defined in this.onBegin
     */
    private comments!: {[id: number]: ModuleComment};

    /**
     * List of hidden reflections.
     */
    private hidden?: Reflection[];

    /**
     * Create a new CommentPlugin instance.
     */
    initialize() {
        this.listenTo(this.owner, {
            [Converter.EVENT_BEGIN]:                   this.onBegin,
            [Converter.EVENT_CREATE_DECLARATION]:      this.onDeclaration,
            [Converter.EVENT_CREATE_SIGNATURE]:        this.onDeclaration,
            [Converter.EVENT_CREATE_TYPE_PARAMETER]:   this.onCreateTypeParameter,
            [Converter.EVENT_FUNCTION_IMPLEMENTATION]: this.onFunctionImplementation,
            [Converter.EVENT_RESOLVE_BEGIN]:           this.onBeginResolve,
            [Converter.EVENT_RESOLVE]:                 this.onResolve
        });
    }

    private storeModuleComment(comment: string, reflection: Reflection) {
        const isPreferred = (comment.toLowerCase().includes('@preferred'));

        if (this.comments[reflection.id]) {
            const info = this.comments[reflection.id];
            if (!isPreferred && (info.isPreferred || info.fullText.length > comment.length)) {
                return;
            }

            info.fullText    = comment;
            info.isPreferred = isPreferred;
        } else {
            this.comments[reflection.id] = {
                reflection:  reflection,
                fullText:    comment,
                isPreferred: isPreferred
            };
        }
    }

    /**
     * Apply all comment tag modifiers to the given reflection.
     *
     * @param reflection  The reflection the modifiers should be applied to.
     * @param comment  The comment that should be searched for modifiers.
     */
    private applyModifiers(reflection: Reflection, comment: Comment) {
        if (comment.hasTag('private')) {
            reflection.setFlag(ReflectionFlag.Private);
            CommentPlugin.removeTags(comment, 'private');
        }

        if (comment.hasTag('protected')) {
            reflection.setFlag(ReflectionFlag.Protected);
            CommentPlugin.removeTags(comment, 'protected');
        }

        if (comment.hasTag('public')) {
            reflection.setFlag(ReflectionFlag.Public);
            CommentPlugin.removeTags(comment, 'public');
        }

        if (comment.hasTag('event')) {
            reflection.kind = ReflectionKind.Event;
            // reflection.setFlag(ReflectionFlag.Event);
            CommentPlugin.removeTags(comment, 'event');
        }

        if (comment.hasTag('hidden')
            || comment.hasTag('ignore')
            || (comment.hasTag('internal') && this.application.options.getCompilerOptions().stripInternal)
        ) {
            if (!this.hidden) {
                this.hidden = [];
            }
            this.hidden.push(reflection);
        }
    }

    /**
     * Triggered when the converter begins converting a project.
     *
     * @param context  The context object describing the current state the converter is in.
     */
    private onBegin(context: Context) {
        this.hidden = undefined;
        this.comments = {};
    }

    /**
     * Triggered when the converter has created a type parameter reflection.
     *
     * @param context  The context object describing the current state the converter is in.
{'fraction_non_alphanumeric': 0.10870272027744662, 'fraction_numerical': 0.0, 'mean_word_length': 2.296891747052519, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7648438', 'n_tokens_mistral': 2351, 'n_tokens_neox': 2316, 'n_words': 589}