• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

json5 / json5 / 473

pending completion
473

push

travis-ci-com

jordanbtucker
1.0.2

388 of 388 branches covered (100.0%)

Branch coverage included in aggregate %.

614 of 614 relevant lines covered (100.0%)

144.69 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

100.0
/src/stringify.js
1
import * as util from './util'
2

3
export default function stringify (value, replacer, space) {
4
    const stack = []
201✔
5
    let indent = ''
201✔
6
    let propertyList
7
    let replacerFunc
8
    let gap = ''
201✔
9
    let quote
10

11
    if (
201✔
12
        replacer != null &&
258✔
13
        typeof replacer === 'object' &&
14
        !Array.isArray(replacer)
15
    ) {
16
        space = replacer.space
12✔
17
        quote = replacer.quote
12✔
18
        replacer = replacer.replacer
12✔
19
    }
20

21
    if (typeof replacer === 'function') {
201✔
22
        replacerFunc = replacer
15✔
23
    } else if (Array.isArray(replacer)) {
186✔
24
        propertyList = []
12✔
25
        for (const v of replacer) {
12✔
26
            let item
27

28
            if (typeof v === 'string') {
27✔
29
                item = v
9✔
30
            } else if (
18✔
31
                typeof v === 'number' ||
33✔
32
                v instanceof String ||
33
                v instanceof Number
34
            ) {
35
                item = String(v)
15✔
36
            }
37

38
            if (item !== undefined && propertyList.indexOf(item) < 0) {
27✔
39
                propertyList.push(item)
24✔
40
            }
41
        }
42
    }
43

44
    if (space instanceof Number) {
201✔
45
        space = Number(space)
3✔
46
    } else if (space instanceof String) {
198✔
47
        space = String(space)
3✔
48
    }
49

50
    if (typeof space === 'number') {
201✔
51
        if (space > 0) {
36✔
52
            space = Math.min(10, Math.floor(space))
33✔
53
            gap = '          '.substr(0, space)
33✔
54
        }
55
    } else if (typeof space === 'string') {
165✔
56
        gap = space.substr(0, 10)
12✔
57
    }
58

59
    return serializeProperty('', {'': value})
201✔
60

61
    function serializeProperty (key, holder) {
62
        let value = holder[key]
423✔
63
        if (value != null) {
423✔
64
            if (typeof value.toJSON5 === 'function') {
420✔
65
                value = value.toJSON5(key)
15✔
66
            } else if (typeof value.toJSON === 'function') {
405✔
67
                value = value.toJSON(key)
15✔
68
            }
69
        }
70

71
        if (replacerFunc) {
423✔
72
            value = replacerFunc.call(holder, key, value)
42✔
73
        }
74

75
        if (value instanceof Number) {
423✔
76
            value = Number(value)
3✔
77
        } else if (value instanceof String) {
420✔
78
            value = String(value)
3✔
79
        } else if (value instanceof Boolean) {
417✔
80
            value = value.valueOf()
6✔
81
        }
82

83
        switch (value) {
423✔
84
        case null: return 'null'
3✔
85
        case true: return 'true'
6✔
86
        case false: return 'false'
6✔
87
        }
88

89
        if (typeof value === 'string') {
408✔
90
            return quoteString(value, false)
30✔
91
        }
92

93
        if (typeof value === 'number') {
378✔
94
            return String(value)
195✔
95
        }
96

97
        if (typeof value === 'object') {
183✔
98
            return Array.isArray(value) ? serializeArray(value) : serializeObject(value)
174✔
99
        }
100

101
        return undefined
9✔
102
    }
103

104
    function quoteString (value) {
105
        const quotes = {
60✔
106
            "'": 0.1,
107
            '"': 0.2,
108
        }
109

110
        const replacements = {
60✔
111
            "'": "\\'",
112
            '"': '\\"',
113
            '\\': '\\\\',
114
            '\b': '\\b',
115
            '\f': '\\f',
116
            '\n': '\\n',
117
            '\r': '\\r',
118
            '\t': '\\t',
119
            '\v': '\\v',
120
            '\0': '\\0',
121
            '\u2028': '\\u2028',
122
            '\u2029': '\\u2029',
123
        }
124

125
        let product = ''
60✔
126

127
        for (const c of value) {
60✔
128
            switch (c) {
228✔
129
            case "'":
130
            case '"':
131
                quotes[c]++
33✔
132
                product += c
33✔
133
                continue
33✔
134
            }
135

136
            if (replacements[c]) {
195✔
137
                product += replacements[c]
54✔
138
                continue
54✔
139
            }
140

141
            if (c < ' ') {
141✔
142
                let hexString = c.charCodeAt(0).toString(16)
6✔
143
                product += '\\x' + ('00' + hexString).substring(hexString.length)
6✔
144
                continue
6✔
145
            }
146

147
            product += c
135✔
148
        }
149

150
        const quoteChar = quote || Object.keys(quotes).reduce((a, b) => (quotes[a] < quotes[b]) ? a : b)
60✔
151

152
        product = product.replace(new RegExp(quoteChar, 'g'), replacements[quoteChar])
60✔
153

154
        return quoteChar + product + quoteChar
60✔
155
    }
156

157
    function serializeObject (value) {
158
        if (stack.indexOf(value) >= 0) {
108✔
159
            throw TypeError('Converting circular structure to JSON5')
3✔
160
        }
161

162
        stack.push(value)
105✔
163

164
        let stepback = indent
105✔
165
        indent = indent + gap
105✔
166

167
        let keys = propertyList || Object.keys(value)
105✔
168
        let partial = []
105✔
169
        for (const key of keys) {
105✔
170
            const propertyString = serializeProperty(key, value)
141✔
171
            if (propertyString !== undefined) {
138✔
172
                let member = serializeKey(key) + ':'
135✔
173
                if (gap !== '') {
135✔
174
                    member += ' '
12✔
175
                }
176
                member += propertyString
135✔
177
                partial.push(member)
135✔
178
            }
179
        }
180

181
        let final
182
        if (partial.length === 0) {
102✔
183
            final = '{}'
12✔
184
        } else {
185
            let properties
186
            if (gap === '') {
90✔
187
                properties = partial.join(',')
78✔
188
                final = '{' + properties + '}'
78✔
189
            } else {
190
                let separator = ',\n' + indent
12✔
191
                properties = partial.join(separator)
12✔
192
                final = '{\n' + indent + properties + ',\n' + stepback + '}'
12✔
193
            }
194
        }
195

196
        stack.pop()
102✔
197
        indent = stepback
102✔
198
        return final
102✔
199
    }
200

201
    function serializeKey (key) {
202
        if (key.length === 0) {
135✔
203
            return quoteString(key, true)
3✔
204
        }
205

206
        const firstChar = String.fromCodePoint(key.codePointAt(0))
132✔
207
        if (!util.isIdStartChar(firstChar)) {
132✔
208
            return quoteString(key, true)
15✔
209
        }
210

211
        for (let i = firstChar.length; i < key.length; i++) {
117✔
212
            if (!util.isIdContinueChar(String.fromCodePoint(key.codePointAt(i)))) {
51✔
213
                return quoteString(key, true)
12✔
214
            }
215
        }
216

217
        return key
105✔
218
    }
219

220
    function serializeArray (value) {
221
        if (stack.indexOf(value) >= 0) {
66✔
222
            throw TypeError('Converting circular structure to JSON5')
3✔
223
        }
224

225
        stack.push(value)
63✔
226

227
        let stepback = indent
63✔
228
        indent = indent + gap
63✔
229

230
        let partial = []
63✔
231
        for (let i = 0; i < value.length; i++) {
63✔
232
            const propertyString = serializeProperty(String(i), value)
81✔
233
            partial.push((propertyString !== undefined) ? propertyString : 'null')
78✔
234
        }
235

236
        let final
237
        if (partial.length === 0) {
60✔
238
            final = '[]'
3✔
239
        } else {
240
            if (gap === '') {
57✔
241
                let properties = partial.join(',')
27✔
242
                final = '[' + properties + ']'
27✔
243
            } else {
244
                let separator = ',\n' + indent
30✔
245
                let properties = partial.join(separator)
30✔
246
                final = '[\n' + indent + properties + ',\n' + stepback + ']'
30✔
247
            }
248
        }
249

250
        stack.pop()
60✔
251
        indent = stepback
60✔
252
        return final
60✔
253
    }
254
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc