UNPKG

4.64 kBJavaScriptView Raw
1(function() {
2 "use strict";
3
4 var typeOf = require('remedial').typeOf;
5 var uniqId = require('uniqid');
6 var trimWhitespace = require('remove-trailing-spaces');
7 var commentExp = /^#comment/;
8 var emptyLineExp = /^#emptyLine/;
9 var lineCommentExp = /#comment::/;
10
11 function stringify(data) {
12 var handlers, indentLevel = '';
13
14 handlers = {
15 "undefined": function() {
16 // objects will not have `undefined` converted to `null`
17 // as this may have unintended consequences
18 // For arrays, however, this behavior seems appropriate
19 return 'null';
20 },
21 "null": function() {
22 return 'null';
23 },
24 "number": function(x) {
25 return x;
26 },
27 "boolean": function(x) {
28 return x ? 'true' : 'false';
29 },
30 "string": function(x) {
31 // to avoid the string "true" being confused with the
32 // the literal `true`, we always wrap strings in quotes
33
34 if(lineCommentExp.test(x)){
35 const [command, comment] = x.split(lineCommentExp.exec(x)[0]);
36 return `${JSON.stringify(command)} # ${comment}`;
37 }
38 return JSON.stringify(x);
39 },
40 "array": function(x) {
41 var output = '';
42
43 if (0 === x.length) {
44 output += '[]';
45 return output;
46 }
47
48 indentLevel = indentLevel.replace(/$/, ' ');
49 x.forEach(function(y, i) {
50 // TODO how should `undefined` be handled?
51
52 var handler = handlers[typeOf(y)];
53
54 if (!handler) {
55 throw new Error('what the crap: ' + typeOf(y));
56 }
57
58 output += '\n' + indentLevel + '- ' + handler(y, true);
59
60 });
61 indentLevel = indentLevel.replace(/ /, '');
62
63 return output;
64 },
65 "object": function(x, inArray, rootNode) {
66 var output = '';
67
68 if (0 === Object.keys(x).length) {
69 output += '{}';
70 return output;
71 }
72
73 if (!rootNode) {
74 indentLevel = indentLevel.replace(/$/, ' ');
75 }
76
77 Object.keys(x).forEach(function(k, i) {
78 var val = x[k],
79 handler = handlers[typeOf(val)];
80
81 if ('undefined' === typeof val) {
82 // the user should do
83 // delete obj.key
84 // and not
85 // obj.key = undefined
86 // but we'll error on the side of caution
87 return;
88 }
89
90 if (!handler) {
91 throw new Error('what the crap: ' + typeOf(val));
92 }
93
94
95 if (!(inArray && i === 0)) {
96 output += '\n' + indentLevel;
97 }
98
99 if (commentExp.test(k)) {
100 output += handlers['comment'](val);
101 } else if(emptyLineExp.test(k)){
102 output += handlers['emptyLine'](val);
103 } else {
104 output += k + ': ' + handler(val);
105 }
106 });
107 indentLevel = indentLevel.replace(/ /, '');
108
109 return output;
110 },
111 "function": function() {
112 // TODO this should throw or otherwise be ignored
113 return '[object Function]';
114 },
115 "comment": function(text) {
116 var output = '';
117
118 output += '# ' + text;
119 return output;
120 },
121 "emptyLine" : function(){
122 return '';
123 }
124 };
125
126 return trimWhitespace(handlers[typeOf(data)](data, true, true) + '\n');
127 }
128
129 function comment() {
130 const uniqComment = `#comment${uniqId()}`;
131 return uniqComment;
132 }
133
134 function lineComment(commentMessage){
135 return `#comment::${commentMessage}`
136 }
137
138 function emptyLine(){
139 return `#emptyLine${uniqId()}`
140 }
141
142 module.exports.emptyLine = emptyLine;
143 module.exports.lineComment = lineComment;
144 module.exports.comment = comment;
145 module.exports.stringify = stringify;
146}());