Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rnv standalone command fixes #1392

Merged
merged 14 commits into from Feb 14, 2024
Merged
4 changes: 2 additions & 2 deletions packages/cli/src/prompt.ts
Expand Up @@ -51,8 +51,8 @@ export const inquirerPrompt = async (params: PromptParams): Promise<Record<strin
return resp;
};

export const inquirerSeparator = () => {
return new inquirer.Separator();
export const inquirerSeparator = (text?: string) => {
return new inquirer.Separator(text);
};

export const pressAnyKeyToContinue = () => {
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/api/index.ts
Expand Up @@ -40,8 +40,8 @@ export const inquirerPrompt: RnvApiPrompt['inquirerPrompt'] = (opts) => {
return getApi().prompt.inquirerPrompt(opts);
};

export const inquirerSeparator: RnvApiPrompt['inquirerSeparator'] = () => {
return getApi().prompt.inquirerSeparator();
export const inquirerSeparator: RnvApiPrompt['inquirerSeparator'] = (text?: string) => {
return getApi().prompt.inquirerSeparator(text);
};

export const generateOptions: RnvApiPrompt['generateOptions'] = (inputData, isMultiChoice, mapping, renderMethod) => {
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/api/types.ts
Expand Up @@ -37,7 +37,7 @@ export type RnvApiPrompt = {
renderMethod?: PromptRenderFn
) => PromptOptions;
pressAnyKeyToContinue: () => Promise<any>;
inquirerSeparator: () => any;
inquirerSeparator: (text?: string) => any;
};

export type RnvContextAnalytics = {
Expand Down
16 changes: 16 additions & 0 deletions packages/core/src/constants.ts
Expand Up @@ -122,6 +122,8 @@ export const SUPPORTED_PLATFORMS = [
export const TASK_RUN = 'run';
export const TASK_CONFIGURE = 'configure';
export const TASK_DOCTOR = 'doctor';
export const TASK_NEW = 'new';
export const TASK_HELP = 'help';
export const TASK_BUILD = 'build';
export const TASK_INFO = 'info';
export const TASK_START = 'start';
Expand All @@ -131,6 +133,8 @@ export const TASK_PACKAGE = 'package';
export const TASK_DEPLOY = 'deploy';
export const TASK_LOG = 'log';
export const TASK_CLEAN = 'clean';
export const TASK_LINK = 'link';
export const TASK_UNLINK = 'unlink';
export const TASK_INSTALL = 'install';
export const TASK_PUBLISH = 'publish';
export const TASK_STATUS = 'status';
Expand Down Expand Up @@ -172,6 +176,9 @@ export const TASK_WORKSPACE_CONFIGURE = 'workspace configure';
export const TASK_CONFIGURE_SOFT = 'configureSoft';
export const TASK_KILL = 'kill';
export const TASK_EJECT = 'eject';
export const TASK_TELEMETRY_DISABLE = 'telemetry disable';
export const TASK_TELEMETRY_ENABLE = 'telemetry enable';
export const TASK_TELEMETRY_STATUS = 'telemetry status';

export const INJECTABLE_CONFIG_PROPS: Array<ConfigPropKey> = [
'id',
Expand All @@ -188,3 +195,12 @@ export const INJECTABLE_CONFIG_PROPS: Array<ConfigPropKey> = [
export const INJECTABLE_RUNTIME_PROPS = ['appId', 'scheme', 'timestamp', 'localhost', 'target', 'port'] as const;

export const REMOTE_DEBUGGER_ENABLED_PLATFORMS = [TIZEN, TIZEN_MOBILE, TIZEN_WATCH];

export const DEFAULT_TASK_DESCRIPTIONS: Record<string, string> = {
[TASK_RUN]: 'Run your app on target device or emulator',
[TASK_PACKAGE]: 'Package source files into bundle',
[TASK_BUILD]: 'Build project binary',
[TASK_CONFIGURE]: 'Configure current project',
[TASK_START]: 'Starts bundler / server',
[TASK_EXPORT]: 'Export the app into deployable binary',
};
121 changes: 88 additions & 33 deletions packages/core/src/tasks/index.ts
Expand Up @@ -8,11 +8,11 @@ import {
getEngineSubTasks,
registerAllPlatformEngines,
} from '../engines';
import { TASK_CONFIGURE_SOFT } from '../constants';
import { DEFAULT_TASK_DESCRIPTIONS, TASK_CONFIGURE_SOFT } from '../constants';
import { RnvContext } from '../context/types';
import { RnvTask, RnvTaskMap, TaskItemMap, TaskObj } from './types';
import { RnvTask, RnvTaskMap, TaskItemMap, TaskObj, TaskOption } from './types';
import { RnvEngine } from '../engines/types';
import { inquirerPrompt, pressAnyKeyToContinue } from '../api';
import { inquirerPrompt, inquirerSeparator, pressAnyKeyToContinue } from '../api';
import { getApi } from '../api/provider';
import { RenativeConfigTaskKey } from '../schema/types';
import { checkIfProjectAndNodeModulesExists } from '../projects/dependencyManager';
Expand Down Expand Up @@ -41,24 +41,44 @@ export const initializeTask = async (c: RnvContext, task: string) => {
return true;
};

const _getTaskOption = ({ taskInstance, hasMultipleSubTasks }: TaskObj) => {
if (hasMultipleSubTasks) {
return `${taskInstance.task.split(' ')[0]}...`;
}
const _getTaskOption = ({ taskInstance }: TaskObj): TaskOption => {
const asArray = taskInstance.task.split(' ');
const output: TaskOption = {
value: taskInstance.task,
command: '',
name: '',
asArray,
isPriorityOrder: taskInstance.isPriorityOrder,
description: taskInstance.description,
isGlobalScope: taskInstance.isGlobalScope,
isPrivate: taskInstance.isPrivate,
};

if (taskInstance.description && taskInstance.description !== '') {
return `${taskInstance.task.split(' ')[0]} ${chalk().grey(`(${taskInstance.description})`)}`;
output.description = taskInstance.description;
output.name = `${taskInstance.task} ${chalk().grey(`(${taskInstance.description})`)}`;
} else {
output.name = taskInstance.task;
}
return `${taskInstance.task.split(' ')[0]}`;
output.command = asArray[0];
output.subCommand = asArray[1];

return output;
};

const _getTaskObj = (taskInstance: RnvTask) => {
const key = taskInstance.task.split(' ')[0];
let hasMultipleSubTasks = false;
if (taskInstance.task.includes(' ')) hasMultipleSubTasks = true;
const key = taskInstance.task;
const taskNameArr = key.split(' ');
let parent: null | string = null;
if (taskNameArr.length > 1) {
taskNameArr.pop();
parent = taskNameArr.join(' ');
}

return {
key,
taskInstance,
hasMultipleSubTasks,
parent,
};
};

Expand All @@ -68,45 +88,80 @@ export const findSuitableTask = async (c: RnvContext, specificTask?: string): Pr
let task = '';
if (!specificTask) {
if (!c.command) {
const suitableTaskInstances: Record<string, TaskObj> = {};
const suitableTasks: Record<string, TaskOption> = {};
REGISTERED_ENGINES.forEach((engine) => {
Object.values(engine.tasks).forEach((taskInstance) => {
const taskObj = _getTaskObj(taskInstance);
suitableTaskInstances[taskObj.key] = taskObj;
let taskObj: TaskOption = _getTaskOption(_getTaskObj(taskInstance));
if (!suitableTasks[taskObj.value]) {
suitableTasks[taskObj.value] = taskObj;
} else {
taskObj = suitableTasks[taskObj.value];
// In case of multiple competing tasks (same task name but coming from different engines)
// We try to revert to generic description instead.
taskObj.description = DEFAULT_TASK_DESCRIPTIONS[taskObj.value] || taskObj.description;
// In case of multiple competing tasks we assume they are "commonly used"
taskObj.isPriorityOrder = true;
}
});
});
Object.values(CUSTOM_TASKS).forEach((taskInstance) => {
const taskObj = _getTaskObj(taskInstance);
suitableTaskInstances[taskObj.key] = taskObj;
const taskObj = _getTaskOption(_getTaskObj(taskInstance));
suitableTasks[taskObj.value] = taskObj;
});

const taskInstances = Object.values(suitableTaskInstances);
let tasks;
const taskInstances = Object.values(suitableTasks);
let tasks: TaskOption[];

let defaultCmd: string | undefined = 'new';
let tasksCommands;
let filteredTasks;
let addendum = '';
if (!c.paths.project.configExists) {
filteredTasks = taskInstances.filter((v) => v.taskInstance.isGlobalScope);
tasks = filteredTasks.map((v) => _getTaskOption(v)).sort();
tasksCommands = filteredTasks.map((v) => v.taskInstance.task.split(' ')[0]).sort();
tasks = taskInstances.filter((v) => v.isGlobalScope && !v.isPrivate).sort();
addendum = ' (Not a ReNative project. options will be limited)';
} else {
tasks = taskInstances.map((v) => _getTaskOption(v)).sort();
tasksCommands = taskInstances.map((v) => v.taskInstance.task.split(' ')[0]).sort();
defaultCmd = tasks.find((v) => v.startsWith('run'));
tasks = taskInstances.filter((v) => !v.isPrivate).sort();
defaultCmd = tasks.find((v) => v.value === 'run')?.name;
}

const { command } = await inquirerPrompt({
const commonTasks: TaskOption[] = [];
const ungroupedTasks: TaskOption[] = [];
const groupedTasks: TaskOption[] = [];
const taskGroups: Record<string, TaskOption> = {};
tasks.forEach((task) => {
if (task.subCommand) {
if (!taskGroups[task.command]) {
const groupTask: TaskOption = {
name: `${task.command}...`,
command: task.command,
value: task.command,
};
taskGroups[task.command] = groupTask;
groupedTasks.push(groupTask);
}
} else if (task.isPriorityOrder) {
commonTasks.push(task);
} else {
ungroupedTasks.push(task);
}
});

const mergedTasks = [
inquirerSeparator('─────────── Common tasks ───────────'),
...commonTasks,
inquirerSeparator('─────────── More tasks ─────────────'),
...ungroupedTasks,
...groupedTasks,
];

const { selectedTask } = await inquirerPrompt({
type: 'list',
default: defaultCmd,
name: 'command',
name: 'selectedTask',
message: `Pick a command${addendum}`,
choices: tasks,
choices: mergedTasks,
pageSize: 15,
logMessage: 'Welcome to the brave new world...',
});
c.command = tasksCommands[tasks.indexOf(command)];
c.command = selectedTask;
}
if (c.command) task = c.command;
if (c.subCommand) task += ` ${c.subCommand}`;
Expand Down Expand Up @@ -343,7 +398,7 @@ export const executeOrSkipTask = async (c: RnvContext, task: string, parentTask:

const ACCEPTED_CONDITIONS = ['platform', 'target', 'appId', 'scheme'] as const;

type ACKey = typeof ACCEPTED_CONDITIONS[number];
type ACKey = (typeof ACCEPTED_CONDITIONS)[number];

const _logSkip = (task: string) => {
logInfo(`Original RNV task ${chalk().white(task)} marked to ignore. SKIPPING...`);
Expand Down
17 changes: 16 additions & 1 deletion packages/core/src/tasks/types.ts
Expand Up @@ -9,6 +9,21 @@ export type RnvTask = {
forceBuildHookRebuild?: boolean;
fn?: RnvTaskFn;
fnHelp?: RnvTaskFn;
isPrivate?: boolean;
isPriorityOrder?: boolean;
};

export type TaskOption = {
name: string;
value: string;
command: string;
asArray?: string[];
subCommand?: string;
subTasks?: TaskOption[];
description?: string;
isGlobalScope?: boolean;
isPrivate?: boolean;
isPriorityOrder?: boolean;
};

export type RnvTaskParameter = {
Expand Down Expand Up @@ -38,5 +53,5 @@ export type TaskItemMap = Record<
export type TaskObj = {
key: string;
taskInstance: RnvTask;
hasMultipleSubTasks?: boolean;
// hasMultipleSubTasks?: boolean;
};
5 changes: 4 additions & 1 deletion packages/engine-core/src/tasks/task.rnv.app.configure.ts
Expand Up @@ -19,6 +19,7 @@ import {
inquirerPrompt,
RnvContext,
inquirerSeparator,
RnvTask,
} from '@rnv/core';

const _loadAppConfigIDfromDir = (dirName: string, appConfigsDir: string) => {
Expand Down Expand Up @@ -204,10 +205,12 @@ export const taskRnvAppConfigure = async (c: RnvContext) => {
return true;
};

export default {
const Task: RnvTask = {
description: 'Configure project with specific appConfig',
fn: taskRnvAppConfigure,
task: TASK_APP_CONFIGURE,
params: PARAMS.withBase(PARAMS.withConfigure()),
platforms: [],
};

export default Task;
6 changes: 4 additions & 2 deletions packages/engine-core/src/tasks/task.rnv.app.create.ts
Expand Up @@ -15,6 +15,7 @@ import {
logTask,
TASK_APP_CREATE,
PARAMS,
RnvTask,
} from '@rnv/core';
import { ConfigFileApp } from '@rnv/core/lib/schema/configFiles/types';

Expand Down Expand Up @@ -163,11 +164,12 @@ export const taskRnvAppCreate: RnvTaskFn = async (c) => {
return true;
};

export default {
const Task: RnvTask = {
description: 'Create new app config',
fn: taskRnvAppCreate,
task: TASK_APP_CREATE,
params: PARAMS.withBase(),
skipPlatforms: true,
platforms: [],
};

export default Task;
13 changes: 10 additions & 3 deletions packages/engine-core/src/tasks/task.rnv.clean.ts
Expand Up @@ -13,6 +13,8 @@ import {
isSystemWin,
RnvTaskFn,
inquirerPrompt,
RnvTask,
TASK_CLEAN,
} from '@rnv/core';

function clearWindowsCacheFiles() {
Expand Down Expand Up @@ -198,17 +200,22 @@ export const taskRnvClean: RnvTaskFn = async (c) => {
logDebug('watchman not installed. skipping');
}

await executeAsync(c, 'npx rimraf -I $TMPDIR/metro-* && npx rimraf -I $TMPDIR/react-* && npx rimraf -I $TMPDIR/haste-*');
await executeAsync(
c,
'npx rimraf -I $TMPDIR/metro-* && npx rimraf -I $TMPDIR/react-* && npx rimraf -I $TMPDIR/haste-*'
);
}
}
return true;
};

export default {
const Task: RnvTask = {
description: 'Automatically removes all node_modules and lock in your project and its dependencies',
fn: taskRnvClean,
task: 'clean',
task: TASK_CLEAN,
params: PARAMS.withBase(),
platforms: [],
isGlobalScope: true,
};

export default Task;
6 changes: 4 additions & 2 deletions packages/engine-core/src/tasks/task.rnv.config.ts
@@ -1,4 +1,4 @@
import { logTask, PARAMS, RnvTaskFn, executeTask, TASK_CONFIGURE_SOFT, SUPPORTED_PLATFORMS } from '@rnv/core';
import { logTask, PARAMS, RnvTaskFn, executeTask, TASK_CONFIGURE_SOFT, SUPPORTED_PLATFORMS, RnvTask } from '@rnv/core';

const TASK_CONFIG = 'config';

Expand All @@ -12,10 +12,12 @@ export const taskRnvConfig: RnvTaskFn = async (c, _, originTask) => {
return true;
};

export default {
const Task: RnvTask = {
description: 'Display RNV config',
fn: taskRnvConfig,
task: TASK_CONFIG,
params: PARAMS.withBase(),
platforms: [...SUPPORTED_PLATFORMS],
};

export default Task;