Skip to content

Commit 435d0d6

Browse files
committed
feat: rewrite to use config store to no be reliant on program for options
1 parent e77b38a commit 435d0d6

13 files changed

Lines changed: 408 additions & 412 deletions

File tree

packages/cli/commands/apps.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import chalk from "chalk";
2-
import { Command, program } from "commander";
2+
import { Command } from "commander";
33
import ora from "ora";
44

55
import { listApps } from "../services/bootstrap.js";
6-
import { handleError } from "../utils/error.js";
6+
import { configStore } from "../stores/config.js";
7+
import { handleError } from "../utils/errors.js";
78

89
export const listAppsAction = async () => {
9-
const { baseUrl } = program.opts();
10+
const baseUrl = configStore.getConfig("baseUrl");
1011
const spinner = ora(`Loading apps from ${chalk.cyan(baseUrl)}...`).start();
1112
try {
1213
const apps = await listApps();

packages/cli/commands/auth.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
import chalk from "chalk";
2-
import { Command, program } from "commander";
2+
import { Command } from "commander";
33
import ora from "ora";
44

5-
import { authenticateUser, setToken } from "../utils/auth.js";
6-
import { handleError } from "../utils/error.js";
5+
import { authStore } from "../stores/auth.js";
6+
import { configStore } from "../stores/config.js";
7+
import { authenticateUser } from "../utils/auth.js";
8+
import { handleError } from "../utils/errors.js";
79

810
export const loginAction = async () => {
9-
const { baseUrl } = program.opts();
11+
const baseUrl = configStore.getConfig("baseUrl");
1012
const spinner = ora(`Logging in to ${chalk.cyan(baseUrl)}...`).start();
1113
try {
1214
await authenticateUser(baseUrl);
@@ -18,10 +20,10 @@ export const loginAction = async () => {
1820
};
1921

2022
export const logoutAction = async () => {
21-
const { baseUrl } = program.opts();
23+
const baseUrl = configStore.getConfig("baseUrl");
2224
const spinner = ora("Logging out...").start();
2325
try {
24-
await setToken(baseUrl, undefined);
26+
await authStore.setToken(baseUrl, undefined);
2527
spinner.succeed("Logged out successfully! 👋");
2628
} catch (error) {
2729
spinner.fail("Logout failed");

packages/cli/commands/features.ts

Lines changed: 45 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,35 @@
11
import { input } from "@inquirer/prompts";
22
import chalk from "chalk";
3-
import { Command, program } from "commander";
3+
import { Command } from "commander";
44
import { mkdir, writeFile } from "node:fs/promises";
55
import { dirname, isAbsolute, join } from "node:path";
66
import ora, { Ora } from "ora";
77

88
import { createFeature, listFeatures } from "../services/features.js";
9-
import { getConfig, getProjectPath } from "../utils/config.js";
10-
import { handleError } from "../utils/error.js";
9+
import { configStore } from "../stores/config.js";
10+
import { handleError, MissingAppIdError } from "../utils/errors.js";
1111
import { genDTS, genFeatureKey, KeyFormatPatterns } from "../utils/gen.js";
12-
import { options } from "../utils/options.js";
13-
14-
type AppIdArgs = {
15-
appId: string;
16-
};
17-
18-
type CreateFeatureArgs = AppIdArgs & {
12+
import {
13+
appIdOption,
14+
featureKeyOption,
15+
featureNameArgument,
16+
typesOutOption,
17+
} from "../utils/options.js";
18+
19+
type CreateFeatureArgs = {
1920
key?: string;
2021
};
2122

22-
type GenerateTypesArgs = AppIdArgs & {
23-
out: string;
24-
};
25-
2623
export const createFeatureAction = async (
2724
name: string | undefined,
28-
{ appId, key }: CreateFeatureArgs,
25+
{ key }: CreateFeatureArgs,
2926
) => {
30-
const { baseUrl } = program.opts();
27+
const { baseUrl, appId } = configStore.getConfig();
3128
let spinner: Ora | undefined;
3229
let existingKeys: string[] = [];
30+
3331
try {
32+
if (!appId) throw new MissingAppIdError();
3433
spinner = ora(
3534
`Loading features of app ${chalk.cyan(appId)} at ${chalk.cyan(baseUrl)}...`,
3635
).start();
@@ -42,6 +41,7 @@ export const createFeatureAction = async (
4241
} catch (error) {
4342
spinner?.fail("Loading features failed");
4443
void handleError(error, "Features Create");
44+
return;
4545
}
4646

4747
try {
@@ -53,7 +53,7 @@ export const createFeatureAction = async (
5353
}
5454

5555
if (!key) {
56-
const keyFormat = getConfig("keyFormat") ?? "custom";
56+
const keyFormat = configStore.getConfig("keyFormat") ?? "custom";
5757
key = await input({
5858
message: "New feature key:",
5959
default: genFeatureKey(name, keyFormat, existingKeys),
@@ -72,31 +72,32 @@ export const createFeatureAction = async (
7272
}
7373
};
7474

75-
export const listFeaturesAction = async ({ appId }: AppIdArgs) => {
76-
const { baseUrl } = program.opts();
77-
const spinner = ora(
78-
`Loading features of app ${chalk.cyan(appId)} at ${chalk.cyan(baseUrl)}...`,
79-
).start();
75+
export const listFeaturesAction = async () => {
76+
const { baseUrl, appId } = configStore.getConfig();
77+
let spinner: Ora | undefined;
78+
8079
try {
80+
if (!appId) throw new MissingAppIdError();
81+
spinner = ora(
82+
`Loading features of app ${chalk.cyan(appId)} at ${chalk.cyan(baseUrl)}...`,
83+
).start();
8184
const features = await listFeatures(appId);
8285
spinner.succeed(
8386
`Loaded features of app ${chalk.cyan(appId)} at ${chalk.cyan(baseUrl)}`,
8487
);
8588
console.table(features);
8689
} catch (error) {
87-
spinner.fail("Loading features failed");
90+
spinner?.fail("Loading features failed");
8891
void handleError(error, "Features List");
8992
}
9093
};
9194

92-
export const generateTypesAction = async ({
93-
appId,
94-
out,
95-
}: GenerateTypesArgs) => {
96-
const { baseUrl } = program.opts();
95+
export const generateTypesAction = async () => {
96+
const { baseUrl, appId, typesPath } = configStore.getConfig();
9797
let spinner: Ora | undefined;
9898
let featureKeys: string[] = [];
9999
try {
100+
if (!appId) throw new MissingAppIdError();
100101
spinner = ora(
101102
`Loading features of app ${chalk.cyan(appId)} at ${chalk.cyan(baseUrl)}...`,
102103
).start();
@@ -107,12 +108,15 @@ export const generateTypesAction = async ({
107108
} catch (error) {
108109
spinner?.fail("Loading features failed");
109110
void handleError(error, "Features Types");
111+
return;
110112
}
111113

112114
try {
113115
spinner = ora("Generating feature types...").start();
114116
const types = genDTS(featureKeys);
115-
const outPath = isAbsolute(out) ? out : join(getProjectPath(), out);
117+
const outPath = isAbsolute(typesPath)
118+
? typesPath
119+
: join(configStore.getProjectPath(), typesPath);
116120
await mkdir(dirname(outPath), { recursive: true });
117121
await writeFile(outPath, types);
118122
spinner.succeed("Generated feature types successfully");
@@ -131,39 +135,29 @@ export function registerFeatureCommands(cli: Command) {
131135
featuresCommand
132136
.command("create")
133137
.description("Create a new feature")
134-
.requiredOption(
135-
options.appId.flags,
136-
options.appId.description,
137-
getConfig(options.appId.configKey),
138-
)
139-
.option(options.featureKey.flags, options.featureKey.description)
140-
.argument(options.featureName.flags, options.featureName.description)
138+
.addOption(appIdOption)
139+
.addOption(featureKeyOption)
140+
.addArgument(featureNameArgument)
141141
.action(createFeatureAction);
142142

143143
featuresCommand
144144
.command("list")
145145
.description("List all features")
146-
.requiredOption(
147-
options.appId.flags,
148-
options.appId.description,
149-
getConfig(options.appId.configKey),
150-
)
146+
.addOption(appIdOption)
151147
.action(listFeaturesAction);
152148

153149
featuresCommand
154150
.command("types")
155151
.description("Generate feature types")
156-
.requiredOption(
157-
options.appId.flags,
158-
options.appId.description,
159-
getConfig(options.appId.configKey),
160-
)
161-
.requiredOption(
162-
options.typesOut.flags,
163-
options.typesOut.description,
164-
getConfig(options.typesOut.configKey) ?? options.typesOut.fallback,
165-
)
152+
.addOption(appIdOption)
153+
.addOption(typesOutOption)
166154
.action(generateTypesAction);
167155

156+
// Update the config with the cli override values
157+
featuresCommand.hook("preAction", (command) => {
158+
const { appId, out } = command.opts();
159+
configStore.setConfig({ appId, typesPath: out });
160+
});
161+
168162
cli.addCommand(featuresCommand);
169163
}

packages/cli/commands/init.ts

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,34 @@
11
import { input, select } from "@inquirer/prompts";
22
import chalk from "chalk";
3-
import { Command, program } from "commander";
3+
import { Command } from "commander";
44
import { relative } from "node:path";
55
import ora, { Ora } from "ora";
66

77
import { App, listApps } from "../services/bootstrap.js";
8-
import { createConfigFile, getConfigPath } from "../utils/config.js";
8+
import { configStore } from "../stores/config.js";
99
import { chalkBrand, DEFAULT_TYPES_PATH } from "../utils/constants.js";
10-
import { handleError } from "../utils/error.js";
11-
import { options } from "../utils/options.js";
10+
import { handleError } from "../utils/errors.js";
11+
import { initOverrideOption } from "../utils/options.js";
1212

1313
type InitArgs = {
1414
force?: boolean;
1515
};
1616

17-
export const initAction = async (args: InitArgs) => {
17+
export const initAction = async (args: InitArgs = {}) => {
1818
let spinner: Ora | undefined;
1919
let apps: App[] = [];
2020

2121
try {
22-
// Check if already initialized
23-
const configPath = getConfigPath();
22+
// Check if config already exists
23+
const configPath = configStore.getConfigPath();
2424
if (configPath && !args.force) {
2525
throw new Error(
2626
"Bucket is already initialized. Use --force to overwrite.",
2727
);
2828
}
2929

3030
console.log(chalkBrand("\nWelcome to Bucket! 🪣\n"));
31-
const { baseUrl } = program.opts();
31+
const baseUrl = configStore.getConfig("baseUrl");
3232

3333
// Load apps
3434
spinner = ora(`Loading apps from ${chalk.cyan(baseUrl)}...`).start();
@@ -37,15 +37,17 @@ export const initAction = async (args: InitArgs) => {
3737
} catch (error) {
3838
spinner?.fail("Loading apps failed");
3939
void handleError(error, "Initialization");
40+
return;
4041
}
4142

4243
try {
43-
const { baseUrl, apiUrl } = program.opts();
4444
let appId: string | undefined;
4545
const nonDemoApps = apps.filter((app) => !app.demo);
4646

4747
// If there is only one non-demo app, select it automatically
48-
if (nonDemoApps.length === 1) {
48+
if (apps.length === 0) {
49+
throw new Error("You don't have any apps yet. Please create one.");
50+
} else if (nonDemoApps.length === 1) {
4951
appId = nonDemoApps[0].id;
5052
console.log(
5153
chalk.gray(
@@ -72,20 +74,18 @@ export const initAction = async (args: InitArgs) => {
7274
default: DEFAULT_TYPES_PATH,
7375
});
7476

77+
// Update config
78+
configStore.setConfig({
79+
appId,
80+
keyFormat,
81+
typesPath,
82+
});
83+
7584
// Create config file
7685
spinner = ora("Creating configuration...").start();
77-
await createConfigFile(
78-
{
79-
baseUrl,
80-
apiUrl,
81-
appId,
82-
typesPath,
83-
keyFormat,
84-
},
85-
args.force,
86-
);
86+
await configStore.saveConfigFile(args.force);
8787
spinner.succeed(
88-
`Configuration created at ${chalk.cyan(relative(process.cwd(), getConfigPath()!))}`,
88+
`Configuration created at ${chalk.cyan(relative(process.cwd(), configStore.getConfigPath()!))}`,
8989
);
9090
} catch (error) {
9191
spinner?.fail("Configuration creation failed");
@@ -97,6 +97,6 @@ export function registerInitCommand(cli: Command) {
9797
cli
9898
.command("init")
9999
.description("Initialize a new Bucket configuration")
100-
.option(options.initOverride.flags, options.initOverride.description)
100+
.addOption(initOverrideOption)
101101
.action(initAction);
102102
}

0 commit comments

Comments
 (0)