@fireberry/cli 0.0.5-beta.9 → 0.2.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.
- package/CLAUDE.md +156 -0
- package/LICENSE +21 -0
- package/dist/api/axios.js +1 -1
- package/dist/api/requests.d.ts +7 -3
- package/dist/api/requests.js +43 -6
- package/dist/api/types.d.ts +34 -3
- package/dist/bin/fireberry.js +23 -0
- package/dist/commands/create.js +6 -2
- package/dist/commands/debug.d.ts +3 -0
- package/dist/commands/debug.js +54 -0
- package/dist/commands/delete.d.ts +1 -0
- package/dist/commands/delete.js +31 -0
- package/dist/commands/install.d.ts +1 -0
- package/dist/commands/install.js +17 -0
- package/dist/commands/push.js +2 -2
- package/dist/constants/component-types.d.ts +7 -0
- package/dist/constants/component-types.js +6 -0
- package/dist/constants/height-options.d.ts +2 -0
- package/dist/constants/height-options.js +1 -0
- package/dist/utils/components.utils.d.ts +4 -3
- package/dist/utils/components.utils.js +98 -11
- package/package.json +1 -1
- package/src/api/axios.ts +1 -1
- package/src/api/requests.ts +54 -7
- package/src/api/types.ts +46 -3
- package/src/bin/fireberry.ts +26 -0
- package/src/commands/create.ts +7 -3
- package/src/commands/debug.ts +84 -0
- package/src/commands/delete.ts +40 -0
- package/src/commands/install.ts +23 -0
- package/src/commands/push.ts +2 -2
- package/src/constants/component-types.ts +10 -0
- package/src/constants/height-options.ts +3 -0
- package/src/templates/manifest.yml +6 -2
- package/src/utils/components.utils.ts +179 -17
|
@@ -4,14 +4,24 @@ import yaml from "js-yaml";
|
|
|
4
4
|
import chalk from "chalk";
|
|
5
5
|
import * as tar from "tar";
|
|
6
6
|
import os from "node:os";
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
Manifest,
|
|
9
|
+
ZippedComponent,
|
|
10
|
+
UntypedManifestComponent,
|
|
11
|
+
RecordComponentSettings,
|
|
12
|
+
GlobalMenuComponentSettings,
|
|
13
|
+
SideMenuComponentSettings,
|
|
14
|
+
} from "../api/types.js";
|
|
15
|
+
import { COMPONENT_TYPE } from "../constants/component-types.js";
|
|
16
|
+
import { HEIGHT_OPTIONS } from "../constants/height-options.js";
|
|
8
17
|
|
|
9
|
-
export const getManifest = async (): Promise<Manifest> => {
|
|
10
|
-
const manifestPath = path.join(process.cwd(), "manifest.yml");
|
|
18
|
+
export const getManifest = async (basePath?: string): Promise<Manifest> => {
|
|
19
|
+
const manifestPath = path.join(basePath || process.cwd(), "manifest.yml");
|
|
20
|
+
const searchDir = basePath || process.cwd();
|
|
11
21
|
|
|
12
22
|
if (!(await fs.pathExists(manifestPath))) {
|
|
13
23
|
throw new Error(
|
|
14
|
-
`No manifest.yml found at ${chalk.yellow(
|
|
24
|
+
`No manifest.yml found at ${chalk.yellow(searchDir)}.\n` +
|
|
15
25
|
`Please run this command from your Fireberry app directory.`
|
|
16
26
|
);
|
|
17
27
|
}
|
|
@@ -33,9 +43,147 @@ export const getManifest = async (): Promise<Manifest> => {
|
|
|
33
43
|
return manifest;
|
|
34
44
|
};
|
|
35
45
|
|
|
46
|
+
const validateRecordComponentSettings = (
|
|
47
|
+
comp: UntypedManifestComponent
|
|
48
|
+
): void => {
|
|
49
|
+
const settings = comp.settings as
|
|
50
|
+
| Partial<RecordComponentSettings>
|
|
51
|
+
| undefined;
|
|
52
|
+
|
|
53
|
+
if (!settings) {
|
|
54
|
+
throw new Error(
|
|
55
|
+
`Component "${comp.title}" (type: ${COMPONENT_TYPE.RECORD}) is missing required settings`
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const requiredFields: (keyof RecordComponentSettings)[] = [
|
|
60
|
+
"iconName",
|
|
61
|
+
"iconColor",
|
|
62
|
+
"objectType",
|
|
63
|
+
"height",
|
|
64
|
+
];
|
|
65
|
+
|
|
66
|
+
for (const fieldName of requiredFields) {
|
|
67
|
+
if (settings[fieldName] === undefined || settings[fieldName] === null) {
|
|
68
|
+
throw new Error(
|
|
69
|
+
`Component "${comp.title}" (type: ${COMPONENT_TYPE.RECORD}) is missing required setting: ${fieldName}`
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (typeof settings.iconName !== "string") {
|
|
75
|
+
throw new Error(
|
|
76
|
+
`Component "${comp.title}" (type: ${COMPONENT_TYPE.RECORD}) setting "iconName" must be a string`
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (typeof settings.iconColor !== "string") {
|
|
81
|
+
throw new Error(
|
|
82
|
+
`Component "${comp.title}" (type: ${COMPONENT_TYPE.RECORD}) setting "iconColor" must be a string`
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (typeof settings.objectType !== "number") {
|
|
87
|
+
throw new Error(
|
|
88
|
+
`Component "${comp.title}" (type: ${COMPONENT_TYPE.RECORD}) setting "objectType" must be a number`
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
if (!settings.height) {
|
|
92
|
+
throw new Error(
|
|
93
|
+
`Component "${comp.title}" (type: ${COMPONENT_TYPE.RECORD}) setting "height" must be one of: ${HEIGHT_OPTIONS.join(" | ")}`
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (!HEIGHT_OPTIONS.includes(settings.height as any)) {
|
|
98
|
+
throw new Error(
|
|
99
|
+
`Component "${comp.title}" (type: ${COMPONENT_TYPE.RECORD}) setting "height" must be one of: ${HEIGHT_OPTIONS.join(" | ")}`
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
const validateGlobalMenuComponentSettings = (
|
|
105
|
+
comp: UntypedManifestComponent
|
|
106
|
+
): void => {
|
|
107
|
+
const settings = comp.settings as
|
|
108
|
+
| Partial<GlobalMenuComponentSettings>
|
|
109
|
+
| undefined;
|
|
110
|
+
|
|
111
|
+
if (!settings) {
|
|
112
|
+
throw new Error(
|
|
113
|
+
`Component "${comp.title}" (type: ${COMPONENT_TYPE.GLOBAL_MENU}) is missing required settings`
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (!settings.displayName) {
|
|
118
|
+
throw new Error(
|
|
119
|
+
`Component "${comp.title}" (type: ${COMPONENT_TYPE.GLOBAL_MENU}) is missing required setting: displayName`
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (typeof settings.displayName !== "string") {
|
|
124
|
+
throw new Error(
|
|
125
|
+
`Component "${comp.title}" (type: ${COMPONENT_TYPE.GLOBAL_MENU}) setting "displayName" must be a string`
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
const validateSideMenuComponentSettings = (
|
|
131
|
+
comp: UntypedManifestComponent
|
|
132
|
+
): void => {
|
|
133
|
+
const settings = comp.settings as
|
|
134
|
+
| Partial<SideMenuComponentSettings>
|
|
135
|
+
| undefined;
|
|
136
|
+
|
|
137
|
+
if (!settings) {
|
|
138
|
+
throw new Error(
|
|
139
|
+
`Component "${comp.title}" (type: ${COMPONENT_TYPE.SIDE_MENU}) is missing required settings`
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (!settings.icon) {
|
|
144
|
+
throw new Error(
|
|
145
|
+
`Component "${comp.title}" (type: ${COMPONENT_TYPE.SIDE_MENU}) setting "icon" must be a string`
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (!settings.width) {
|
|
150
|
+
throw new Error(
|
|
151
|
+
`Component "${comp.title}" (type: ${COMPONENT_TYPE.SIDE_MENU}) setting "width" must be a S | M | L`
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (
|
|
156
|
+
settings.width !== "S" &&
|
|
157
|
+
settings.width !== "M" &&
|
|
158
|
+
settings.width !== "L"
|
|
159
|
+
) {
|
|
160
|
+
throw new Error(
|
|
161
|
+
`Component "${comp.title}" (type: ${COMPONENT_TYPE.SIDE_MENU}) setting "width" must be a S | M | L`
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
const validateComponentSettings = (comp: UntypedManifestComponent): void => {
|
|
167
|
+
switch (comp.type) {
|
|
168
|
+
case COMPONENT_TYPE.RECORD:
|
|
169
|
+
validateRecordComponentSettings(comp);
|
|
170
|
+
break;
|
|
171
|
+
case COMPONENT_TYPE.GLOBAL_MENU:
|
|
172
|
+
validateGlobalMenuComponentSettings(comp);
|
|
173
|
+
break;
|
|
174
|
+
case COMPONENT_TYPE.SIDE_MENU:
|
|
175
|
+
validateSideMenuComponentSettings(comp);
|
|
176
|
+
break;
|
|
177
|
+
default:
|
|
178
|
+
throw new Error(
|
|
179
|
+
`Component "${comp.title}" has unsupported type: ${comp.type}. Supported types: ${COMPONENT_TYPE.RECORD}, ${COMPONENT_TYPE.GLOBAL_MENU}`
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
|
|
36
184
|
export const validateComponentBuild = async (
|
|
37
185
|
componentPath: string,
|
|
38
|
-
comp:
|
|
186
|
+
comp: UntypedManifestComponent
|
|
39
187
|
) => {
|
|
40
188
|
if (!(await fs.pathExists(componentPath))) {
|
|
41
189
|
throw new Error(
|
|
@@ -49,10 +197,13 @@ export const validateComponentBuild = async (
|
|
|
49
197
|
|
|
50
198
|
if (stats.isDirectory()) {
|
|
51
199
|
const files = await fs.readdir(componentPath);
|
|
200
|
+
|
|
52
201
|
if (files.length === 0) {
|
|
53
|
-
throw new Error(`Component <${comp.
|
|
202
|
+
throw new Error(`Component <${comp.id}> at: /${comp.path} not found`);
|
|
54
203
|
}
|
|
55
204
|
}
|
|
205
|
+
|
|
206
|
+
validateComponentSettings(comp);
|
|
56
207
|
};
|
|
57
208
|
|
|
58
209
|
export const zipComponentBuild = async (
|
|
@@ -102,31 +253,42 @@ export const zipComponentBuild = async (
|
|
|
102
253
|
}
|
|
103
254
|
};
|
|
104
255
|
|
|
105
|
-
export const
|
|
106
|
-
manifest
|
|
107
|
-
|
|
108
|
-
|
|
256
|
+
export const validateManifestComponents = async (manifest: Manifest) => {
|
|
257
|
+
const components = manifest.components as unknown as
|
|
258
|
+
| UntypedManifestComponent[]
|
|
259
|
+
| undefined;
|
|
109
260
|
if (!components || components.length === 0) {
|
|
110
|
-
|
|
261
|
+
throw new Error("No components found in manifest");
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
const ids = components.map((comp) => comp.id);
|
|
265
|
+
if (new Set(ids).size !== ids.length) {
|
|
266
|
+
throw new Error("All component ids must be unique");
|
|
111
267
|
}
|
|
112
268
|
|
|
113
|
-
const
|
|
114
|
-
|
|
115
|
-
|
|
269
|
+
for (const comp of components) {
|
|
270
|
+
const componentPath = path.join(process.cwd(), comp.path);
|
|
271
|
+
await validateComponentBuild(componentPath, comp);
|
|
116
272
|
}
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
export const handleComponents = async (
|
|
276
|
+
manifest: Manifest
|
|
277
|
+
): Promise<ZippedComponent[]> => {
|
|
278
|
+
await validateManifestComponents(manifest);
|
|
279
|
+
const components =
|
|
280
|
+
manifest.components as unknown as UntypedManifestComponent[];
|
|
117
281
|
|
|
118
282
|
const zippedComponents: ZippedComponent[] = [];
|
|
119
283
|
|
|
120
284
|
for (const comp of components) {
|
|
121
285
|
const componentPath = path.join(process.cwd(), comp.path);
|
|
122
286
|
|
|
123
|
-
await validateComponentBuild(componentPath, comp);
|
|
124
|
-
|
|
125
287
|
const buildBuffer = await zipComponentBuild(componentPath, comp.title);
|
|
126
288
|
|
|
127
289
|
zippedComponents.push({
|
|
128
290
|
title: comp.title,
|
|
129
|
-
|
|
291
|
+
id: comp.id,
|
|
130
292
|
build: buildBuffer,
|
|
131
293
|
});
|
|
132
294
|
}
|