-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathrepl.js
135 lines (113 loc) · 3.7 KB
/
repl.js
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
'use strict';
const repl = require('repl');
const replHistory = require('./history');
const LoopbackRepl = module.exports = {
start(ctx) {
const config = Object.assign({}, ctx.config);
const replServer = repl.start(config);
Object.assign(replServer.context, ctx.handles);
replServer.eval = wrapReplEval(replServer);
if (ctx.handles.cb === true) {
replServer.context.result = undefined;
replServer.context.cb = (err, result) => {
replServer.context.err = err;
replServer.context.result = result;
if (err) {
console.error('Error: ' + err);
}
if (!config.quiet) {
console.log(result);
}
};
}
replServer.defineCommand('usage', {
help: 'Detailed Loopback Console usage information',
action() {
this.outputStream.write(LoopbackRepl.usage(ctx, true));
this.displayPrompt();
},
});
replServer.defineCommand('models', {
help: 'Display available Loopback models',
action() {
this.outputStream.write(Object.keys(ctx.models).join(', ') + '\n');
this.displayPrompt();
},
});
replServer.on('exit', function() {
if (replServer._flushing) {
replServer.pause();
return replServer.once('flushHistory', function() {
process.exit();
});
}
process.exit();
});
return replHistory(replServer, config.historyPath).then(() => replServer);
},
usage(ctx, details) {
const modelHandleNames = Object.keys(ctx.models);
const customHandleNames = Object.keys(ctx.handles).filter(k => {
return !ctx.handleInfo[k] && !ctx.models[k];
});
let usage =
'============================================\n' +
'Loopback Console\n\n' +
'Primary handles available:\n';
Object.keys(ctx.handleInfo).forEach(key => {
usage += ` - ${key}: ${ctx.handleInfo[key]}\n`;
});
if (modelHandleNames.length > 0 || ctx.customHandleNames.length > 0) {
usage += '\nOther handles available:\n';
}
if (modelHandleNames.length > 0) {
usage += ` - Models: ${ modelHandleNames.join(', ') }\n`;
}
if (customHandleNames.length > 0) {
usage += ` - Custom: ${ customHandleNames.join(',') }\n`;
}
if (details) {
usage +=
'\nExamples:\n' +
ctx.config.prompt +
'myUser = User.findOne({ where: { username: \'heath\' })\n' +
ctx.config.prompt +
'myUser.updateAttribute(\'fullName\', \'Heath Morrison\')\n' +
ctx.config.prompt +
'myUser.widgets.add({ ... })\n\n';
}
usage += '============================================\n\n';
return usage;
},
};
// Wrap the default eval with a handler that resolves promises
function wrapReplEval(replServer) {
const defaultEval = replServer.eval;
return function(code, context, file, cb) {
return defaultEval.call(this, code, context, file, (err, result) => {
if (!result || !result.then) {
return cb(err, result);
}
result.then(resolved => {
resolvePromises(result, resolved);
cb(null, resolved);
}).catch(err => {
resolvePromises(result, err);
console.log('\x1b[31m' + '[Promise Rejection]' + '\x1b[0m');
if (err && err.message) {
console.log('\x1b[31m' + err.message + '\x1b[0m');
}
// Application errors are not REPL errors
cb(null, err);
});
});
function resolvePromises(promise, resolved) {
Object.keys(context).forEach(key => {
// Replace any promise handles in the REPL context with the resolved promise
if (context[key] === promise) {
context[key] = resolved;
}
});
}
};
}