From 872ceb5656fab1b63a186fc78cdf2141bba4cb88 Mon Sep 17 00:00:00 2001 From: Ross Stenersen Date: Mon, 6 Oct 2025 14:04:57 -0500 Subject: [PATCH] refactor: update device profile and preference create commands to use new inquirer --- src/commands/devicepreferences/create.ts | 37 ++++------- src/lib/command/util/deviceprofiles-create.ts | 65 ++++++++----------- 2 files changed, 40 insertions(+), 62 deletions(-) diff --git a/src/commands/devicepreferences/create.ts b/src/commands/devicepreferences/create.ts index e2327f07..50b81055 100644 --- a/src/commands/devicepreferences/create.ts +++ b/src/commands/devicepreferences/create.ts @@ -1,4 +1,4 @@ -import inquirer from 'inquirer' +import { select } from '@inquirer/prompts' import { type ArgumentsCamelCase, type Argv, type CommandModule } from 'yargs' import { type DevicePreferenceCreate, type PreferenceType } from '@smartthings/core-sdk' @@ -17,6 +17,7 @@ import { import { userInputProcessor } from '../../lib/command/input-processor.js' import { tableFieldDefinitions } from '../../lib/command/util/devicepreferences-util.js' import { + booleanInput, optionalIntegerInput, optionalNumberInput, optionalStringInput, @@ -64,19 +65,13 @@ const getInputFromUser = async (): Promise => { const title = await stringInput('Preference title:') const description = await optionalStringInput('Preference description:') - const required = (await inquirer.prompt({ - type: 'confirm', - name: 'value', - message: 'Is the preference required?', - default: false, - })).value as boolean + const required = await booleanInput('Is the preference required?', { default: false }) - const preferenceType = (await inquirer.prompt({ - type: 'list', - name: 'preferenceType', + const preferenceTypeChoices: PreferenceType[] = ['integer', 'number', 'boolean', 'string', 'enumeration'] + const preferenceType = await select({ message: 'Choose a type for your preference.', - choices: ['integer', 'number', 'boolean', 'string', 'enumeration'], - })).preferenceType as PreferenceType + choices: preferenceTypeChoices, + }) as PreferenceType const base = { name, title, description, required, @@ -115,14 +110,12 @@ const getInputFromUser = async (): Promise => { } if (preferenceType === 'boolean') { - const defaultValue = (await inquirer.prompt({ - type: 'list', - name: 'defaultValue', + const defaultValue = await select({ message: 'Choose a default value.', choices: [{ name: 'none', value: undefined }, { name: 'true', value: true }, { name: 'false', value: false }], - })).defaultValue as boolean | undefined + }) return { ...base, preferenceType, definition: { default: defaultValue ?? undefined, @@ -136,13 +129,11 @@ const getInputFromUser = async (): Promise => { 'Optional maximum length.', { validate: numberValidateFn({ min: minLength || 1 }) }, ) - const stringType = (await inquirer.prompt({ - type: 'list', - name: 'stringType', + const stringType = await select({ message: 'Choose a type of string.', choices: ['text', 'password', 'paragraph'], default: 'text', - })).stringType as 'text' | 'password' | 'paragraph' + }) as 'text' | 'password' | 'paragraph' const defaultValue = await optionalStringInput('Optional default value.', { validate: input => { if (minLength !== undefined && input.length < minLength) { @@ -179,15 +170,13 @@ const getInputFromUser = async (): Promise => { } } while (name) - const defaultValue = (await inquirer.prompt({ - type: 'list', - name: 'defaultValue', + const defaultValue = await select({ message: 'Choose a default option.', choices: [ { name: 'none', value: undefined }, ...Object.entries(options).map(([name, value]) => ({ name: `${value} (${name})`, value: name }))], default: undefined, - })).defaultValue as 'text' | 'password' | 'paragraph' + }) return { ...base, preferenceType, definition: { diff --git a/src/lib/command/util/deviceprofiles-create.ts b/src/lib/command/util/deviceprofiles-create.ts index f7c3fb8c..d934bd95 100644 --- a/src/lib/command/util/deviceprofiles-create.ts +++ b/src/lib/command/util/deviceprofiles-create.ts @@ -1,4 +1,4 @@ -import inquirer from 'inquirer' +import { input, select } from '@inquirer/prompts' import { type DeviceProfile, @@ -8,11 +8,12 @@ import { type SmartThingsClient, } from '@smartthings/core-sdk' +import { optionalStringInput, stringInput } from '../../user-query.js' +import { fatalError } from '../../util.js' +import { APICommand } from '../api-command.js' import { chooseCapabilityFiltered } from './capabilities-choose.js' import { type CapabilityId } from './capabilities-util.js' import { cleanupForCreate, cleanupForUpdate, DeviceDefinitionRequest } from './deviceprofiles-util.js' -import { APICommand } from '../api-command.js' -import { fatalError } from '../../util.js' const capabilitiesWithoutPresentations = ['healthCheck', 'execute'] @@ -128,18 +129,20 @@ export const capabilityDefined = async (client: SmartThingsClient, idStr: string } } -export const promptAndAddCapability = async (command: APICommand, deviceProfile: DeviceProfileRequest, componentId: string, prompt = 'Capability ID'): Promise => { +export const promptAndAddCapability = async ( + command: APICommand, + deviceProfile: DeviceProfileRequest, + componentId: string, + prompt = 'Capability Id', +): Promise => { let capabilityId: CapabilityId = { id: '', version: 0 } - const idStr = (await inquirer.prompt({ - type: 'input', - name: 'id', + const idStr = await input({ message: `${prompt} (type ? for a list):`, - validate: async (input) => { - return (input.endsWith('?') || input === '' || await capabilityDefined(command.client, input)) + validate: async (input) => + (input.endsWith('?') || input === '' || await capabilityDefined(command.client, input)) ? true - : `Invalid ID "${input}". Please enter a valid capability ID or ? for a list of available capabilities.` - }, - })).id + : `Invalid Id "${input}". Please enter a valid capability Id or ? for a list of available capabilities.`, + }) if (idStr) { if (idStr.endsWith('?')) { @@ -162,34 +165,25 @@ export const promptAndAddCapability = async (command: APICommand, deviceProfile: return capabilityId } +const componentRegExp = new RegExp(/^[0-9a-zA-Z]{1,100}$/) export const promptAndAddComponent = async (deviceProfile: DeviceProfileRequest, previousComponentId: string): Promise => { const components = deviceProfile.components || [] - let componentId: string = (await inquirer.prompt({ - type: 'input', - name: 'componentId', - message: 'ComponentId ID: ', - validate: (input) => { - return (new RegExp(/^[0-9a-zA-Z]{1,100}$/).test(input) && !components.find(it => it.id === input)) || 'Invalid component name' - }, - })).componentId + const componentId = await optionalStringInput('Component Id:', { + validate: input => (componentRegExp.test(input) && !components.find(it => it.id === input)) || 'Invalid component name', + }) if (componentId) { components.push({ id: componentId, capabilities: [] }) - } else { - componentId = previousComponentId + return componentId } - return componentId + return previousComponentId } +const profileNameRegExp = new RegExp(/^(?!\s)[-_!.~'() *0-9a-zA-Z]{1,100}(? => { - const name = (await inquirer.prompt({ - type: 'input', - name: 'deviceProfileName', - message: 'Device Profile Name:', - validate: (input: string) => { - return new RegExp(/^(?!\s)[-_!.~'() *0-9a-zA-Z]{1,100}(? profileNameRegExp.test(input) || 'Invalid device profile name', + }) const deviceProfile: DeviceProfileRequest = { name, @@ -203,7 +197,7 @@ export const getInputFromUser = async (command: APICommand): Promise