UNPKG

@swell/cli

Version:

Swell's command line interface/utility

171 lines (170 loc) 6.87 kB
import { checkbox } from '@inquirer/prompts'; import { Args, Flags } from '@oclif/core'; import { CreateCollectionCommand } from '../../create-collection-command.js'; import { ConfigType } from '../../lib/apps/index.js'; import { toCollectionLabel, toCollectionName, toFileName, } from '../../lib/create/index.js'; import { parseEvents, parseFields, } from '../../lib/create/model.js'; import { SCHEMAS } from '../../lib/create/schemas.js'; export default class CreateModel extends CreateCollectionCommand { static args = { collection: Args.string({ default: '', description: 'Collection ID to create or extend (e.g., products)', }), }; static description = 'Interactive mode lets you choose to create a new collection or extend a standard one.\nTo discover standard collections: swell inspect models'; static examples = [ '$ swell create model', '$ swell create model products -y', '$ swell create model visitors -f title:string,photo:string -l "Visitors" -y', ]; static helpMeta = { usageDirect: '<collection> [...] -y', }; static flags = { label: Flags.string({ char: 'l', default: '', description: 'Display label (default: capitalized collection)', }), description: Flags.string({ char: 'd', default: '', description: 'Description', }), fields: Flags.string({ char: 'f', default: '', description: 'Fields as id:type pairs (e.g., title:string,price:currency)', }), events: Flags.string({ char: 'e', default: 'created,updated,deleted', description: 'Events to track (default: created,updated,deleted)', }), overwrite: Flags.boolean({ default: false, description: 'Overwrite existing file', }), yes: Flags.boolean({ char: 'y', description: 'Skip prompts, require all arguments', }), }; static summary = 'Create or extend a data model configuration in the models folder.'; createType = ConfigType.MODEL; async run() { const { args, flags } = await this.parse(CreateModel); const confirmYes = Boolean(flags.yes); // Helper validators const validEventValues = ['created', 'updated', 'deleted']; const validFieldTypes = [ 'collection', 'currency', 'image', 'int', 'link', 'string', ]; const validateEvents = (values) => { const invalid = values.filter((v) => !validEventValues.includes(v)); if (invalid.length > 0) { this.error(`Invalid event(s): ${invalid.join(', ')}\n\nValid events: ${validEventValues.join(', ')}\n\nExample: swell create model visitors -e created,updated -y`, { exit: 1 }); } }; const validateFields = (pairs) => { const invalid = []; for (const pair of pairs) { if (!pair.includes(':')) { invalid.push(pair); continue; } const type = pair.split(':')[1]?.trim(); if (!validFieldTypes.includes(type)) { invalid.push(pair); } } if (invalid.length > 0) { this.error(`Invalid field(s): ${invalid.join(', ')}\n\nValid types: ${validFieldTypes.join(', ')}\n\nExample: swell create model visitors -f title:string,price:currency -y`, { exit: 1 }); } }; if (confirmYes) { const argCollection = args.collection; if (!argCollection) { this.error('Missing required argument for non-interactive mode: COLLECTION\n\nExample: swell create model products -y\n\nTip: run `swell inspect models` to list standard collections you can extend.', { exit: 1 }); } const collection = toCollectionName(argCollection); const label = flags.label || toCollectionLabel(collection); const description = flags.description || ''; const eventsRaw = (flags.events || 'created,updated,deleted'); const eventsList = eventsRaw .split(',') .map((v) => v.trim()) .filter(Boolean); validateEvents(eventsList); const fieldsRaw = (flags.fields || ''); const fieldPairs = fieldsRaw ? fieldsRaw .split(',') .map((v) => v.trim()) .filter(Boolean) : []; validateFields(fieldPairs); const fileName = toFileName(collection); const fileBody = { $schema: SCHEMAS.MODEL, collection, description, fields: parseFields(fieldPairs), label, events: parseEvents(eventsList), }; await this.createFile({ fileBody, fileName }, flags.overwrite, /* shouldConfirm */ false); return; } // Interactive flow (prompts) const { collection, description, label } = await this.promptCollection(); const fileName = toFileName(collection); const fileBody = { $schema: SCHEMAS.MODEL, collection, }; const { events, fields, overwrite } = flags; if (label) fileBody.label = label; fileBody.description = description; if (fields) { const pairs = fields .split(',') .map((v) => v.trim()) .filter(Boolean); validateFields(pairs); fileBody.fields = parseFields(pairs); } else { fileBody.fields = {}; } // If events were provided via flag, use them; otherwise prompt if (events && events !== 'created,updated,deleted') { const eventsList = events .split(',') .map((v) => v.trim()) .filter(Boolean); validateEvents(eventsList); fileBody.events = parseEvents(eventsList); } else { const eventsInput = await checkbox({ choices: [ { name: 'created', value: 'created' }, { name: 'updated', value: 'updated' }, { name: 'deleted', value: 'deleted' }, ], message: 'Which events should be captured by default?', }); fileBody.events = parseEvents(eventsInput); } await this.createFile({ fileBody, fileName }, overwrite); } }