jsforce
Version:
Salesforce API Library for JavaScript
363 lines (362 loc) • 11.5 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Repl = void 0;
/**
* @file Creates REPL interface with built in Salesforce API objects and automatically resolves promise object
* @author Shinichi Tomita <shinichi.tomita@gmail.com>
* @private
*/
const events_1 = require("events");
const repl_1 = require("repl");
const stream_1 = require("stream");
const __1 = __importDefault(require(".."));
const function_1 = require("../util/function");
/**
* Intercept the evaled value returned from repl evaluator, convert and send back to output.
* @private
*/
function injectBefore(replServer, method, beforeFn) {
const _orig = replServer[method];
replServer[method] = (...args) => {
const callback = args.pop();
beforeFn(...args.concat((err, res) => {
if (err || res) {
callback(err, res);
}
else {
_orig.apply(replServer, args.concat(callback));
}
}));
};
return replServer;
}
/**
* @private
*/
function injectAfter(replServer, method, afterFn) {
const _orig = replServer[method];
replServer[method] = (...args) => {
const callback = args.pop();
_orig.apply(replServer, args.concat((...args) => {
try {
afterFn(...args.concat(callback));
}
catch (e) {
callback(e);
}
}));
};
return replServer;
}
/**
* When the result was "promise", resolve its value
* @private
*/
function promisify(err, value, callback) {
// callback immediately if no value passed
if (!callback && (0, function_1.isFunction)(value)) {
callback = value;
return callback();
}
if (err) {
throw err;
}
if ((0, function_1.isPromiseLike)(value)) {
value.then((v) => {
callback(null, v);
}, (err) => {
callback(err);
});
}
else {
callback(null, value);
}
}
/**
* Output object to stdout in JSON representation
* @private
*/
function outputToStdout(prettyPrint) {
if (prettyPrint && !(0, function_1.isNumber)(prettyPrint)) {
prettyPrint = 4;
}
return (err, value, callback) => {
if (err) {
console.error(err);
}
else {
const str = JSON.stringify(value, null, prettyPrint);
console.log(str);
}
callback(err, value);
};
}
/**
* define get accessor using Object.defineProperty
* @private
*/
function defineProp(obj, prop, getter) {
if (Object.defineProperty) {
Object.defineProperty(obj, prop, { get: getter });
}
}
/**
*
*/
class Repl {
_cli;
_in;
_out;
_interactive = true;
_paused = false;
_replServer = undefined;
constructor(cli) {
this._cli = cli;
this._in = new stream_1.Transform();
this._out = new stream_1.Transform();
this._in._transform = (chunk, encoding, callback) => {
if (!this._paused) {
this._in.push(chunk);
}
callback();
};
this._out._transform = (chunk, encoding, callback) => {
if (!this._paused && this._interactive !== false) {
this._out.push(chunk);
}
callback();
};
}
/**
*
*/
start(options = {}) {
this._interactive = options.interactive !== false;
process.stdin.resume();
if (process.stdin.setRawMode) {
process.stdin.setRawMode(true);
}
process.stdin.pipe(this._in);
this._out.pipe(process.stdout);
defineProp(this._out, 'columns', () => process.stdout.columns);
this._replServer = (0, repl_1.start)({
input: this._in,
output: this._out,
terminal: true,
});
this._defineAdditionalCommands();
this._replServer = injectBefore(this._replServer, 'completer', (line, callback) => {
this.complete(line)
.then((rets) => {
callback(null, rets);
})
.catch((err) => {
callback(err);
});
});
this._replServer = injectAfter(this._replServer, 'eval', promisify);
if (options.interactive === false) {
this._replServer = injectAfter(this._replServer, 'eval', outputToStdout(options.prettyPrint));
this._replServer = injectAfter(this._replServer, 'eval', function () {
process.exit();
});
}
this._replServer.on('exit', () => process.exit());
this._defineBuiltinVars(this._replServer.context);
if (options.evalScript) {
this._in.write(options.evalScript + '\n', 'utf-8');
}
return this;
}
/**
*
*/
_defineAdditionalCommands() {
const cli = this._cli;
const replServer = this._replServer;
if (!replServer) {
return;
}
replServer.defineCommand('connections', {
help: 'List currenty registered Salesforce connections',
action: async () => {
await cli.listConnections();
replServer.displayPrompt();
},
});
replServer.defineCommand('connect', {
help: 'Connect to Salesforce instance',
action: async (...args) => {
const [name, password] = args;
const params = password
? { connection: name, username: name, password: password }
: { connection: name, username: name };
try {
await cli.connect(params);
}
catch (err) {
if (err instanceof Error) {
console.error(err.message);
}
}
replServer.displayPrompt();
},
});
replServer.defineCommand('disconnect', {
help: 'Disconnect connection and erase it from registry',
action: (name) => {
cli.disconnect(name);
replServer.displayPrompt();
},
});
replServer.defineCommand('use', {
help: 'Specify login server to establish connection',
action: (loginServer) => {
cli.setLoginServer(loginServer);
replServer.displayPrompt();
},
});
replServer.defineCommand('authorize', {
help: 'Connect to Salesforce using OAuth2 authorization flow',
action: async (clientName) => {
try {
await cli.authorize(clientName);
}
catch (err) {
if (err instanceof Error) {
console.error(err.message);
}
}
replServer.displayPrompt();
},
});
replServer.defineCommand('register', {
help: 'Register OAuth2 client information',
action: async (...args) => {
const [clientName, clientId, clientSecret, redirectUri, loginUrl,] = args;
const config = { clientId, clientSecret, redirectUri, loginUrl };
try {
await cli.register(clientName, config);
}
catch (err) {
if (err instanceof Error) {
console.error(err.message);
}
}
replServer.displayPrompt();
},
});
replServer.defineCommand('open', {
help: 'Open Salesforce web page using established connection',
action: (url) => {
cli.openUrlUsingSession(url);
replServer.displayPrompt();
},
});
}
/**
*
*/
pause() {
this._paused = true;
if (process.stdin.setRawMode) {
process.stdin.setRawMode(false);
}
}
/**
*
*/
resume() {
this._paused = false;
process.stdin.resume();
if (process.stdin.setRawMode) {
process.stdin.setRawMode(true);
}
}
/**
*
*/
async complete(line) {
const tokens = line.replace(/^\s+/, '').split(/\s+/);
const [command, keyword = ''] = tokens;
if (command.startsWith('.') && tokens.length === 2) {
let candidates = [];
if (command === '.connect' || command === '.disconnect') {
candidates = await this._cli.getConnectionNames();
}
else if (command === '.authorize') {
candidates = await this._cli.getClientNames();
}
else if (command === '.use') {
candidates = ['production', 'sandbox'];
}
candidates = candidates.filter((name) => name.startsWith(keyword));
return [candidates, keyword];
}
}
/**
* Map all jsforce object to REPL context
* @private
*/
_defineBuiltinVars(context) {
const cli = this._cli;
// define salesforce package root objects
for (const key in __1.default) {
if (Object.prototype.hasOwnProperty.call(__1.default, key) &&
!global[key]) {
context[key] = __1.default[key];
}
}
// expose jsforce package root object in context.
context.jsforce = __1.default;
function createProxyFunc(prop) {
return (...args) => {
const conn = cli.getCurrentConnection();
return conn[prop](...args);
};
}
function createProxyAccessor(prop) {
return () => {
const conn = cli.getCurrentConnection();
return conn[prop];
};
}
const conn = cli.getCurrentConnection();
// list all props in connection instance, other than EventEmitter or object built-in methods
const props = {};
let o = conn;
while (o && o !== events_1.EventEmitter.prototype && o !== Object.prototype) {
for (const p of Object.getOwnPropertyNames(o)) {
if (p !== 'constructor') {
props[p] = true;
}
}
o = Object.getPrototypeOf(o);
}
for (const prop of Object.keys(props)) {
if (typeof global[prop] !== 'undefined') {
// avoid global override
continue;
}
if (prop.startsWith('_')) {
// ignore private
continue;
}
if ((0, function_1.isFunction)(conn[prop])) {
context[prop] = createProxyFunc(prop);
}
else if ((0, function_1.isObject)(conn[prop])) {
defineProp(context, prop, createProxyAccessor(prop));
}
}
// expose default connection as "$conn"
defineProp(context, '$conn', () => {
return cli.getCurrentConnection();
});
}
}
exports.Repl = Repl;
exports.default = Repl;