<commit_before>/*
 * Squidex Headless CMS
 *
 * @license
 * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
 */

// tslint:disable:no-shadowed-variable

import { Component, OnDestroy, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { Subscription } from 'rxjs';
import { filter, map, onErrorResumeNext } from 'rxjs/operators';

import {
    AppsState,
    fadeAnimation,
    FieldDto,
    fieldTypes,
    MessageBus,
    ModalView,
    PatternsState,
    SchemaDetailsDto,
    SchemasState,
    Types
} from '@app/shared';

import {
    SchemaCloning
} from './../messages';

@Component({
    selector: 'sqx-schema-page',
    styleUrls: ['./schema-page.component.scss'],
    templateUrl: './schema-page.component.html',
    animations: [
        fadeAnimation
    ]
})
export class SchemaPageComponent implements OnDestroy, OnInit {
    private selectedSchemaSubscription: Subscription;

    public fieldTypes = fieldTypes;

    public schemaExport: any;
    public schema: SchemaDetailsDto;

    public exportSchemaDialog = new ModalView();

    public configureScriptsDialog = new ModalView();

    public editOptionsDropdown = new ModalView();
    public editSchemaDialog = new ModalView();

    public addFieldDialog = new ModalView();

    constructor(
        public readonly appsState: AppsState,
        public readonly schemasState: SchemasState,
        public readonly patternsState: PatternsState,
        private readonly route: ActivatedRoute,
        private readonly router: Router,
        private readonly messageBus: MessageBus
    ) {
    }

    public ngOnDestroy() {
        this.selectedSchemaSubscription.unsubscribe();
    }

    public ngOnInit() {
        this.patternsState.load().pipe(onErrorResumeNext()).subscribe();

        this.selectedSchemaSubscription =
            this.schemasState.selectedSchema.pipe(filter(s => !!s), map(s => s!))
                .subscribe(schema => {
                    this.schema = schema;

                    this.export();
                });
    }

    public publish() {
        this.schemasState.publish(this.schema).subscribe();
    }

    public unpublish() {
        this.schemasState.unpublish(this.schema).subscribe();
    }

    public sortFields(fields: FieldDto[]) {
        this.schemasState.sortFields(this.schema, fields).subscribe();
    }

    public trackByField(index: number, field: FieldDto) {
        return field.fieldId;
    }

    public deleteSchema() {
        this.schemasState.delete(this.schema)
            .subscribe(() => {
                this.back();
            });
    }

    public cloneSchema() {
        this.messageBus.emit(new SchemaCloning(this.schemaExport));
    }

    private export() {
        const result: any = {
            fields: this.schema.fields.map(field => {
                const { fieldId, ...copy } = field;

                if (Types.isArray(copy.nested)) {
                    for (let i = 0; i < copy.nested.length; i++) {
                        const nestedField = copy.nested[i];
                        const { fieldId, parentId, ...nestedCopy } = nestedField;

                        for (const key in nestedCopy.properties) {
                            if (nestedCopy.properties.hasOwnProperty(key) &&
                               !nestedCopy.properties[key]) {
                                delete copy.properties[key];
                            }
                        }

                        copy.nested[i] = <any>nestedCopy;
                    }
                }

                for (const key in copy.properties) {
                    if (copy.properties.hasOwnProperty(key) &&
                       !copy.properties[key]) {
                        delete copy.properties[key];
                    }
                }

                return copy;
            }),
            properties: {}
        };

        if (this.schema.properties.label) {
            result.properties.label = this.schema.properties.label;
        }

        if (this.schema.properties.hints) {
            result.properties.hints = this.schema.properties.hints;
        }
<commit_msg>Improve schema export.<commit_after>/*
 * Squidex Headless CMS
 *
 * @license
 * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
 */

// tslint:disable:no-shadowed-variable

import { Component, OnDestroy, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { Subscription } from 'rxjs';
import { filter, map, onErrorResumeNext } from 'rxjs/operators';

import {
    AppsState,
    fadeAnimation,
    FieldDto,
    fieldTypes,
    MessageBus,
    ModalView,
    PatternsState,
    SchemaDetailsDto,
    SchemasState,
    Types
} from '@app/shared';

import {
    SchemaCloning
} from './../messages';

@Component({
    selector: 'sqx-schema-page',
    styleUrls: ['./schema-page.component.scss'],
    templateUrl: './schema-page.component.html',
    animations: [
        fadeAnimation
    ]
})
export class SchemaPageComponent implements OnDestroy, OnInit {
    private selectedSchemaSubscription: Subscription;

    public fieldTypes = fieldTypes;

    public schemaExport: any;
    public schema: SchemaDetailsDto;

    public exportSchemaDialog = new ModalView();

    public configureScriptsDialog = new ModalView();

    public editOptionsDropdown = new ModalView();
    public editSchemaDialog = new ModalView();

    public addFieldDialog = new ModalView();

    constructor(
        public readonly appsState: AppsState,
        public readonly schemasState: SchemasState,
        public readonly patternsState: PatternsState,
        private readonly route: ActivatedRoute,
        private readonly router: Router,
        private readonly messageBus: MessageBus
    ) {
    }

    public ngOnDestroy() {
        this.selectedSchemaSubscription.unsubscribe();
    }

    public ngOnInit() {
        this.patternsState.load().pipe(onErrorResumeNext()).subscribe();

        this.selectedSchemaSubscription =
            this.schemasState.selectedSchema.pipe(filter(s => !!s), map(s => s!))
                .subscribe(schema => {
                    this.schema = schema;

                    this.export();
                });
    }

    public publish() {
        this.schemasState.publish(this.schema).subscribe();
    }

    public unpublish() {
        this.schemasState.unpublish(this.schema).subscribe();
    }

    public sortFields(fields: FieldDto[]) {
        this.schemasState.sortFields(this.schema, fields).subscribe();
    }

    public trackByField(index: number, field: FieldDto) {
        return field.fieldId;
    }

    public deleteSchema() {
        this.schemasState.delete(this.schema)
            .subscribe(() => {
                this.back();
            });
    }

    public cloneSchema() {
        this.messageBus.emit(new SchemaCloning(this.schemaExport));
    }

    private export() {
        const cleanup = (source: any, ...exclude: string[]): any => {
            const clone = {};

            for (const key in source) {
                if (source.hasOwnProperty(key) && exclude.indexOf(key) < 0) {
                    const value = source[key];

                    if (value) {
                        clone[key] = value;
                    }
                }
            }

            return clone;
        };

        const result: any = {
            fields: this.schema.fields.map(field => {
                const copy = cleanup(field, 'fieldId');

                if (Types.isArray(copy.nested)) {
                    if (copy.nested.length === 0) {
                        delete copy['nested'];
                    } else {
                        for (let i = 0; i < copy.nested.length; i++) {
                            const nestedField = copy.nested[i];
                            const nestedCopy = cleanup(nestedField, 'fieldId', 'parentId');

                            nestedCopy.properties = cleanup(nestedField.properties);

                            copy.nested[i] = nestedCopy;
                        }
                    }
                }

                copy.properties = cleanup(field.properties);

                return copy;
            }),
            properties: cleanup(this.schema.properties)
        };

{'fraction_non_alphanumeric': 0.10906040268456375, 'fraction_numerical': 0.00047938638542665386, 'mean_word_length': 1.866712469941601, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 15, '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': '6036781', 'n_tokens_mistral': 2247, 'n_tokens_neox': 2146, 'n_words': 466}