json2html.ts 5.15 KB
Newer Older
Zéfling's avatar
Zéfling committed
1

2
3
4
export interface Json2htmlAttr {
    [key: string]: string | number | null;
}
Zéfling's avatar
Zéfling committed
5

6
7
export type Json2htmlBody = (Json2htmlRef | string)[] | Json2htmlRef | string;

Zéfling's avatar
Zéfling committed
8
export interface Json2htmlRef {
9
10
    tag: string;
    attrs?: Json2htmlAttr;
11
    body?: Json2htmlBody;
Zéfling's avatar
Zéfling committed
12
13
14
}

export interface Json2htmlOptions {
Zéfling's avatar
Zéfling committed
15
    formatting?: 'inline' | 'multiline';
16
17
18
19
20
21
22
23
    spaceType?: 'space' | 'tab';
    spaceLength?: number;
    spaceBase?: number;
    maxLenght?: number;
    attrPosition?: 'inline' | 'space' | 'alignTag' | 'alignFirstAttr';
    // type?: 'html' | 'xml';
    indent?: boolean;
    noContentTags?: string[];
Zéfling's avatar
Zéfling committed
24
25
26
27
28
29
30
31
32
}

export class Json2html {

    readonly options: Json2htmlOptions = {
        spaceType: 'space',
        spaceLength: 4,
        spaceBase: 0,
        maxLenght: 0,
Zéfling's avatar
Zéfling committed
33
        attrPosition: 'alignFirstAttr',
34
        // type: 'html',
Zéfling's avatar
Zéfling committed
35
        formatting: 'multiline',
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
        indent: true,
        noContentTags: [
            'area',
            'base',
            'br',
            'col',
            'command',
            'embed',
            'hr',
            'img',
            'input',
            'keygen',
            'link',
            'meta',
            'param',
            'source',
            'track',
            'wbr'
        ]
    };
Zéfling's avatar
Zéfling committed
56
57

    constructor(
58
        public json: Json2htmlRef | Json2htmlRef[],
Zéfling's avatar
Zéfling committed
59
60
61
62
63
64
        option: Json2htmlOptions = {}
    ) {
        Object.assign(this.options, option);
    }

    toString() {
65
66
67
68
69
70
71
72
73
        let html = '';
        if (!Array.isArray(this.json)) {
            html = `${this._getSpacing(0)}${this._generate(0, this.json)}`;
        } else {
            this.json.forEach((element, index) => {
                html += `${index > 0 ? '\n' : ''}${this._getSpacing(0)}${this._generate(0, element)}`;
            });
        }
        return html;
Zéfling's avatar
Zéfling committed
74
75
76
    }

    private _generate(lvl: number, json: Json2htmlRef) {
77
78
79
        const hasContent = !this.options.noContentTags.includes(json.tag.toLowerCase());
        let string = `<${json.tag}${this._generateAttrs(lvl, json)}>`;
        if (hasContent) {
80
            let tagcontent = this._generateBody(lvl, json);
81
            if (tagcontent && this._hasMultiline()) {
Zéfling's avatar
Zéfling committed
82
83
                tagcontent = `${tagcontent}\n${this._getSpacing(lvl)}`;
            }
84
            string += `${tagcontent}</${json.tag}>`;
Zéfling's avatar
Zéfling committed
85
        }
86
        return string;
Zéfling's avatar
Zéfling committed
87
88
89
90
    }

    private _generateAttrs(lvl: number, json: Json2htmlRef) {
        let string = '';
91
        const attrs = json.attrs;
Zéfling's avatar
Zéfling committed
92
93
94
95
        if (attrs && Object.keys(attrs).length) {
            for (const id in attrs) {
                if (attrs[id] !== undefined) {
                    let attr = '';
96
97
                    switch (this.options.attrPosition) {
                        case 'inline':
Zéfling's avatar
Zéfling committed
98
                            attr += ' ';
99
100
                            break;
                        case 'space':
Zéfling's avatar
Zéfling committed
101
                            attr += string && this.options.indent && this._hasMultiline()
102
103
104
105
                                ? `\n${this._getSpacing(lvl + 1)}`
                                : string += ' ';
                            break;
                        case 'alignTag':
Zéfling's avatar
Zéfling committed
106
                            attr += string && this.options.indent && this._hasMultiline()
107
108
109
110
                                ? `\n${this._getSpacing(lvl, 1)}`
                                : ' ';
                            break;
                        case 'alignFirstAttr':
Zéfling's avatar
Zéfling committed
111
112
                            attr += string && this.options.indent && this._hasMultiline()
                                ? `\n${this._getSpacing(lvl, json.tag.length + 2)}`
113
114
115
                                : ' ';
                            break;
                    }
Zéfling's avatar
Zéfling committed
116
117
                    attr += `${id}${attrs[id] !== null || attrs[id] ? `="${attrs[id]}"` : ''}`;
                    string += attr;
Zéfling's avatar
Zéfling committed
118
119
120
121
122
123
                }
            }
        }
        return string;
    }

124
    private _generateBody(lvl: number, json: Json2htmlRef) {
Zéfling's avatar
Zéfling committed
125
126
127
        let string = '';
        if (json.body) {
            if (typeof json.body === 'string') {
Zéfling's avatar
Zéfling committed
128
129
130
                if (this._hasMultiline()) {
                    string = `\n${this._getSpacing(lvl + 1)}`;
                }
Zéfling's avatar
Zéfling committed
131
                string += json.body;
132
133
            } else if (!Array.isArray(json.body)) {
                string += this._generateBodyElement(lvl, json);
Zéfling's avatar
Zéfling committed
134
            } else {
135
136
                json.body.forEach(element => {
                    string += this._generateBodyElement(lvl, element);
137
                });
Zéfling's avatar
Zéfling committed
138
139
140
141
142
            }
        }
        return string;
    }

143
144
145
146
147
148
149
150
151
152
153
    private _generateBodyElement(lvl: number, element: Json2htmlRef | string): string {
        let string = '';
        if (this._hasMultiline()) {
            string += `\n${this._getSpacing(lvl + 1)}`;
        }
        string += typeof element === 'string'
            ? element
            : this._generate(lvl + 1, element);
        return string;
    }

Zéfling's avatar
Zéfling committed
154
155
156
157
158
159
160
161
162
163
164
    private _hasMultiline(): boolean {
        return this.options.formatting === 'multiline';
    }

    private _getSpacing(lvl: number, ajout: number = 0): string {
        return this.options.indent
            ? (this.options.spaceType === 'space' ? ' ' : '\t')
                .repeat((lvl + this.options.spaceBase) * this.options.spaceLength + ajout)
            : '';
    }

Zéfling's avatar
Zéfling committed
165
}