@fireberry/cli 0.2.5-beta.0 → 0.2.5-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -13,7 +13,13 @@ const program = new Command();
13
13
  program
14
14
  .name("fireberry")
15
15
  .description("Fireberry developer CLI")
16
- .version(packageJson.version);
16
+ .version(packageJson.version)
17
+ .configureOutput({
18
+ outputError: (str, write) => {
19
+ const formatted = str.replace(/^error:/i, 'Error:');
20
+ write(chalk.red(formatted));
21
+ }
22
+ });
17
23
  program
18
24
  .command("init")
19
25
  .argument("[tokenid]", "Fireberry token id")
@@ -23,10 +29,9 @@ program
23
29
  });
24
30
  program
25
31
  .command("create")
26
- .argument("[name...]", "App name")
27
- .description("Create a new Fireberry app")
28
- .action(async (nameArgs) => {
29
- const name = nameArgs ? nameArgs.join("-") : undefined;
32
+ .argument("[name]", "App name")
33
+ .description("Create a new Fireberry app with a component")
34
+ .action(async (name) => {
30
35
  await runCreate({ name });
31
36
  });
32
37
  program
@@ -13,6 +13,12 @@ import { HEIGHT_OPTIONS } from "../constants/height-options.js";
13
13
  const __filename = fileURLToPath(import.meta.url);
14
14
  const __dirname = path.dirname(__filename);
15
15
  const VALID_COMPONENT_TYPES = Object.values(COMPONENT_TYPE);
16
+ function sanitizeComponentName(name) {
17
+ return name
18
+ .toLowerCase()
19
+ .replace(/[^a-z0-9]+/g, "-")
20
+ .replace(/^-+|-+$/g, "");
21
+ }
16
22
  function validateComponentType(type) {
17
23
  if (!VALID_COMPONENT_TYPES.includes(type)) {
18
24
  throw new Error(`Invalid component type: "${type}". Valid types are: ${VALID_COMPONENT_TYPES.join(", ")}`);
@@ -118,17 +124,17 @@ export async function runCreateComponent({ type, name, }) {
118
124
  throw new Error(`Component with name "${componentName}" already exists in manifest.yml`);
119
125
  }
120
126
  const validatedType = validateComponentType(componentType);
127
+ const sanitizedName = sanitizeComponentName(componentName);
121
128
  const spinner = ora();
122
129
  try {
123
130
  const componentSettings = await promptForSettings(validatedType);
124
131
  spinner.text = chalk.cyan(`Creating Vite React app for "${chalk.cyan(componentName)}"...`);
125
132
  spinner.start();
126
- const componentDir = path.join(process.cwd(), "static", componentName);
133
+ const componentDir = path.join(process.cwd(), componentName);
127
134
  await fs.ensureDir(componentDir);
128
- // Create Vite app with React template
129
135
  spinner.text = `Running npm create vite@latest...`;
130
- const viteResult = spawnSync(`npm create vite@latest ${componentName} -- --template react --no-interactive`, {
131
- cwd: path.join(process.cwd(), "static"),
136
+ const viteResult = spawnSync(`npm create vite@latest ${sanitizedName} -- --template react --no-interactive`, {
137
+ cwd: process.cwd(),
132
138
  stdio: "inherit",
133
139
  shell: true,
134
140
  });
@@ -177,7 +183,7 @@ export async function runCreateComponent({ type, name, }) {
177
183
  type: validatedType,
178
184
  title: componentName,
179
185
  id: componentId,
180
- path: `static/${componentName}/dist`,
186
+ path: `${componentName}/dist`,
181
187
  settings: componentSettings,
182
188
  };
183
189
  if (!manifest.components) {
@@ -193,9 +199,9 @@ export async function runCreateComponent({ type, name, }) {
193
199
  spinner.succeed(`Successfully created component "${chalk.cyan(componentName)}"!`);
194
200
  console.log(chalk.gray(`Component ID: ${componentId}`));
195
201
  console.log(chalk.gray(`Type: ${validatedType}`));
196
- console.log(chalk.gray(`Path: static/${componentName}/dist`));
197
- console.log(chalk.green("\nšŸŽ‰ Your component is ready!"));
198
- console.log(chalk.white(` cd static/${componentName}`));
202
+ console.log(chalk.gray(`Path: ${sanitizedName}/dist`));
203
+ console.log(chalk.green(`\nYour component "${chalk.cyan(componentName)}" is ready!`));
204
+ console.log(chalk.white(` cd ${sanitizedName}`));
199
205
  console.log(chalk.white(` npm run dev # Start development server`));
200
206
  console.log(chalk.white(` npm run build # Build for production`));
201
207
  }
@@ -2,13 +2,12 @@ import inquirer from "inquirer";
2
2
  import path from "node:path";
3
3
  import fs from "fs-extra";
4
4
  import { v4 as uuidv4 } from "uuid";
5
- import { fileURLToPath } from "node:url";
5
+ import yaml from "js-yaml";
6
6
  import ora from "ora";
7
7
  import chalk from "chalk";
8
8
  import { createApp } from "../api/requests.js";
9
9
  import { getManifest } from "../utils/components.utils.js";
10
- const __filename = fileURLToPath(import.meta.url);
11
- const __dirname = path.dirname(__filename);
10
+ import { runCreateComponent } from "./create-component.js";
12
11
  function slugifyName(name) {
13
12
  const validPattern = /^[a-zA-Z0-9_-]+$/;
14
13
  if (!validPattern.test(name)) {
@@ -20,44 +19,55 @@ export async function runCreate({ name }) {
20
19
  let appName = name;
21
20
  if (!appName) {
22
21
  const answers = await inquirer.prompt([
23
- { type: "input", name: "name", message: "App name" },
22
+ {
23
+ type: "input",
24
+ name: "name",
25
+ message: "App name:",
26
+ },
24
27
  ]);
25
28
  appName = (answers.name || "").trim();
26
29
  }
27
30
  if (!appName) {
28
- throw new Error("Missing name.");
31
+ throw new Error("Missing app name.");
29
32
  }
30
33
  const slug = slugifyName(appName);
31
34
  const appId = uuidv4();
32
- const componentId = uuidv4();
33
35
  const appDir = path.resolve(process.cwd(), slug);
36
+ const componentName = `${slug}-component`;
34
37
  if (await fs.pathExists(appDir)) {
35
38
  throw new Error(`Already exists. ${chalk.yellow(slug)}`);
36
39
  }
37
40
  const spinner = ora(`Creating app "${chalk.cyan(appName)}"...`).start();
41
+ const originalCwd = process.cwd();
38
42
  try {
39
43
  await fs.ensureDir(appDir);
40
- const templatesDir = path.join(__dirname, "..", "..", "src", "templates");
41
- const manifestTemplate = await fs.readFile(path.join(templatesDir, "manifest.yml"), "utf-8");
42
- const htmlTemplate = await fs.readFile(path.join(templatesDir, "index.html"), "utf-8");
43
- const manifestContent = manifestTemplate
44
- .replace(/{{appName}}/g, appName)
45
- .replace(/{{appId}}/g, appId)
46
- .replace(/{{componentId}}/g, componentId);
47
- const htmlContent = htmlTemplate.replace(/{{appName}}/g, appName);
48
- await fs.writeFile(path.join(appDir, "manifest.yml"), manifestContent);
49
- await fs.writeFile(path.join(appDir, "index.html"), htmlContent);
50
- const manifest = await getManifest(appDir);
51
- await createApp(manifest);
52
- spinner.succeed(`Successfully created "${chalk.cyan(appName)}" app!`);
44
+ const initialManifest = {
45
+ app: {
46
+ id: appId,
47
+ name: appName,
48
+ description: "",
49
+ },
50
+ components: [],
51
+ };
52
+ await fs.writeFile(path.join(appDir, "manifest.yml"), yaml.dump(initialManifest, { indent: 2, lineWidth: -1, noRefs: true }), "utf-8");
53
+ spinner.succeed(`App directory "${chalk.cyan(appName)}" created!`);
53
54
  console.log(chalk.gray(`šŸ“ Location: ${appDir}`));
54
55
  console.log(chalk.gray(`App ID: ${appId}`));
55
- console.log(chalk.green("\nšŸŽ‰ Your app is ready! Next steps:"));
56
+ process.chdir(appDir);
57
+ console.log(chalk.cyan(`\nAdding component "${componentName}"...`));
58
+ await runCreateComponent({ name: componentName });
59
+ spinner.start();
60
+ spinner.text = `Registering app with Fireberry...`;
61
+ await createApp(await getManifest());
62
+ spinner.succeed(`App registered with Fireberry!`);
63
+ console.log(chalk.green(`\nšŸŽ‰ Your app is ready!`));
64
+ console.log(chalk.white(`\nNext steps:`));
56
65
  console.log(chalk.white(` cd ${slug}`));
57
- console.log(chalk.white(" # Start developing your Fireberry app"));
66
+ console.log(chalk.white(` fireberry push # Push to Fireberry`));
58
67
  }
59
68
  catch (error) {
60
69
  spinner.fail(`Failed to create app "${chalk.cyan(appName)}"`);
70
+ process.chdir(originalCwd);
61
71
  throw error;
62
72
  }
63
73
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fireberry/cli",
3
- "version": "0.2.5-beta.0",
3
+ "version": "0.2.5-beta.1",
4
4
  "description": "Fireberry CLI tool",
5
5
  "type": "module",
6
6
  "author": "",
@@ -41,6 +41,8 @@
41
41
  "access": "public"
42
42
  },
43
43
  "dependencies": {
44
+ "@fireberry/ds": "^0.0.151",
45
+ "@fireberry/sdk": "^0.0.5",
44
46
  "axios": "^1.12.2",
45
47
  "chalk": "^5.3.0",
46
48
  "commander": "^12.1.0",
@@ -15,7 +15,13 @@ const program = new Command();
15
15
  program
16
16
  .name("fireberry")
17
17
  .description("Fireberry developer CLI")
18
- .version(packageJson.version);
18
+ .version(packageJson.version)
19
+ .configureOutput({
20
+ outputError: (str, write) => {
21
+ const formatted = str.replace(/^error:/i, 'Error:');
22
+ write(chalk.red(formatted));
23
+ }
24
+ });
19
25
 
20
26
  program
21
27
  .command("init")
@@ -27,11 +33,10 @@ program
27
33
 
28
34
  program
29
35
  .command("create")
30
- .argument("[name...]", "App name")
31
- .description("Create a new Fireberry app")
32
- .action(async (nameArgs?: string[]) => {
33
- const name = nameArgs ? nameArgs.join("-") : undefined;
34
- await runCreate({ name });
36
+ .argument("[name]", "App name")
37
+ .description("Create a new Fireberry app with a component")
38
+ .action(async (name?: string) => {
39
+ await runCreate({ name });
35
40
  });
36
41
 
37
42
  program
@@ -22,6 +22,13 @@ interface CreateComponentOptions {
22
22
 
23
23
  const VALID_COMPONENT_TYPES = Object.values(COMPONENT_TYPE);
24
24
 
25
+ function sanitizeComponentName(name: string): string {
26
+ return name
27
+ .toLowerCase()
28
+ .replace(/[^a-z0-9]+/g, "-")
29
+ .replace(/^-+|-+$/g, "");
30
+ }
31
+
25
32
  function validateComponentType(type: string): ComponentType {
26
33
  if (!VALID_COMPONENT_TYPES.includes(type as ComponentType)) {
27
34
  throw new Error(
@@ -156,6 +163,8 @@ export async function runCreateComponent({
156
163
 
157
164
  const validatedType = validateComponentType(componentType);
158
165
 
166
+ const sanitizedName = sanitizeComponentName(componentName);
167
+
159
168
  const spinner = ora();
160
169
 
161
170
  try {
@@ -166,15 +175,14 @@ export async function runCreateComponent({
166
175
  );
167
176
  spinner.start();
168
177
 
169
- const componentDir = path.join(process.cwd(), "static", componentName);
178
+ const componentDir = path.join(process.cwd(), componentName);
170
179
  await fs.ensureDir(componentDir);
171
180
 
172
- // Create Vite app with React template
173
181
  spinner.text = `Running npm create vite@latest...`;
174
182
  const viteResult = spawnSync(
175
- `npm create vite@latest ${componentName} -- --template react --no-interactive`,
183
+ `npm create vite@latest ${sanitizedName} -- --template react --no-interactive`,
176
184
  {
177
- cwd: path.join(process.cwd(), "static"),
185
+ cwd: process.cwd(),
178
186
  stdio: "inherit",
179
187
  shell: true,
180
188
  }
@@ -247,7 +255,7 @@ export async function runCreateComponent({
247
255
  type: validatedType,
248
256
  title: componentName,
249
257
  id: componentId,
250
- path: `static/${componentName}/dist`,
258
+ path: `${componentName}/dist`,
251
259
  settings: componentSettings,
252
260
  };
253
261
 
@@ -270,11 +278,15 @@ export async function runCreateComponent({
270
278
  spinner.succeed(
271
279
  `Successfully created component "${chalk.cyan(componentName)}"!`
272
280
  );
281
+
273
282
  console.log(chalk.gray(`Component ID: ${componentId}`));
274
283
  console.log(chalk.gray(`Type: ${validatedType}`));
275
- console.log(chalk.gray(`Path: static/${componentName}/dist`));
276
- console.log(chalk.green("\nšŸŽ‰ Your component is ready!"));
277
- console.log(chalk.white(` cd static/${componentName}`));
284
+ console.log(chalk.gray(`Path: ${sanitizedName}/dist`));
285
+
286
+ console.log(
287
+ chalk.green(`\nYour component "${chalk.cyan(componentName)}" is ready!`)
288
+ );
289
+ console.log(chalk.white(` cd ${sanitizedName}`));
278
290
  console.log(chalk.white(` npm run dev # Start development server`));
279
291
  console.log(chalk.white(` npm run build # Build for production`));
280
292
  } catch (error) {
@@ -2,14 +2,12 @@ import inquirer from "inquirer";
2
2
  import path from "node:path";
3
3
  import fs from "fs-extra";
4
4
  import { v4 as uuidv4 } from "uuid";
5
- import { fileURLToPath } from "node:url";
5
+ import yaml from "js-yaml";
6
6
  import ora from "ora";
7
7
  import chalk from "chalk";
8
8
  import { createApp } from "../api/requests.js";
9
9
  import { getManifest } from "../utils/components.utils.js";
10
-
11
- const __filename = fileURLToPath(import.meta.url);
12
- const __dirname = path.dirname(__filename);
10
+ import { runCreateComponent } from "./create-component.js";
13
11
 
14
12
  interface CreateOptions {
15
13
  name?: string;
@@ -31,59 +29,70 @@ export async function runCreate({ name }: CreateOptions): Promise<void> {
31
29
 
32
30
  if (!appName) {
33
31
  const answers = await inquirer.prompt([
34
- { type: "input", name: "name", message: "App name" },
32
+ {
33
+ type: "input",
34
+ name: "name",
35
+ message: "App name:",
36
+ },
35
37
  ]);
36
38
  appName = (answers.name || "").trim();
37
39
  }
40
+
38
41
  if (!appName) {
39
- throw new Error("Missing name.");
42
+ throw new Error("Missing app name.");
40
43
  }
41
44
 
42
45
  const slug = slugifyName(appName);
43
46
  const appId = uuidv4();
44
- const componentId = uuidv4();
45
47
  const appDir = path.resolve(process.cwd(), slug);
48
+ const componentName = `${slug}-component`;
46
49
 
47
50
  if (await fs.pathExists(appDir)) {
48
51
  throw new Error(`Already exists. ${chalk.yellow(slug)}`);
49
52
  }
50
53
 
51
54
  const spinner = ora(`Creating app "${chalk.cyan(appName)}"...`).start();
55
+ const originalCwd = process.cwd();
52
56
 
53
57
  try {
54
58
  await fs.ensureDir(appDir);
55
59
 
56
- const templatesDir = path.join(__dirname, "..", "..", "src", "templates");
57
- const manifestTemplate = await fs.readFile(
58
- path.join(templatesDir, "manifest.yml"),
59
- "utf-8"
60
- );
61
- const htmlTemplate = await fs.readFile(
62
- path.join(templatesDir, "index.html"),
60
+ const initialManifest = {
61
+ app: {
62
+ id: appId,
63
+ name: appName,
64
+ description: "",
65
+ },
66
+ components: [],
67
+ };
68
+
69
+ await fs.writeFile(
70
+ path.join(appDir, "manifest.yml"),
71
+ yaml.dump(initialManifest, { indent: 2, lineWidth: -1, noRefs: true }),
63
72
  "utf-8"
64
73
  );
65
74
 
66
- const manifestContent = manifestTemplate
67
- .replace(/{{appName}}/g, appName)
68
- .replace(/{{appId}}/g, appId)
69
- .replace(/{{componentId}}/g, componentId);
75
+ spinner.succeed(`App directory "${chalk.cyan(appName)}" created!`);
76
+ console.log(chalk.gray(`šŸ“ Location: ${appDir}`));
77
+ console.log(chalk.gray(`App ID: ${appId}`));
70
78
 
71
- const htmlContent = htmlTemplate.replace(/{{appName}}/g, appName);
79
+ process.chdir(appDir);
72
80
 
73
- await fs.writeFile(path.join(appDir, "manifest.yml"), manifestContent);
74
- await fs.writeFile(path.join(appDir, "index.html"), htmlContent);
75
- const manifest = await getManifest(appDir);
81
+ console.log(chalk.cyan(`\nAdding component "${componentName}"...`));
76
82
 
77
- await createApp(manifest);
83
+ await runCreateComponent({ name: componentName });
84
+ spinner.start();
85
+ spinner.text = `Registering app with Fireberry...`;
86
+ await createApp(await getManifest());
87
+ spinner.succeed(`App registered with Fireberry!`);
78
88
 
79
- spinner.succeed(`Successfully created "${chalk.cyan(appName)}" app!`);
80
- console.log(chalk.gray(`šŸ“ Location: ${appDir}`));
81
- console.log(chalk.gray(`App ID: ${appId}`));
82
- console.log(chalk.green("\nšŸŽ‰ Your app is ready! Next steps:"));
89
+ console.log(chalk.green(`\nšŸŽ‰ Your app is ready!`));
90
+ console.log(chalk.white(`\nNext steps:`));
83
91
  console.log(chalk.white(` cd ${slug}`));
84
- console.log(chalk.white(" # Start developing your Fireberry app"));
92
+ console.log(chalk.white(` fireberry push # Push to Fireberry`));
85
93
  } catch (error) {
86
94
  spinner.fail(`Failed to create app "${chalk.cyan(appName)}"`);
95
+ process.chdir(originalCwd);
87
96
  throw error;
88
97
  }
89
98
  }
@@ -1,15 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
-
4
- <head>
5
- <meta charset="UTF-8">
6
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
- <title>{{appName}}</title>
8
- </head>
9
-
10
- <body>
11
- <h1>Hello World</h1>
12
- <p>Welcome to {{appName}}!</p>
13
- </body>
14
-
15
- </html>
@@ -1,14 +0,0 @@
1
- app:
2
- id: "{{appId}}"
3
- name: "{{appName}}"
4
- description: ""
5
- components:
6
- - type: record
7
- title: my-first-component
8
- id: "{{componentId}}"
9
- path: static/comp/build
10
- settings:
11
- iconName: "related-single"
12
- iconColor: "#7aae7f"
13
- objectType: 0
14
- height: "M"