<commit_before>import React, { Component, createElement } from 'react';
import { observable, action, computed, reaction } from 'mobx';
import * as Validator from 'validatorjs';


import { fieldDefinition, normalizesdFieldDefinition, formSchema, normalizedFormSchema } from './interface';

import { ReactiveMobxFormField } from './Field';

export class ReactiveMobxForm {
	formSchema: normalizedFormSchema;
	
	component: any;

	@observable fields: Array<ReactiveMobxFormField> = [];
	@observable errors: Validator.Errors;
	@observable isValid: boolean | void;

	@observable submitting: boolean = false;
	@observable validating: boolean = false;
	@observable submissionError: string = '';

	// computed
	/*
	hasErrors
	isValid
	isDirty
	isPristine
	isDefault
	isEmpty
	isFocused
	isToucehd
	isChanged
	error
	*/

	static normalizeSchema(formSchema:formSchema):normalizedFormSchema {
		const normalized = {};

		Object.keys(formSchema).map(fieldName => {
			normalized[fieldName] = ReactiveMobxFormField.normalizeFieldDefinition(formSchema[fieldName])
		});

		return normalized;
	}

	constructor(formSchema) {
		this.formSchema = ReactiveMobxForm.normalizeSchema(formSchema);
	}

	@computed get isDirty() {
		return this.fields.some(field => field.isDirty);
	}

	// todo: on for initialize values are recomputed -> this cause validation to recompute, may be inefficient
	@computed get validation() {
		return new Validator(this.values, this.rules);
	}

	// todo: values are recomputed each time field is registered, think if this is good begavior for form initialization
	@computed get values() {
		return this.fields.reduce((values:any, field) => {
			values[field.name] = field.value;
			return values;
		}, {});
	}

	@computed get rules() {
		const rules = {};

		Object.keys(this.formSchema).forEach((fieldName) => {
			if (this.formSchema[fieldName][1]) {
				rules[fieldName] = this.formSchema[fieldName][1];
			}
		});

		return rules;
	}

	// todo: may be use transaction to make values recompute once
	@action registerField(fieldName:string) {
		let field = this.fields.find(field => field.name === fieldName);

		if (!field) {
			this.fields.push(new ReactiveMobxFormField(fieldName, this.formSchema[fieldName]));
			field = this.fields[this.fields.length - 1];
		}

		return field;
	}

	@action removeField(fieldName:string) {
		const fieldIdx = this.fields.findIndex(field => field.name === fieldName);

		this.fields.splice(fieldIdx, 1);
		// todo: delete field from schema also ????
	}

	@action extendSchema(schemaExtension:formSchema) {
		// todo: Probably ist good to have some safe extension
		const normalizeSchemaExtension = ReactiveMobxForm.normalizeSchema(schemaExtension);
		
		Object.assign(this.formSchema, normalizeSchemaExtension);
	}

	@action reset() {
		this.fields.forEach(field => {
			field.value = field.initialValue;
		})
	}

	registerValidation() {		
		reaction(
			() => this.validation,
			() => {
				this.isValid = this.validation.passes();
				this.errors = this.validation.errors;
			}
		)<commit_msg>Rewrite values collection function to use .reduce instead of for loop<commit_after>import React, { Component, createElement } from 'react';
import { observable, action, computed, reaction } from 'mobx';
import * as Validator from 'validatorjs';


import { fieldDefinition, normalizesdFieldDefinition, formSchema, normalizedFormSchema } from './interface';

import { ReactiveMobxFormField } from './Field';

export class ReactiveMobxForm {
	formSchema: normalizedFormSchema;
	
	component: any;

	@observable fields: Array<ReactiveMobxFormField> = [];
	@observable errors: Validator.Errors;
	@observable isValid: boolean | void;

	@observable submitting: boolean = false;
	@observable validating: boolean = false;
	@observable submissionError: string = '';

	// computed
	/*
	hasErrors
	isValid
	isDirty
	isPristine
	isDefault
	isEmpty
	isFocused
	isToucehd
	isChanged
	error
	*/

	static normalizeSchema(formSchema:formSchema):normalizedFormSchema {
		const normalized = {};

		Object.keys(formSchema).map(fieldName => {
			normalized[fieldName] = ReactiveMobxFormField.normalizeFieldDefinition(formSchema[fieldName])
		});

		return normalized;
	}

	constructor(formSchema) {
		this.formSchema = ReactiveMobxForm.normalizeSchema(formSchema);
	}

	@computed get isDirty() {
		return this.fields.some(field => field.isDirty);
	}

	// todo: on for initialize values are recomputed -> this cause validation to recompute, may be inefficient
	@computed get validation() {
		return new Validator(this.values, this.rules);
	}

	// todo: values are recomputed each time field is registered, think if this is good begavior for form initialization
	@computed get values() {
		return this.fields.reduce((values:any, field) => Object.assign(values, {[field.name]:field.value}), {});
	}

	@computed get rules() {
		return Object.keys(this.formSchema).reduce((rules: any, fieldName) => {
			const rule = this.formSchema[fieldName][1];
			return Object.assign(rules, rule ? {[fieldName]: rule} : {});
		}, {});
	}

	// todo: may be use transaction to make values recompute once
	@action registerField(fieldName:string) {
		let field = this.fields.find(field => field.name === fieldName);

		if (!field) {
			this.fields.push(new ReactiveMobxFormField(fieldName, this.formSchema[fieldName]));
			field = this.fields[this.fields.length - 1];
		}

		return field;
	}

	@action removeField(fieldName:string) {
		const fieldIdx = this.fields.findIndex(field => field.name === fieldName);

		this.fields.splice(fieldIdx, 1);
		// todo: delete field from schema also ????
	}

	@action extendSchema(schemaExtension:formSchema) {
		// todo: Probably ist good to have some safe extension
		const normalizeSchemaExtension = ReactiveMobxForm.normalizeSchema(schemaExtension);
		
		Object.assign(this.formSchema, normalizeSchemaExtension);
	}

	@action reset() {
		this.fields.forEach(field => {
			field.value = field.initialValue;
		});
	}

	registerValidation() {
		reaction(
			() => this.validation,
			() => {
				this.isValid = this.validation.passes();
				this.errors = this.validation.errors;
			}
		)
{'fraction_non_alphanumeric': 0.12101910828025478, 'fraction_numerical': 0.0011432304425935, 'mean_word_length': 4.572338489535942, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 25, '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': '4062119', 'n_tokens_mistral': 2032, 'n_tokens_neox': 1851, 'n_words': 447}