# SFDX-Node

Wrapper for the Salesforce CLI to use in Node.js

## Installation
`npm install sfdx-node`

## Usage
 The Salesforce CLI is based on OCLIF and is a combination of different OCLIF plugins. This module includes all the commands in `force`, `auth`
 and `config` namespaces. To use Salesforce CLI commands within Node.js programs, we wrap the namespace, topics, and camelcase the commands.
 For example:
 - `sfdx force:org:list` becomes `sfdx.force.org.list()`
 - `sfdx force:package:version:create` becomes `sfdx.force.package.versionCreate()`
 - `sfdx auth:web:login` becomes `sfdx.auth.web.login()`
 - `sfdx config:set` becomes `sfdx.config.set()`

 > sfdx NAMESPACE:TOPIC:COMMAND:SUB -> sfdx.namespace.topic.commandSub();

 Command parameters can be passed in as an object to the command using the flag names. So `sfdx force:org:create --setalias myorg --setdefaultusername`
 can be executed as below:

```javascript
const sfdx = require('sfdx-node');

// Create a new scratch org with alias myorg and set it as default org
sfdx.force.org.create({
  setalias: 'myorg',
  setdefaultusername: true
});
```

 Similarly, the special command arguments can be passing in as an array named `args` inside an object, as the second method argument.
 So, `sfdx alias:set myorg1=test-user1@example.com myorg2=test-user2@example.com` can be executed as below:

```javascript
const sfdx = require('sfdx-node');

// Set/overwrite aliases for already authorized orgs
sfdx.alias.set({},{
  args: ['myorg1=test-user1@example.com', 'myorg2=test-user2@example.com']
});
```

 Commands all return a JS Promise.

```javascript
const sfdx = require('sfdx-node');

//authorize a dev hub
sfdx.auth.web.login({
  setdefaultdevhubusername: true,
  setalias: 'HubOrg'
})
  .then(() => sfdx.force.source.push()) //push source
  .then(() => {
    // Display confirmation of source push
    console.log('Source pushed to scratch org');
  });
```

## Using `_quiet` for showing/hiding command output

It is possible to control the visibility of the output (success or failure) generated by a Salesforce CLI command, executed through this module.
Output can be made visible by passing in the flag `_quiet` as `false`. Default value for flag `_quiet` is `true`, which means that the default
behavior of this module is to hide the output of a Salesforce CLI command.

```javascript
const sfdx = require('sfdx-node');

// Fetch all the aliases, but do not show how the Salesforce CLI command output
sfdx.alias.list()
  .then((listResult) => {
    // Do something with the fetched list of all aliases
    console.log('Alias list:', listResult);
  });

// Fetch all the aliases, and show the Salesforce CLI command output
sfdx.alias.list({
  _quiet: false
})
  .then((listResult) => {
    // Do something else with the fetched list of all aliases
  });
```


## Using `_rejectOnError` for promise rejection (in case of a command failure)

Majority of the Salesforce CLI commands, when executed through node, do not reject the promise when an error occurs. They rather resolve with
`undefined`. Promise rejection can be forced by passing in the flag `_rejectOnError` as `true`. A few Salesforce CLI commands reject the promise
as their out-of-the-box behavior, without using this `_rejectOnError` flag.

```javascript
const sfdx = require('sfdx-node');

// Pull the remote changes from the scratch org
sfdx.force.source.pull({
  _rejectOnError: true
})
  .then((pullResult) => {
    // Successfully pulled from scratch org
    console.log('Changes pulled from scratch org:', pullResult);
  })
  .catch((pullError) => {
    // Promise rejected in case of conflicts or some other issue while pulling from scratch org
    console.log('Errors occurred during pull operation:', pullError);
  });
```

Rejecting promises is not the default bahavior of this module, unless the promise is rejected by Salesforce CLI command itself. This `_rejectOnError`
flag needs to be passed in as `true` for every command that is expected to reject the promise in case of an error.

### Promise rejection overlapping for parallel calls

When multiple CLI commands are executed in parallel using this module, while also making use of `_rejectOnError`, more than one or even all the commands
may end up rejecting the promises. This can happen because the errors are shared among all the parallel executions.

To avoid this, make use of `sfdx-node/parallel` module. It works in the same way as the main module, except for the fact that each command is executed in
it's own child process. This ensures that each command execution has it's own context and it doesn't share errors with other commands executing in parallel.

```javascript
const sfdx = require('sfdx-node/parallel');

// Get source status for first scratch org
sfdx.force.source.status({
  targetusername: 'test-user1@example.com',
  _rejectOnError: true
})
  .then((statusResult) => {
    // Source status for first scratch org
    console.log('First org source status:', statusResult);
  })
  .catch((statusError) => {
    // Error occurred during source status check for first scratch org
    console.log('First org error:', statusError);
  });

// Get source status for second scratch org
sfdx.force.source.status({
  targetusername: 'test-user2@example.com',
  _rejectOnError: true
})
  .then((statusResult) => {
    // Source status for second scratch org
    console.log('Second org source status:', statusResult);
  })
  .catch((statusError) => {
    // Error occurred during source status check for second scratch org
    console.log('Second org error:', statusError);
  });
```
