This repository was archived by the owner on Oct 14, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 141
Expand file tree
/
Copy pathdisplay.js
More file actions
254 lines (221 loc) · 7.2 KB
/
Copy pathdisplay.js
File metadata and controls
254 lines (221 loc) · 7.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
var util = require('util'),
isEqual = require('underscore').isEqual,
display = module.exports;
// prevent anyone from peeking at the code we passed in
if (global.process) {
global.process.execArgv = null;
global.process._eval = null;
global.process.exit = function() {
};
Object.defineProperty(global.process, "_eval", {
writable: false,
configurable: false,
value: "Don't cheat :)"
});
}
function combineMessages(msgs, separator) {
return msgs.filter(function(m) {
return m != null;
}).join(separator);
}
/**
* Utility method for formatting messages.
* @param {function|string|array} msg If a function msg will be evaluated. If an array is provided
* then all values will be combined with a - between them, with null values filtered out.
* @param {string} prefix If prefix is provided it will be prepended with a - character for readability
*/
module.exports.message = function message(msg, prefix) {
if (typeof msg == 'function') {
msg = msg();
}
else if (Array.isArray(msg)) {
msg = combineMessages(msg, ' - ');
}
msg = prefix ? (prefix + ' - ' + msg) : msg;
return msg || '';
};
/**
* Base method for writing custom output tokens.
*/
module.exports.write = function write(type, msg, opts) {
opts = opts || {};
var mode = (opts.mode || "").toUpperCase();
var label = (opts.label || "");
if (opts.mode == 'JSON') {
msg = JSON.stringify(msg);
}
msg = display.format(display.message(msg));
console.log("\n<" + type.toUpperCase() + ":" + mode + ":" + label + ">" + msg);
};
/**
* Convenience method so that you dont have to write display.write("LOG", msg, opts) but instead display.log(msg, opts)
*/
module.exports.log = function(msg, opts) {
display.write("LOG", msg, opts);
};
/**
* Convenience method so that you dont have to write display.write("TAB", msg, opts) but instead display.tab(label, msg, mode)
*/
module.exports.tab = function tab(label, msg, mode) {
display.write("TAB", msg, {label: label || "???", mode: mode});
};
/**
* Convenience method for rendering the passed in object as JSON
* @param obj
* @param label
*/
module.exports.json = function json(obj, label, tab) {
display.write(tab ? 'TAB' : 'LOG', obj, {label: label, mode: 'JSON'});
};
/**
* Writes a propertly to the last displayed token
*/
module.exports.prop = function prop(name, value) {
display.write("PROP", value, {label: name});
};
/**
* renders an inspection of the object passed in. Similar to console.dir but allows the ability
* to add a label and set as a tab
* @param {object} obj Object to be inspected
* @param {string} label optional label
* @param {boolean} tab optional if it should be rendered as a tab
*/
module.exports.inspect = function inspect(obj, label, tab) {
display.write(tab ? "TAB" : "LOG", util.inspect(obj), {label: label});
};
/**
* formats an value to be outputted. If a function is provided then it will be evaluated,
* if an object is provided then it will JSONfied. By default
* any line breaks will be replaced with <:BR:> so that the entire message is considered
* one group of data.
*/
module.exports.format = function format(obj, options) {
options = options || {};
var out = '';
if (typeof obj == 'string') {
out = obj;
}
else if (typeof obj == 'function') {
out = obj.toString();
}
else if (obj && obj !== true) {
// for backwards compatibility we will support the indent option
if (options.indent || options.json) {
out = global.Test.stringify(obj, options.indent ? 4 : 0);
}
else {
out = util.inspect(obj, options);
}
}
else {
out = ('' + obj);
}
// replace linebreaks with LF so that they can be converted back to line breaks later. Otherwise
// the linebreak will be treated as a new data item.
return out.replace(/\n/g, '<:LF:>');
};
/**
* Simple HTML escape functionality.
*/
module.exports.escapeHtml = function escapeHtml(html) {
return String(html)
.replace(/&/g, '&')
.replace(/"/g, '"')
.replace(/'/g, ''')
.replace(/</g, '<')
.replace(/>/g, '>');
};
/**
* Renders a set of tabs explaining the difference between two JSON values.
* @param expected
* @param actual
* @param collapsed
*/
module.exports.explainJson = function explainJson(actual, expected, collapsed) {
display.explain(actual, expected, {collapsed: collapsed, mode: 'JSON'});
};
/**
* Renders a set of tabs, with an optional diff tab if the values are actually different
* @param actual
* @param expected
* @param options
*/
module.exports.explain = function explain(actual, expected, options) {
// allow true to be passed in as a shortcut to setting collapsed
if (options === true || options === false) {
options = {collapsed: options};
}
options = options || {};
var collapsed = options.collapsed ? "-" : "",
diff = true;
if (options.mode) {
if (typeof(options.mode) == 'string') {
options.mode = options.mode.toUpperCase();
}
// if mode is not a string, then its expected to be an explain boolean and we can throw it away.
// doing this allows us to have pass mode strings as explain values within wrapping functions.
// see cw-2.js Test.assertEquals
else {
options.mode = null;
}
}
options.mode = options.mode;
if (options.mode == 'JSON') {
diff = actual && expected;
// if (typeof(actual) != 'string') {
// actual = JSON.stringify(actual);
// }
//
// if (typeof(expected) != 'string') {
// expected = JSON.stringify(expected);
// }
diff = diff && actual != expected;
}
// string mode is a special mode for this method which just means inspect as direct strings
else if (options.mode == 'STRING') {
options.mode = null;
actual = actual ? actual.toString() : actual;
expected = expected ? expected.toString() : expected;
diff = expected != actual && actual && expected;
}
else {
diff = !(actual && expected && isEqual(actual, expected));
expected = util.inspect(expected);
actual = util.inspect(actual);
}
// if collapsed is not specifically set, then we will only collapse if values are equal by default
if (collapsed == null || collapsed == undefined) {
collapsed = !diff;
}
display.log(expected, {label: collapsed + "Expected", mode: options.mode});
// allows you to setup a special class for a log container
if (options.className) {
display.prop("className", options.className);
}
display.tab("Actual", actual, options.mode);
if (diff) {
display.tab("Diff", "", "DIFF");
}
if (options.arguments) {
var details = "";
options.arguments.forEach(function(v, i) {
if (i > 0) details += "\n\n";
details += "<label>Argument " + i + ":</label>\n";
details += util.inspect(v);
});
display.tab("Arguments", details);
display.prop("className", "inspection");
}
if (options.context) {
display.tab("Context", util.inspect(options.context));
}
if (options.swap) display.write("SWAP");
};
module.exports.getPackages = function() {
var buffer = require('child_process').execSync('npm ls --json');
return JSON.parse(buffer.toString());
};
module.exports.availablePackages = function(label) {
var packages = display.getPackages();
display.json(packages, label);
};