<commit_before>package cz.habarta.typescript.generator.ext;

import java.util.*;
import cz.habarta.typescript.generator.Settings;
import cz.habarta.typescript.generator.TsType;
import cz.habarta.typescript.generator.TsType.GenericReferenceType;
import cz.habarta.typescript.generator.compiler.EnumKind;
import cz.habarta.typescript.generator.compiler.EnumMemberModel;
import cz.habarta.typescript.generator.emitter.EmitterExtension;
import cz.habarta.typescript.generator.emitter.EmitterExtensionFeatures;
import cz.habarta.typescript.generator.emitter.TsBeanModel;
import cz.habarta.typescript.generator.emitter.TsEnumModel;
import cz.habarta.typescript.generator.emitter.TsModel;
import cz.habarta.typescript.generator.emitter.TsPropertyModel;

/**
 * Emitter which generates type-safe property path getters.
 *
 * Many javascript frameworks require that you specify "property paths"
 * to extract data from objects. For instance, if you have a data model
 * which is an array of items, and you want to display them in a grid,
 * you can give column specifications as strings, like "field1.field2".
 * With this emitter you can specify such paths like so:
 * {@code ClassName.field1.field2.get()}
 * Once you call {@code get()}, you get a string
 * (in this case "field1.field2")
 */
public class BeanPropertyPathExtension extends EmitterExtension {

    @Override
    public EmitterExtensionFeatures getFeatures() {
        final EmitterExtensionFeatures features = new EmitterExtensionFeatures();
        features.generatesRuntimeCode = true;
        return features;
    }

    @Override
    public void emitElements(Writer writer, Settings settings, boolean exportKeyword, TsModel model) {
        emitFieldsClass(writer, settings);

        Set<TsBeanModel> emittedBeans = new HashSet<>();
        for (TsBeanModel bean : model.getBeans()) {
            emittedBeans.addAll(
                writeBeanAndParentsFieldSpecs(writer, settings, model, emittedBeans, bean));
        }
        for (TsBeanModel bean : model.getBeans()) {
            createBeanFieldConstant(writer, exportKeyword, bean);
        }
    }

    private static void emitFieldsClass(Writer writer, Settings settings) {
        List<String> fieldsClassLines = Arrays.asList(
            "class Fields {",
            "    protected parent: Fields | undefined;",
            "    protected name: string | undefined;",
            "    constructor(parent?: Fields, name?: string) {",
            "        this.parent = parent;",
            "        this.name = name;",
            "    };",
            "    get(): string | undefined {",
            "        if (this.parent && this.parent.get()) {",
            "            return this.name ? this.parent.get() + \".\" + this.name : this.parent.get();",
            "        } else {",
            "            return this.name;",
            "        }",
            "    }",
            "}");
        writer.writeIndentedLine("");
        for (String fieldsClassLine : fieldsClassLines) {
            writer.writeIndentedLine(fieldsClassLine.replace("    ", settings.indentString));
        }
    }

    /**
     * Emits a bean and its parent beans before if needed.
     * Returns the list of beans that were emitted.<commit_msg>fixes bug with the bean property path extension, if the DTO had a field named 'name' or 'parent'<commit_after>package cz.habarta.typescript.generator.ext;

import java.util.*;
import cz.habarta.typescript.generator.Settings;
import cz.habarta.typescript.generator.TsType;
import cz.habarta.typescript.generator.TsType.GenericReferenceType;
import cz.habarta.typescript.generator.compiler.EnumKind;
import cz.habarta.typescript.generator.compiler.EnumMemberModel;
import cz.habarta.typescript.generator.emitter.EmitterExtension;
import cz.habarta.typescript.generator.emitter.EmitterExtensionFeatures;
import cz.habarta.typescript.generator.emitter.TsBeanModel;
import cz.habarta.typescript.generator.emitter.TsEnumModel;
import cz.habarta.typescript.generator.emitter.TsModel;
import cz.habarta.typescript.generator.emitter.TsPropertyModel;

/**
 * Emitter which generates type-safe property path getters.
 *
 * Many javascript frameworks require that you specify "property paths"
 * to extract data from objects. For instance, if you have a data model
 * which is an array of items, and you want to display them in a grid,
 * you can give column specifications as strings, like "field1.field2".
 * With this emitter you can specify such paths like so:
 * {@code ClassName.field1.field2.get()}
 * Once you call {@code get()}, you get a string
 * (in this case "field1.field2")
 */
public class BeanPropertyPathExtension extends EmitterExtension {

    @Override
    public EmitterExtensionFeatures getFeatures() {
        final EmitterExtensionFeatures features = new EmitterExtensionFeatures();
        features.generatesRuntimeCode = true;
        return features;
    }

    @Override
    public void emitElements(Writer writer, Settings settings, boolean exportKeyword, TsModel model) {
        emitFieldsClass(writer, settings);

        Set<TsBeanModel> emittedBeans = new HashSet<>();
        for (TsBeanModel bean : model.getBeans()) {
            emittedBeans.addAll(
                writeBeanAndParentsFieldSpecs(writer, settings, model, emittedBeans, bean));
        }
        for (TsBeanModel bean : model.getBeans()) {
            createBeanFieldConstant(writer, exportKeyword, bean);
        }
    }

    private static void emitFieldsClass(Writer writer, Settings settings) {
        List<String> fieldsClassLines = Arrays.asList(
            "class Fields {",
            "    protected $$parent: Fields | undefined;",
            "    protected $$name: string | undefined;",
            "    constructor(parent?: Fields, name?: string) {",
            "        this.$$parent = parent;",
            "        this.$$name = name;",
            "    };",
            "    get(): string | undefined {",
            "        if (this.$$parent && this.$$parent.get()) {",
            "            return this.$$name ? this.$$parent.get() + \".\" + this.$$name : this.$$parent.get();",
            "        } else {",
            "            return this.$$name;",
            "        }",
            "    }",
            "}");
        writer.writeIndentedLine("");
        for (String fieldsClassLine : fieldsClassLines) {
            writer.writeIndentedLine(fieldsClassLine.replace("    ", settings.indentString));
        }
    }

    /**
     * Emits a bean and its parent beans before if needed.
     * Returns the list of beans that were emitted.
{'fraction_non_alphanumeric': 0.10644722935225728, 'fraction_numerical': 0.0018118677336554432, 'mean_word_length': 2.780821917808219, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 9, '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': '7156353', 'n_tokens_mistral': 1799, 'n_tokens_neox': 1719, 'n_words': 462}