<commit_before>import { ASSEMBLER_INSTANCE_PROPERTY_NAME } from './core'

export class TargetAssembler {
    /**
     * Create the assembler instance and assemble the specified object
     * Initializes the object by all passed init arguments
     * @param {*} [init]
     * @param {*} [rest]
     */
    constructor(init, ...rest) {
        this.assemble(init)
        if(rest.length) {
            rest.forEach(init => this.init(init))
        }
    }

    /**
     * Instantiate and initialize the specified object
     * @param {*} [init] initializing dictionary
     * @returns {Object|*}
     */
    assemble(init) {
        const target = this.create(init)
        this.setInstance(target)
        this.init(init)
        return target
    }

    /**
     * Create the specified object
     * @param {*} [init] initializing dictionary
     * @returns {Object|*}
     */
    create(init) {
        return init && init.constructor === Object?
            this.constructor.create(init) :
            this.constructor.create()
    }

    /**
     * Initialize the object with the defined properties
     * @param {*} init initializing dictionary
     * @returns {Object|*} initialized node
     */
    init(init) {
        const target = this._target
        if(init && init.constructor === Object) {
            const constructor = this.constructor
            for(let prop in init) {
                const value = init[prop]
                if(value !== undefined) {
                    if(prop in this) this[prop] = value
                    else if(prop in constructor) void null
                    else if(prop in target) target[prop] = value
                    else this._onMismatch(prop, value)
                }
            }
        }
    }

    /**
     * @param {Object|*} target
     */
    setInstance(target) {
        this._target = target
        target[ASSEMBLER_INSTANCE_PROPERTY_NAME] = this
    }

    /**
     * @param {Object|*} target
     * @returns {TargetAssembler|*}
     */
    getInstance(target) {
        return target? this.constructor.getInstance(target) : null
    }

    /**
     * The init mismatch handler
     * @param {String} prop mismatched property name
     * @param {*} value mismatched property value
     */
    _onMismatch(prop, value) {
        const propval = prop + `="${ value }"`
        const name = this.name
        const message = `The property ${ propval } is not found on the ${ name } instance:`
        console.warn(message, this)
    }

    /**
     * Stub for extension
     */
    static create() {
        throw Error(`Could not create an abstract ${ this.name } instance!`)
    }

    /**
     * @param {Object|*} target
     * @returns {TargetAssembler|*|null}
     */
    static getInstance(target) {
        return target[ASSEMBLER_INSTANCE_PROPERTY_NAME] || null
    }
}

Object.defineProperty(
    TargetAssembler.prototype,
    '_target',
    {
        writable : true,
        value : null
    })
<commit_msg>TargetAssembler: refactoring<commit_after>import { ASSEMBLER_INSTANCE_PROPERTY_NAME } from './core'

export class TargetAssembler {
    /**
     * Create the assembler instance and assemble the specified object
     * Initializes the object by all passed init arguments
     * @param {*} [init]
     * @param {*} [rest]
     */
    constructor(init, ...rest) {
        this.assemble(init)
        if(rest.length) {
            rest.forEach(init => this.init(init))
        }
    }

    /**
     * Instantiate and initialize the specified object
     * @param {*} [init] initializing dictionary
     * @returns {Object|*}
     */
    assemble(init) {
        this.setInstance(this.create(init))
        this.init(init)
        return this._target
    }

    /**
     * Create the specified object
     * @param {*} [init] initializing dictionary
     * @returns {Object|*}
     */
    create(init) {
        return init && init.constructor === Object?
            this.constructor.create(init) :
            this.constructor.create()
    }

    /**
     * Initialize the object with the defined properties
     * @param {*} init initializing dictionary
     * @returns {Object|*} initialized node
     */
    init(init) {
        const target = this._target
        if(init && init.constructor === Object) {
            const constructor = this.constructor
            for(let prop in init) {
                const value = init[prop]
                if(value !== undefined) {
                    if(prop in this) this[prop] = value
                    else if(prop in constructor) void null
                    else if(prop in target) target[prop] = value
                    else this._onMismatch(prop, value)
                }
            }
        }
    }

    /**
     * @param {Object|*} target
     */
    setInstance(target) {
        this._target = target
        target[ASSEMBLER_INSTANCE_PROPERTY_NAME] = this
    }

    /**
     * @param {Object|*} target
     * @returns {TargetAssembler|*}
     */
    getInstance(target) {
        return target? this.constructor.getInstance(target) : null
    }

    /**
     * The init property mismatch handler
     * @param {String} prop mismatched property name
     * @param {*} value mismatched property value
     */
    _onMismatch(prop, value) {
        const propval = prop + `="${ value }"`
        const name = this.constructor.name
        const message = `The property ${ propval } is not found on the ${ name } instance:`
        console.warn(this, message)
    }

    /**
     * Stub for extension
     */
    static create() {
        throw Error(`Could not create an abstract ${ this.name } instance!`)
    }

    /**
     * @param {Object|*} target
     * @returns {TargetAssembler|*|null}
     */
    static getInstance(target) {
        return target[ASSEMBLER_INSTANCE_PROPERTY_NAME] || null
    }
}

Object.defineProperty(
    TargetAssembler.prototype,
    '_target',
    {
        writable : true,
        value : null
    })

{'fraction_non_alphanumeric': 0.11530748663101605, 'fraction_numerical': 0.0, 'mean_word_length': 1.9095770539620807, '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': '709574', 'n_tokens_mistral': 1674, 'n_tokens_neox': 1639, 'n_words': 421}