Skip to content

Commit

Permalink
refactor: rename CLI command to preferences
Browse files Browse the repository at this point in the history
  • Loading branch information
natemoo-re committed Nov 27, 2023
1 parent 40ec2e7 commit 6db6799
Show file tree
Hide file tree
Showing 6 changed files with 198 additions and 63 deletions.
50 changes: 0 additions & 50 deletions packages/astro/src/cli/config/index.ts

This file was deleted.

14 changes: 7 additions & 7 deletions packages/astro/src/cli/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ type CLICommand =
| 'sync'
| 'check'
| 'info'
| 'config'
| 'preferences'
| 'telemetry';

/** Display --help flag */
Expand All @@ -34,7 +34,7 @@ async function printAstroHelp() {
['info', 'List info about your current Astro setup.'],
['preview', 'Preview your build locally.'],
['sync', 'Generate content collection types.'],
['config', 'Configure user preferences.'],
['preferences', 'Configure user preferences.'],
['telemetry', 'Configure telemetry settings.'],
],
'Global Flags': [
Expand Down Expand Up @@ -66,7 +66,7 @@ function resolveCommand(flags: yargs.Arguments): CLICommand {
'add',
'sync',
'telemetry',
'config',
'preferences',
'dev',
'build',
'preview',
Expand Down Expand Up @@ -117,10 +117,10 @@ async function runCommand(cmd: string, flags: yargs.Arguments) {
const exitCode = await sync({ flags });
return process.exit(exitCode);
}
case 'config': {
const { config } = await import('./config/index.js');
const [key, value] = flags._.slice(3).map(v => v.toString());
const exitCode = await config(key, value, { flags });
case 'preferences': {
const { preferences } = await import('./preferences/index.js');
const [subcommand, key, value] = flags._.slice(3).map(v => v.toString());
const exitCode = await preferences(subcommand, key, value, { flags });
return process.exit(exitCode);
}
}
Expand Down
151 changes: 151 additions & 0 deletions packages/astro/src/cli/preferences/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
/* eslint-disable no-console */
import type yargs from 'yargs-parser';
import type { AstroSettings } from '../../@types/astro.js';

import { cyan } from 'kleur/colors';
import { fileURLToPath } from 'node:url';

import * as msg from '../../core/messages.js';
import { flagsToAstroInlineConfig } from '../flags.js';
import { resolveConfig } from '../../core/config/config.js';
import { createSettings } from '../../core/config/settings.js';
import { isValidKey, coerce, type PreferenceKey } from '../../preferences/index.js';
import { error, log } from '../../core/logger/core.js';
import { nodeLogOptions } from '../../core/logger/node.js';
import { DEFAULT_PREFERENCES, type Preferences } from '../../preferences/defaults.js';
import dlv from 'dlv';


interface PreferencesOptions {
flags: yargs.Arguments;
}

const PREFERENCES_SUBCOMMANDS = ['get', 'set', 'enable', 'disable', 'delete', 'reset', 'list'] as const;
export type Subcommand = typeof PREFERENCES_SUBCOMMANDS[number];

function isValidSubcommand(subcommand: string): subcommand is Subcommand {
return PREFERENCES_SUBCOMMANDS.includes(subcommand as Subcommand);
}

export async function preferences(subcommand: string, key: string, value: string | undefined, { flags }: PreferencesOptions): Promise<number> {
if (!isValidSubcommand(subcommand) || flags?.help || flags?.h) {
printHelp({
commandName: 'astro preferences',
usage: 'set [key] [:value]',
tables: {
Flags: [
['--global', 'Change setting value globally.'],
['--help (-h)', 'See all available flags.'],
],
},
description: `Starts a local server to serve your static dist/ directory. Check ${cyan(
'https://docs.astro.build/en/reference/cli-reference/#astro-preview'
)} for more information.`,
});
return 0;
}

const inlineConfig = flagsToAstroInlineConfig(flags);
const { astroConfig } = await resolveConfig(inlineConfig ?? {}, 'dev');
const settings = await createSettings(astroConfig, fileURLToPath(astroConfig.root));
const opts: SubcommandOptions = {
location: flags.global ? 'global' : undefined,
json: flags.json
}

if (subcommand === 'list') {
return listPreferences(settings, opts);
}

if (subcommand === 'enable' || subcommand === 'disable') {
key = `${key}.enabled` as PreferenceKey;
}

if (!isValidKey(key)) {
error(nodeLogOptions, 'preferences', `Unknown preference "${key}"\n`);
return 1;
}

if (subcommand === 'set' && value === undefined) {
const type = typeof dlv(DEFAULT_PREFERENCES, key);
// TODO: better error message
error(nodeLogOptions, 'preferences', `Please provide a ${type} value for "${key}"\n`);
return 1;
}

switch (subcommand) {
case 'get': return getPreference(settings, key, opts);
case 'set': return setPreference(settings, key, value, opts);
case 'reset':
case 'delete': return resetPreference(settings, key, opts);
case 'enable': return enablePreference(settings, key, opts);
case 'disable': return disablePreference(settings, key, opts);
}
}

interface SubcommandOptions {
location?: 'global' | 'project';
json?: boolean;
}

// Default `location` to "project" to avoid reading default preferencesa
async function getPreference(settings: AstroSettings, key: PreferenceKey, { location = 'project' }: SubcommandOptions) {
try {
const value = await settings.preferences.get(key, { location });
// TODO: guard against printing objects
if (value !== undefined) {
console.log(msg.preferenceGet(key, value));
} else {
const defaultValue = await settings.preferences.get(key);
console.log(msg.preferenceDefault(key, defaultValue));
}
return 0;
} catch {}
return 1;
}

async function setPreference(settings: AstroSettings, key: PreferenceKey, value: unknown, { location }: SubcommandOptions) {
try {
await settings.preferences.set(key, value as any, { location });
console.log(msg.preferenceSet(key, value))
return 0;
} catch {}
return 1;
}

async function enablePreference(settings: AstroSettings, key: PreferenceKey, { location }: SubcommandOptions) {
try {
await settings.preferences.set(key, true, { location });
console.log(msg.preferenceEnabled(key.replace('.enabled', '')))
return 0;
} catch {}
return 1;
}

async function disablePreference(settings: AstroSettings, key: PreferenceKey, { location }: SubcommandOptions) {
try {
await settings.preferences.set(key, false, { location });
console.log(msg.preferenceDisabled(key.replace('.enabled', '')))
return 0;
} catch {}
return 1;
}

async function resetPreference(settings: AstroSettings, key: PreferenceKey, { location }: SubcommandOptions) {
try {
await settings.preferences.set(key, undefined as any, { location });
console.log(msg.preferenceReset(key))
return 0;
} catch {}
return 1;
}

async function listPreferences(settings: AstroSettings, { location, json }: SubcommandOptions) {
const store = await settings.preferences.getAll({ location });
if (json) {
console.log(JSON.stringify(store, null, 2));
}
// TODO: pretty print
console.log(JSON.stringify(store, null, 2));
return 0;
}
24 changes: 24 additions & 0 deletions packages/astro/src/core/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,30 @@ export function telemetryEnabled() {
].join('\n');
}

export function preferenceEnabled(name: string) {
return `${green('◉')} ${name} is now ${bgGreen(black(' enabled '))}\n`;
}

export function preferenceSet(name: string, value: any) {
return `${green('◉')} ${name} has been set to ${bgGreen(black(` ${JSON.stringify(value)} `))}\n`;
}

export function preferenceGet(name: string, value: any) {
return `${green('◉')} ${name} is set to ${bgGreen(black(` ${JSON.stringify(value)} `))}\n`;
}

export function preferenceDefault(name: string, value: any) {
return `${yellow('◯')} ${name} has not been set. It defaults to ${bgYellow(black(` ${JSON.stringify(value)} `))}\n`;
}

export function preferenceDisabled(name: string) {
return `${yellow('◯')} ${name} is now ${bgYellow(black(' disabled '))}\n`;
}

export function preferenceReset(name: string) {
return `${cyan('◆')} ${name} has been reset ${bgCyan(black(' reset '))}\n`;
}

export function telemetryDisabled() {
return [
green('▶ Anonymous telemetry ') + bgGreen(' disabled '),
Expand Down
19 changes: 13 additions & 6 deletions packages/astro/src/preferences/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,15 @@ export interface PreferenceOptions {
location?: 'global' | 'project';
}

export type PreferenceKey = DotKeys<Preferences>;

export interface AstroPreferences {
get<Key extends DotKeys<Preferences>>(key: Key, opts?: PreferenceOptions): GetDotKey<Preferences, Key>;
set<Key extends DotKeys<Preferences>>(key: Key, value: GetDotKey<Preferences, Key>, opts?: PreferenceOptions): void;
get<Key extends PreferenceKey>(key: Key, opts?: PreferenceOptions): Promise<GetDotKey<Preferences, Key>>;
set<Key extends PreferenceKey>(key: Key, value: GetDotKey<Preferences, Key>, opts?: PreferenceOptions): Promise<void>;
getAll(opts?: PreferenceOptions): Promise<Record<string, any>>;
}

export function isValidKey(key: string): key is DotKeys<Preferences> {
export function isValidKey(key: string): key is PreferenceKey {
return dget(DEFAULT_PREFERENCES, key) !== undefined;
}
export function coerce(key: string, value: string | number) {
Expand All @@ -49,13 +52,17 @@ export default function createPreferences(config: AstroConfig): AstroPreferences
const stores = { global, project };

return {
get(key, { location } = {}) {
async get(key, { location } = {}) {
if (!location) return project.get(key) ?? global.get(key) ?? dget(DEFAULT_PREFERENCES, key);
return stores[location].get(key);
},
set(key, value, { location = 'project' } = {}) {
async set(key, value, { location = 'project' } = {}) {
stores[location].set(key, value);
}
},
async getAll({ location } = {}) {
if (!location) return Object.assign({}, stores['global'].getAll(), stores['project'].getAll());
return stores[location].getAll();
},
}
}

Expand Down
3 changes: 3 additions & 0 deletions packages/astro/src/preferences/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,7 @@ export class PreferenceStore {
dset(this.store, key, value);
this.write();
}
getAll(): Record<string, any> {
return this.store;
}
}

0 comments on commit 6db6799

Please sign in to comment.