Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions messages/action-summary-viewer.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ Configuration written to:

Found 0 rules.

# rules-action.outfile-location

Rules written to:

# rules-action.rules-total

Found %d rule(s) from %d engine(s):
Expand Down
18 changes: 9 additions & 9 deletions messages/config-command.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,33 +12,33 @@ We're continually improving Salesforce Code Analyzer. Tell us what you think! Gi

# command.examples

- Display the current state of the Code Analyzer configuration using the default behavior: display top level configuration, display the engine and rule override settings associated with all the rules that have a "Recommended" tag; and automatically apply any existing custom configuration settings found in a `code-analyzer.yml` or `code-analyzer.yaml` file in the current folder:
- Display the current state of the Code Analyzer configuration using the default behavior: display top level configuration, display the engine and rule override settings associated with all the rules; and automatically apply any existing custom configuration settings found in a `code-analyzer.yml` or `code-analyzer.yaml` file in the current folder:

<%= config.bin %> <%= command.id %>

- This example is identical to the previous one, assuming that `./code-analyzer.yml` exists in your current folder.

<%= config.bin %> <%= command.id %> --config-file ./code-analyzer.yml --rule-selector Recommended
<%= config.bin %> <%= command.id %> --config-file ./code-analyzer.yml --rule-selector all

- Write the current state of configuration to the file `code-analyzer.yml`, including any configuration from an existing `code-analyzer.yml` file. The command preserves all values from the original config, but overwrites any comments:

<%= config.bin %> <%= command.id %> --config-file ./code-analyzer.yml --output-file code-analyzer.yml

- Display the configuration state for all rules, instead of just the recommended ones:
- Display the configuration state for just the recommended rules, instead of all the rules:

<%= config.bin %> <%= command.id %> --rule-selector all
<%= config.bin %> <%= command.id %> --rule-selector Recommended

- Display the configuration state associated with recommended rules that are applicable to your workspace folder, `./src`:
- Display the configuration state associated with all the rules that are applicable to your workspace folder, `./src`:

<%= config.bin %> <%= command.id %> --workspace ./src

- Display any relevant configuration settings associated with the rule name 'no-undef' from the 'eslint' engine:

<%= config.bin %> <%= command.id %> --rule-selection eslint:no-undef
<%= config.bin %> <%= command.id %> --rule-selector eslint:no-undef

- Load an existing configuration file called `existing-config.yml`, and then write the configuration to a new file called `new-config.yml`, the configuration state that is applicable to all rules that are relevant to the workspace located in the current folder:

<%= config.bin %> <%= command.id %> --config-file ./existing-config.yml --rule-selection all --workspace . --output-file ./subfolder-config.yml
<%= config.bin %> <%= command.id %> --config-file ./existing-config.yml --workspace . --output-file ./subfolder-config.yml

# flags.workspace.summary

Expand All @@ -62,9 +62,9 @@ Use the --rule-selector flag to display only the configuration associated with t

You can combine different criteria using colons to further filter the list; the colon works as an intersection. For example, "--rule-selector eslint:Security" reduces the output to only contain the configuration state associated with the rules from the "eslint" engine that have the "Security" tag. To add multiple rule selectors together (a union), specify the --rule-selector flag multiple times, such as "--rule-selector eslint:Recommended --rule-selector retire-js:3".

If you don't specify this flag, then the command uses the "Recommended" tag rule selector.
If you don't specify this flag, then the command uses the "all" rule selector.

Run `<%= config.bin %> <%= command.id %> --rule-selector all` to display the configuration state associated with all possible rules available, and not just the recommended ones.
Run `<%= config.bin %> <%= command.id %> --rule-selector Recommended` to display the configuration state associated with just the 'Recommended' rules, instead of all the rules.

# flags.config-file.summary

Expand Down
5 changes: 4 additions & 1 deletion messages/progress-event-listener.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,11 @@ Executing rules
# execution-spinner.progress-summary
%d of %d engines finished after %ds.

# execution-spinner.engine-status
# execution-spinner.engine-progress
- %s at %d% completion.

# execution-spinner.engine-progress-with-message
- %s at %d% completion - %s

# execution-spinner.finished-status
done. Executed rules from %s.
18 changes: 15 additions & 3 deletions messages/rules-command.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ We're continually improving Salesforce Code Analyzer. Tell us what you think! Gi

<%= config.bin %> <%= command.id %> --rule-selector eslint:all

- List all rules for all engines:
- List the details about all rules for all engines; also write the rules in JSON format to a file called "rules.json" in the "out" folder, which must already exist:

<%= config.bin %> <%= command.id %> --rule-selector all
<%= config.bin %> <%= command.id %> --rule-selector all --output-file ./out/rules.json --view detail

- Get a more accurate list of the rules that apply specifically to your workspace (all the files in the current folder):

Expand Down Expand Up @@ -102,4 +102,16 @@ Format to display the rules in the terminal.

# flags.view.description

The format `table` is concise and shows minimal output, the format `detail` shows all available information.
The format `table` is concise and shows minimal output, the format `detail` shows all available information.

If you specify neither --view nor --output-file, then the default table view is shown. If you specify --output-file but not --view, only summary information is shown in the terminal.

# flags.output-file.summary

Name of the file where the selected rules are written. The file format depends on the extension you specify; currently, only .json is supported for JSON-formatted output.

# flags.output-file.description

If you specify a folder, such as "--output-file ./out/rules.json", the folder must already exist or you get an error. If the file already exists, it's overwritten without prompting.

If you don't specify this flag, the command outputs the rules to only the terminal.
3 changes: 3 additions & 0 deletions messages/rules-writer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# error.unrecognized-file-format

The output file %s has an unsupported extension. Valid extension(s): .json.
9 changes: 6 additions & 3 deletions messages/run-command.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,20 +126,23 @@ If you specify neither --view nor --output-file, then the default table view is

# flags.output-file.summary

Output file that contains the analysis results. The file format depends on the extension you specify, such as .csv, .html, .xml, and so on.
Name of the file where the analysis results are written. The file format depends on the extension you specify, such as .csv, .html, .xml, and so on.

# flags.output-file.description

If you don't specify this flag, the command outputs the results in the terminal. Use this flag to print the results to a file; the format of the results depends on the extension you provide. For example, "--output-file results.csv" creates a comma-separated values file. You can specify one of these extensions:
If you don't specify this flag, the command outputs the results to only the terminal. Use this flag to print the results to a file; the format of the results depends on the extension you provide. For example, "--output-file results.csv" creates a comma-separated values file. You can specify one of these extensions:

- .csv
- .html or .htm
- .json
- .sarif or .sarif.json
- .xml

To output the results to multiple files, specify this flag multiple times. For example: "--output-file ./out/results.json --output-file ./out/report.html" creates a JSON results file and an HTML file in the "./out" folder.
To output the results to multiple files, specify this flag multiple times. For example: "--output-file results.json --output-file report.html" creates both a JSON results file and an HTML file.

If you specify a folder, such as "--output-file ./out/results.json", the folder must already exist or you get an error. If the file already exists, it's overwritten without prompting.

# error.invalid-severity-threshold

Expected --severity-threshold=%s to be one of: %s

19 changes: 10 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,24 +1,25 @@
{
"name": "@salesforce/plugin-code-analyzer",
"description": "Static code scanner that applies quality and security rules to Apex code, and provides feedback.",
"version": "5.0.0-beta.2",
"version": "5.0.0-beta.3",
"author": "Salesforce Code Analyzer Team",
"bugs": "https://github.com/forcedotcom/sfdx-scanner/issues",
"dependencies": {
"@oclif/core": "3.27.0",
"@salesforce/code-analyzer-core": "0.23.0",
"@salesforce/code-analyzer-engine-api": "0.18.0",
"@salesforce/code-analyzer-eslint-engine": "0.20.0",
"@salesforce/code-analyzer-flowtest-engine": "0.18.0",
"@salesforce/code-analyzer-pmd-engine": "0.20.0",
"@salesforce/code-analyzer-regex-engine": "0.18.0",
"@salesforce/code-analyzer-retirejs-engine": "0.18.0",
"@salesforce/code-analyzer-core": "0.25.1",
"@salesforce/code-analyzer-engine-api": "0.20.0",
"@salesforce/code-analyzer-eslint-engine": "0.20.1",
"@salesforce/code-analyzer-flowtest-engine": "0.18.1",
"@salesforce/code-analyzer-pmd-engine": "0.21.0",
"@salesforce/code-analyzer-regex-engine": "0.18.1",
"@salesforce/code-analyzer-retirejs-engine": "0.18.1",
"@salesforce/code-analyzer-sfge-engine": "0.1.0",
"@salesforce/core": "6.7.6",
"@salesforce/sf-plugins-core": "5.0.13",
"@salesforce/ts-types": "^2.0.12",
"@types/js-yaml": "^4.0.9",
"@types/node": "^22.12.0",
"ansis": "^3.10.0",
"ansis": "^3.17.0",
"fast-glob": "^3.3.3",
"js-yaml": "^4.1.0",
"ts-node": "^10",
Expand Down
2 changes: 1 addition & 1 deletion src/commands/code-analyzer/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export default class ConfigCommand extends SfCommand<void> implements Displayabl
char: 'r',
multiple: true,
delimiter: ',',
default: ["Recommended"]
default: ["all"]
}),
'config-file': Flags.file({
summary: getMessage(BundleName.ConfigCommand, 'flags.config-file.summary'),
Expand Down
53 changes: 45 additions & 8 deletions src/commands/code-analyzer/rules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@ import {Flags, SfCommand} from '@salesforce/sf-plugins-core';
import {View} from '../../Constants';
import {CodeAnalyzerConfigFactoryImpl} from '../../lib/factories/CodeAnalyzerConfigFactory';
import {EnginePluginsFactoryImpl} from '../../lib/factories/EnginePluginsFactory';
import {RuleDetailDisplayer, RuleTableDisplayer} from '../../lib/viewers/RuleViewer';
import {RuleDetailDisplayer, RulesNoOpDisplayer, RuleTableDisplayer} from '../../lib/viewers/RuleViewer';
import {RulesActionSummaryViewer} from '../../lib/viewers/ActionSummaryViewer';
import {RulesAction, RulesDependencies} from '../../lib/actions/RulesAction';
import {RulesAction, RulesDependencies, RulesInput} from '../../lib/actions/RulesAction';
import {BundleName, getMessage, getMessages} from '../../lib/messages';
import {Displayable, UxDisplay} from '../../lib/Display';
import {LogEventDisplayer} from '../../lib/listeners/LogEventListener';
import {RuleSelectionProgressSpinner} from '../../lib/listeners/ProgressEventListener';
import {CompositeRulesWriter} from '../../lib/writers/RulesWriter';

export default class RulesCommand extends SfCommand<void> implements Displayable {
// We don't need the `--json` output for this command.
Expand Down Expand Up @@ -42,11 +43,15 @@ export default class RulesCommand extends SfCommand<void> implements Displayable
char: 'c',
exists: true
}),
'output-file': Flags.file({
summary: getMessage(BundleName.RulesCommand, 'flags.output-file.summary'),
description: getMessage(BundleName.RulesCommand, 'flags.output-file.description'),
char: 'f'
}),
view: Flags.string({
summary: getMessage(BundleName.RulesCommand, 'flags.view.summary'),
description: getMessage(BundleName.RulesCommand, 'flags.view.description'),
char: 'v',
default: View.TABLE,
options: Object.values(View)
})
};
Expand All @@ -56,21 +61,53 @@ export default class RulesCommand extends SfCommand<void> implements Displayable
this.warn(getMessage(BundleName.Shared, "warning.command-state", [getMessage(BundleName.Shared, 'label.command-state')]));

const parsedFlags = (await this.parse(RulesCommand)).flags;
const dependencies: RulesDependencies = this.createDependencies(parsedFlags.view as View);
const outputFiles = parsedFlags['output-file'] ? [parsedFlags['output-file']] : [];
const view = parsedFlags.view as View | undefined;

const dependencies: RulesDependencies = this.createDependencies(view, outputFiles);
const action: RulesAction = RulesAction.createAction(dependencies);
await action.execute(parsedFlags);

const rulesInput: RulesInput = {
'config-file': parsedFlags['config-file'],
'output-file': outputFiles,
'rule-selector': parsedFlags['rule-selector'],
'workspace': parsedFlags['workspace'],
};

await action.execute(rulesInput);
}

protected createDependencies(view: View): RulesDependencies {
protected createDependencies(view: View | undefined, outputFiles: string[]): RulesDependencies {
const uxDisplay: UxDisplay = new UxDisplay(this, this.spinner);
return {
const dependencies: RulesDependencies = {
configFactory: new CodeAnalyzerConfigFactoryImpl(),
pluginsFactory: new EnginePluginsFactoryImpl(),
logEventListeners: [new LogEventDisplayer(uxDisplay)],
progressListeners: [new RuleSelectionProgressSpinner(uxDisplay)],
actionSummaryViewer: new RulesActionSummaryViewer(uxDisplay),
viewer: view === View.TABLE ? new RuleTableDisplayer(uxDisplay) : new RuleDetailDisplayer(uxDisplay)
viewer: this.createRulesViewer(view, outputFiles, uxDisplay),
writer: CompositeRulesWriter.fromFiles(outputFiles)
};

return dependencies;
}

/**
* Creates the {@link RuleViewer} that will be called from {@link RulesAction.execute} to display rules.
* If a view option is set, rules will be displayed in the specified format.
* If an output file is set, rules will not display.
* By default, the details display will be used.
*/
private createRulesViewer(view: View | undefined, outputFiles: string[] = [], uxDisplay: UxDisplay) {
if (view === View.DETAIL) {
return new RuleDetailDisplayer(uxDisplay);
} else if (view === View.TABLE) {
return new RuleTableDisplayer(uxDisplay);
} else if (outputFiles.length > 0) {
return new RulesNoOpDisplayer();
}

return new RuleTableDisplayer(uxDisplay);
}
}

Loading