Skip to content
Merged
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ After pressing <kbd>V</kbd> to enter range selection mode:

| ARGUMENT | DESCRIPTION |
| -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| -p, --profiles | Allows you to select the [profile](./docs/profiles.md) (set of targets) to use. If no option is specified, the available ones will be listed.. _(**node** by default)_. |
| -c, --bg-color | Change row highlight color. _(Available: **blue**, cyan, magenta, white, red and yellow)_ |
| -d, --directory | Set the directory from which to begin searching. By default, starting-point is . |
| -D, --delete-all | Automatically delete all node_modules folders that are found. Suggested to be used together with `-x`. |
Expand Down
3 changes: 1 addition & 2 deletions docs/profiles.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,11 @@ Special profile: all
- `coverage`: Code coverage reports. Deleting removes historical coverage data. Regenerated by running tests with coverage enabled.
- `.nyc_output`: Raw coverage output from `nyc`. Deleting removes raw coverage data. Regenerated on the next run of `nyc`.
- `.jest`: Jest's test cache and artifacts. Deleting may slow down the next test run. Regenerated automatically by Jest.
- `dist`: General-purpose directory for compiled or built output. Deleting removes the production-ready assets. Regenerated by running a build script (e.g., `npm run build`).
- `gatsby_cache`: Gatsby's internal cache. Deleting may slow down the next build. Regenerated automatically by Gatsby.
- `.docusaurus`: Docusaurus build cache and data. Deleting removes generated site files. Regenerated by Docusaurus on the next build.
- `.swc`: SWC (Speedy Web Compiler) cache. Deleting may slow down the next compilation. Regenerated automatically by SWC.
- `.stylelintcache`: Stylelint's cache for linted files. Deleting forces a full re-lint. Regenerated by Stylelint when run with the `--cache` flag.
- `tmp`: Temporary files and directories. Deleting is generally safe but should be done with caution. Regenerated by the respective tools and processes when needed.
- `deno_cache`: Deno's cache for modules. Deleting is safe. Regenerated when Deno modules are next fetched.

## python

Expand Down
102 changes: 93 additions & 9 deletions src/cli/cli.controller.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import {
ConsoleService,
ProfilesService,
ResultsService,
SpinnerService,
UpdateService,
} from './services/index.js';
import {
DEFAULT_CONFIG,
DEFAULT_PROFILE,
MIN_CLI_COLUMNS_SIZE,
UI_POSITIONS,
} from '../constants/index.js';
Expand Down Expand Up @@ -73,6 +75,7 @@ export class CliController {
private readonly uiService: UiService,
private readonly scanService: ScanService,
private readonly jsonOutputService: JsonOutputService,
private readonly profilesService: ProfilesService,
) {}

init(): void {
Expand Down Expand Up @@ -249,17 +252,47 @@ export class CliController {
const options = this.consoleService.getParameters(process.argv);
if (options.isTrue('help')) {
this.showHelp();
// eslint-disable-next-line n/no-process-exit
process.exit(0);
this.exitGracefully();
}
if (options.isTrue('version')) {
this.showProgramVersion();
// eslint-disable-next-line n/no-process-exit
process.exit(0);
this.exitGracefully();
}

if (options.isTrue('profiles') && options.isTrue('target-folder')) {
console.log(
'Cannot use both --profiles and --target-folder options together.',
);
this.exitGracefully();
}

if (
options.isTrue('profiles') &&
options.getStrings('profiles').length === 0
) {
// TODO check user defined
const defaultProfile = DEFAULT_PROFILE;
console.log(
colors.bold(colors.bgYellow(colors.black(' Available profiles '))),
);
console.log(
`Remember: ${colors.bold(colors.yellow('context matters'))}. What's safe to remove in one project or ecosystem could be important in another.\n`,
);
console.log(
this.profilesService.getAvailableProfilesToPrint(defaultProfile),
);
this.exitGracefully();
}

if (options.isTrue('delete-all')) {
if (!options.isTrue('target-folder') || options.isTrue('profiles')) {
// TODO mejorar mensaje e incluir tip buscar lista targets de un profile.
console.log('--delete-all only can be used with --target-folder.');
this.exitWithError();
}
this.config.deleteAll = true;
}

if (options.isTrue('sort-by')) {
if (!this.isValidSortParam(options.getString('sort-by'))) {
this.invalidSortParam();
Expand Down Expand Up @@ -302,6 +335,45 @@ export class CliController {
if (options.isTrue('no-check-updates')) {
this.config.checkUpdates = false;
}

if (!options.isTrue('target-folder')) {
if (!options.isTrue('profiles')) {
this.logger.info(`Using default profile targets (${DEFAULT_PROFILE})`);
this.config.targets = this.profilesService.getTargetsFromProfiles([
DEFAULT_PROFILE,
]);
} else {
const selectedProfiles = options.getStrings('profiles');
const badProfiles =
this.profilesService.getBadProfiles(selectedProfiles);

if (badProfiles.length > 0) {
this.logger.warn(
`The following profiles are invalid: ${badProfiles.join(', ')}`,
);
const profileText = badProfiles.length > 1 ? 'profiles' : 'profile';
console.log(
colors.bold(colors.bgRed(colors.white(` Invalid ${profileText} `))),
);
console.log(
`The following ${profileText} are invalid: ${colors.red(badProfiles.join(', '))}.`,
);
console.log(
`You can list the available profiles with ${colors.bold(colors.green('--profiles'))} command ${colors.gray('(without arguments)')}.`,
);
this.exitWithError();
}

const targets =
this.profilesService.getTargetsFromProfiles(selectedProfiles);
this.logger.info(
`Using profiles ${selectedProfiles.join(', ')} | With targets ${targets.join(', ')}`,
);
this.config.profiles = selectedProfiles;
this.config.targets = targets;
}
}

if (options.isTrue('target-folder')) {
this.config.targets = options.getString('target-folder').split(',');
}
Expand Down Expand Up @@ -542,7 +614,7 @@ export class CliController {
error: (error) => this.jsonOutputService.writeError(error),
complete: () => {
this.jsonOutputService.completeScan();
process.exit(0);
this.exitGracefully();
},
});
}
Expand Down Expand Up @@ -571,7 +643,7 @@ export class CliController {
private setupJsonModeSignalHandlers(): void {
const gracefulShutdown = () => {
this.jsonOutputService.handleShutdown();
process.exit(0);
this.exitGracefully();
};

process.on('SIGINT', gracefulShutdown);
Expand Down Expand Up @@ -625,15 +697,21 @@ export class CliController {
}

private exitWithError(): void {
this.uiService.print('\n');
this.uiService.setRawMode(false);
this.uiService.setCursorVisible(true);
this.resetConsoleState();
const logPath = this.logger.getSuggestLogFilePath();
this.logger.saveToFile(logPath);
// eslint-disable-next-line n/no-process-exit
process.exit(1);
}

private exitGracefully(): void {
this.resetConsoleState();
const logPath = this.logger.getSuggestLogFilePath();
this.logger.saveToFile(logPath);
// eslint-disable-next-line n/no-process-exit
process.exit(0);
}

private quit(): void {
this.uiService.setRawMode(false);
this.uiService.clear();
Expand All @@ -646,6 +724,12 @@ export class CliController {
process.exit(0);
}

private resetConsoleState(): void {
this.uiService.print('\n');
this.uiService.setRawMode(false);
this.uiService.setCursorVisible(true);
}

private printExitMessage(): void {
const { spaceReleased } = this.resultsService.getStats();
new GeneralUi().printExitMessage({ spaceReleased });
Expand Down
1 change: 1 addition & 0 deletions src/cli/interfaces/config.interface.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export interface IConfig {
profiles: string[];
folderRoot: string;
backgroundColor: string;
warningColor: string;
Expand Down
5 changes: 5 additions & 0 deletions src/cli/interfaces/profiles.interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export interface TARGETS_PROFILE {
name: string;
targets: string[];
description: string;
}
9 changes: 9 additions & 0 deletions src/cli/models/start-parameters.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,13 @@ export class StartParameters {

return value;
}

getStrings(key: string): string[] {
const value = this.values[key];
if (!value || typeof value === 'boolean') {
return [];
}

return value.split(',').map((item) => item.trim());
}
}
1 change: 1 addition & 0 deletions src/cli/services/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ export * from './spinner.service.js';
export * from './update.service.js';
export * from './json-output.service.js';
export * from '../../core/services/stream.service.js';
export * from './profiles.service.js';
42 changes: 42 additions & 0 deletions src/cli/services/profiles.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { DEFAULT_PROFILES } from '../../constants/index.js';
import colors from 'colors';

export class ProfilesService {
getAvailableProfilesToPrint(defaultProfileName?: string): string {
return DEFAULT_PROFILES.reduce((acc, profile) => {
const isDefault = profile.name === defaultProfileName;
const entry =
` ${colors.green(profile.name)}${isDefault ? colors.italic(' (default)') : ''} - ${profile.description}\n` +
colors.gray(` ${profile.targets.join(colors.italic(','))}\n\n`);
return acc + entry;
}, '');
}

/** Return an array of invalid profile names (if not exist or dont have targets). */
getBadProfiles(profilesNames: string[]): string[] {
const availableProfilesNames = DEFAULT_PROFILES.map(
(profile) => profile.name,
);
return profilesNames.filter(
(profileName) => !availableProfilesNames.includes(profileName),
);
}

getTargetsFromProfiles(profilesNames: string[]): string[] {
const profileMap = new Map(DEFAULT_PROFILES.map((p) => [p.name, p]));
const targets = new Set<string>();

for (const name of profilesNames) {
const profile = profileMap.get(name);
if (!profile) {
continue;
}

for (const target of profile.targets) {
targets.add(target);
}
}

return Array.from(targets);
}
}
8 changes: 7 additions & 1 deletion src/constants/cli.constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@ import { ICliOptions } from '../cli/interfaces/index.js';
import colors from 'colors';

export const OPTIONS: ICliOptions[] = [
{
arg: ['-p', '--profiles'],
description:
'Specifies profiles (presets) of folders to search, separated by commas (e.g., `-p python,java`, `-p all`). If used without a value, lists the available profiles. Default: `node`.',
name: 'profiles',
},
{
arg: ['-c', '--bg-color'],
description:
Expand Down Expand Up @@ -67,7 +73,7 @@ export const OPTIONS: ICliOptions[] = [
arg: ['-t', '--target'],
description:
// eslint-disable-next-line quotes
"Specify the name of the directories you want to search for (by default, it's 'node_modules'). You can define multiple targets separating with comma. Ej. `-t node_modules,.cache,`.",
'Specify the name of the directories you want to search for. You can define multiple targets separating with comma. Ej. `-t node_modules,.cache`.',
name: 'target-folder',
},
{
Expand Down
1 change: 1 addition & 0 deletions src/constants/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ export * from './spinner.constants.js';
export * from './update.constants.js';
export * from './options.constants.js';
export * from './result-descriptions.constants.js';
export * from './profiles.constants.js';
2 changes: 2 additions & 0 deletions src/constants/main.constants.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { IConfig } from '../cli/interfaces/index.js';
import { DEFAULT_PROFILE } from './profiles.constants.js';

export const MIN_CLI_COLUMNS_SIZE = 60;
export const CURSOR_SIMBOL = '~>';
Expand All @@ -8,6 +9,7 @@ export const DECIMALS_SIZE = 2;
export const OVERFLOW_CUT_FROM = 11;

export const DEFAULT_CONFIG: IConfig = {
profiles: [DEFAULT_PROFILE],
folderRoot: '',
backgroundColor: 'bgBlue',
warningColor: 'brightYellow',
Expand Down
Loading