sprawlify 0.0.88 → 0.0.90

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.
Files changed (2) hide show
  1. package/dist/index.mjs +387 -2
  2. package/package.json +2 -1
package/dist/index.mjs CHANGED
@@ -1,13 +1,398 @@
1
1
  #!/usr/bin/env node
2
2
  import { Command } from "commander";
3
+ import fsExtra from "fs-extra";
4
+ import path, { join } from "path";
5
+ import prompts from "prompts";
6
+ import { z } from "zod";
7
+ import { cyan, green, red, yellow } from "kleur/colors";
8
+ import { existsSync } from "fs";
3
9
  //#region package.json
4
- var version = "0.0.88";
10
+ var version = "0.0.90";
11
+ //#endregion
12
+ //#region src/utils/file-helper.ts
13
+ const FILE_BACKUP_SUFFIX = ".bak";
14
+ function deleteFileBackup(filePath) {
15
+ const backupPath = `${filePath}${FILE_BACKUP_SUFFIX}`;
16
+ if (!fsExtra.existsSync(backupPath)) return false;
17
+ try {
18
+ fsExtra.unlinkSync(backupPath);
19
+ return true;
20
+ } catch (error) {
21
+ return false;
22
+ }
23
+ }
24
+ //#endregion
25
+ //#region src/utils/highlighter.ts
26
+ const highlighter = {
27
+ error: red,
28
+ warn: yellow,
29
+ info: cyan,
30
+ success: green
31
+ };
32
+ //#endregion
33
+ //#region src/utils/logger.ts
34
+ const logger = {
35
+ error(...args) {
36
+ console.log(highlighter.error(args.join(" ")));
37
+ },
38
+ warn(...args) {
39
+ console.log(highlighter.warn(args.join(" ")));
40
+ },
41
+ info(...args) {
42
+ console.log(highlighter.info(args.join(" ")));
43
+ },
44
+ success(...args) {
45
+ console.log(highlighter.success(args.join(" ")));
46
+ },
47
+ log(...args) {
48
+ console.log(args.join(" "));
49
+ },
50
+ break() {
51
+ console.log("");
52
+ }
53
+ };
54
+ //#endregion
55
+ //#region src/registry/errors.ts
56
+ const RegistryErrorCode = {
57
+ NETWORK_ERROR: "NETWORK_ERROR",
58
+ NOT_FOUND: "NOT_FOUND",
59
+ GONE: "GONE",
60
+ UNAUTHORIZED: "UNAUTHORIZED",
61
+ FORBIDDEN: "FORBIDDEN",
62
+ FETCH_ERROR: "FETCH_ERROR",
63
+ NOT_CONFIGURED: "NOT_CONFIGURED",
64
+ INVALID_CONFIG: "INVALID_CONFIG",
65
+ MISSING_ENV_VARS: "MISSING_ENV_VARS",
66
+ LOCAL_FILE_ERROR: "LOCAL_FILE_ERROR",
67
+ PARSE_ERROR: "PARSE_ERROR",
68
+ VALIDATION_ERROR: "VALIDATION_ERROR",
69
+ UNKNOWN_ERROR: "UNKNOWN_ERROR"
70
+ };
71
+ var RegistryError = class extends Error {
72
+ code;
73
+ statusCode;
74
+ context;
75
+ suggestion;
76
+ timestamp;
77
+ cause;
78
+ constructor(message, options = {}) {
79
+ super(message);
80
+ this.name = "RegistryError";
81
+ this.code = options.code || RegistryErrorCode.UNKNOWN_ERROR;
82
+ this.statusCode = options.statusCode;
83
+ this.cause = options.cause;
84
+ this.context = options.context;
85
+ this.suggestion = options.suggestion;
86
+ this.timestamp = /* @__PURE__ */ new Date();
87
+ if (Error.captureStackTrace) Error.captureStackTrace(this, this.constructor);
88
+ }
89
+ toJSON() {
90
+ return {
91
+ name: this.name,
92
+ message: this.message,
93
+ code: this.code,
94
+ statusCode: this.statusCode,
95
+ context: this.context,
96
+ suggestion: this.suggestion,
97
+ timestamp: this.timestamp,
98
+ stack: this.stack
99
+ };
100
+ }
101
+ };
102
+ //#endregion
103
+ //#region src/utils/handle-error.ts
104
+ function handleError(error) {
105
+ logger.break();
106
+ logger.error(`Something went wrong. Please check the error below for more details.`);
107
+ logger.error(`If the problem persists, please open an issue on GitHub.`);
108
+ logger.error("");
109
+ if (typeof error === "string") {
110
+ logger.error(error);
111
+ logger.break();
112
+ process.exit(1);
113
+ }
114
+ if (error instanceof RegistryError) {
115
+ if (error.message) {
116
+ logger.error(error.cause ? "Error:" : "Message:");
117
+ logger.error(error.message);
118
+ }
119
+ if (error.cause) {
120
+ logger.error("\nMessage:");
121
+ logger.error(error.cause);
122
+ }
123
+ if (error.suggestion) {
124
+ logger.error("\nSuggestion:");
125
+ logger.error(error.suggestion);
126
+ }
127
+ logger.break();
128
+ process.exit(1);
129
+ }
130
+ if (error instanceof z.ZodError) {
131
+ logger.error("Validation failed:");
132
+ for (const [key, value] of Object.entries(error.flatten().fieldErrors)) logger.error(`- ${highlighter.info(key)}: ${value}`);
133
+ logger.break();
134
+ process.exit(1);
135
+ }
136
+ if (error instanceof Error) {
137
+ logger.error(error.message);
138
+ logger.break();
139
+ process.exit(1);
140
+ }
141
+ logger.break();
142
+ process.exit(1);
143
+ }
144
+ //#endregion
145
+ //#region src/registry/context.ts
146
+ let context = { headers: {} };
147
+ function clearRegistryContext() {
148
+ context.headers = {};
149
+ }
150
+ //#endregion
151
+ //#region src/preset/presets.ts
152
+ const PRESETS = {
153
+ clay: {
154
+ name: "Clay",
155
+ frameworks: ["react"]
156
+ },
157
+ monochrome: {
158
+ name: "Monochrome",
159
+ frameworks: [
160
+ "react",
161
+ "solid",
162
+ "svelte",
163
+ "vue"
164
+ ]
165
+ }
166
+ };
167
+ //#endregion
168
+ //#region src/frameworks/index.ts
169
+ const FRAMEWORKS = {};
170
+ const METAFRAMEWORKS = {};
171
+ //#endregion
172
+ //#region src/utils/env-loader.ts
173
+ async function loadEnvFiles(cwd = process.cwd()) {
174
+ try {
175
+ const { config } = await import("@dotenvx/dotenvx");
176
+ for (const envFile of [
177
+ ".env.local",
178
+ ".env.development.local",
179
+ ".env.development",
180
+ ".env"
181
+ ]) {
182
+ const envPath = join(cwd, envFile);
183
+ if (existsSync(envPath)) config({
184
+ path: envPath,
185
+ overload: false,
186
+ quiet: true
187
+ });
188
+ }
189
+ } catch (error) {
190
+ logger.warn("Failed to load env files:", error);
191
+ }
192
+ }
193
+ //#endregion
194
+ //#region src/commands/init.ts
195
+ const initOptionsSchema = z.object({
196
+ cwd: z.string(),
197
+ name: z.string().optional(),
198
+ preset: z.string().optional(),
199
+ components: z.array(z.string()).optional(),
200
+ yes: z.boolean(),
201
+ defaults: z.boolean(),
202
+ force: z.boolean(),
203
+ reinstall: z.boolean().optional(),
204
+ framework: z.string().optional(),
205
+ metaframework: z.string().optional()
206
+ });
207
+ async function runInit(options) {
208
+ const cwd = options.cwd;
209
+ const componentsJsonPath = path.resolve(cwd, "components.json");
210
+ logger.info("Starting project initialization...");
211
+ if (!options.defaults && !options.skipPreflight) {
212
+ if (!options.framework) {
213
+ const { framework } = await prompts({
214
+ type: "select",
215
+ name: "framework",
216
+ message: "Which framework would you like to use?",
217
+ choices: [
218
+ {
219
+ title: "React",
220
+ value: "react"
221
+ },
222
+ {
223
+ title: "Solid",
224
+ value: "solid"
225
+ },
226
+ {
227
+ title: "Svelte",
228
+ value: "svelte"
229
+ },
230
+ {
231
+ title: "Vue",
232
+ value: "vue"
233
+ }
234
+ ],
235
+ initial: 0
236
+ });
237
+ if (!framework) {
238
+ logger.error("Framework selection is required.");
239
+ process.exit(1);
240
+ }
241
+ options.framework = framework;
242
+ }
243
+ if (!options.preset) {
244
+ const { preset } = await prompts({
245
+ type: "select",
246
+ name: "preset",
247
+ message: "Which preset would you like to use?",
248
+ choices: Object.entries(PRESETS).map(([key, preset]) => ({
249
+ title: preset.name,
250
+ value: key,
251
+ disabled: !preset.frameworks.includes(options.framework)
252
+ })),
253
+ initial: 0
254
+ });
255
+ if (!preset) {
256
+ logger.error("Preset selection is required.");
257
+ process.exit(1);
258
+ }
259
+ options.preset = preset;
260
+ }
261
+ if (!options.metaframework) {
262
+ const { metaframework } = await prompts({
263
+ type: "select",
264
+ name: "metaframework",
265
+ message: "Which metaframework would you like to use (optional)?",
266
+ choices: [
267
+ {
268
+ title: "None",
269
+ value: "none"
270
+ },
271
+ {
272
+ title: "Next.js",
273
+ value: "next"
274
+ },
275
+ {
276
+ title: "Vite",
277
+ value: "vite"
278
+ },
279
+ {
280
+ title: "Nuxt",
281
+ value: "nuxt"
282
+ },
283
+ {
284
+ title: "SvelteKit",
285
+ value: "sveltekit"
286
+ }
287
+ ],
288
+ initial: 0
289
+ });
290
+ options.metaframework = metaframework === "none" ? void 0 : metaframework;
291
+ }
292
+ }
293
+ if (options.framework) options.framework;
294
+ const config = {
295
+ $schema: "https://ui.primitives.com/schema.json",
296
+ framework: options.framework || "react",
297
+ preset: options.preset || "monochrome",
298
+ metaframework: options.metaframework,
299
+ aliases: {
300
+ components: "@/components",
301
+ ui: "@/components/ui",
302
+ utils: "@/lib/utils"
303
+ }
304
+ };
305
+ let backupPath = null;
306
+ if (fsExtra.existsSync(componentsJsonPath)) {
307
+ backupPath = `${componentsJsonPath}${FILE_BACKUP_SUFFIX}`;
308
+ fsExtra.copyFileSync(componentsJsonPath, backupPath);
309
+ logger.info(`Created backup of existing configuration: ${path.basename(backupPath)}`);
310
+ }
311
+ try {
312
+ await fsExtra.ensureDir(path.dirname(componentsJsonPath));
313
+ await fsExtra.writeJson(componentsJsonPath, config, { spaces: 2 });
314
+ logger.success(`Created ${highlighter.info("components.json")} configuration file.`);
315
+ } catch (error) {
316
+ logger.error(`Failed to create components.json: ${error}`);
317
+ if (backupPath && fsExtra.existsSync(backupPath)) {
318
+ fsExtra.copyFileSync(backupPath, componentsJsonPath);
319
+ fsExtra.unlinkSync(backupPath);
320
+ logger.info("Restored original configuration file.");
321
+ }
322
+ throw error;
323
+ }
324
+ }
325
+ const init = new Command().name("init").alias("create").description("initialize your project and install dependencies").argument("[components...]", "names, url or local path to component").option("-p, --preset <preset>", "the preset to use. (monochrome, clay)").option("-f, --framework <framework>", "the framework to use. (react, solid, svelte, vue)").option("--metaframework <metaframework>", "the metaframework to use. (next, react-router, nuxt, sveltekit)").option("-y, --yes", "skip confirmation prompt.", true).option("-d, --defaults", "use default configuration: --preset=monochrome --framework=react --metaframework=vanilla", false).option("-f, --force", "force overwrite of existing configuration.", false).option("-c, --cwd <cwd>", "the working directory. defaults to the current directory.", process.cwd()).option("-n, --name <name>", "the name for the new project.").option("-s, --silent", "mute output.", false).option("--reinstall", "re-install existing UI components.").option("--no-reinstall", "do not re-install existing UI components.").action(async (components, opts) => {
326
+ let reinstallComponents = [];
327
+ const restoreBackupOnExit = () => {};
328
+ process.on("exit", restoreBackupOnExit);
329
+ try {
330
+ const options = initOptionsSchema.parse({
331
+ ...opts,
332
+ reinstall: opts.reinstall,
333
+ cwd: path.resolve(opts.cwd)
334
+ });
335
+ if (options.defaults) {
336
+ options.preset = options.preset || "monochrome";
337
+ options.framework = options.framework || "react";
338
+ options.reinstall = options.reinstall ?? false;
339
+ }
340
+ if (options.preset && !(options.preset in PRESETS)) {
341
+ logger.error(`Invalid preset: ${highlighter.info(options.preset)}. Available presets: ${Object.keys(PRESETS).map((f) => highlighter.info(f)).join(", ")}.`);
342
+ logger.break();
343
+ process.exit(1);
344
+ }
345
+ if (options.framework && !(options.framework in FRAMEWORKS)) {
346
+ logger.error(`Invalid framework: ${highlighter.info(options.framework)}. Available frameworks: ${Object.keys(FRAMEWORKS).map((f) => highlighter.info(f)).join(", ")}.`);
347
+ logger.break();
348
+ process.exit(1);
349
+ }
350
+ if (options.metaframework && !(options.metaframework in METAFRAMEWORKS)) {
351
+ logger.error(`Invalid metaframework: ${highlighter.info(options.metaframework)}. Available metaframeworks: ${Object.keys(METAFRAMEWORKS).map((f) => highlighter.info(f)).join(", ")}.`);
352
+ logger.break();
353
+ process.exit(1);
354
+ }
355
+ const cwd = options.cwd;
356
+ if (fsExtra.existsSync(path.resolve(cwd, "components.json")) && !options.force) {
357
+ const { overwrite } = await prompts({
358
+ type: "confirm",
359
+ name: "overwrite",
360
+ message: `A ${highlighter.info("components.json")} file already exists. Would you like to overwrite it?`,
361
+ initial: false
362
+ });
363
+ if (!overwrite) {
364
+ logger.info(` To start over, remove the ${highlighter.info("components.json")} file and run ${highlighter.info("init")} again.`);
365
+ logger.break();
366
+ process.exit(1);
367
+ }
368
+ options.force = true;
369
+ }
370
+ if (reinstallComponents.length) components = [...components, ...reinstallComponents];
371
+ options.components = components;
372
+ await loadEnvFiles(options.cwd);
373
+ await runInit(options);
374
+ logger.break();
375
+ logger.log(`Project initialization completed.\nYou may now add components.`);
376
+ process.removeListener("exit", restoreBackupOnExit);
377
+ deleteFileBackup(path.resolve(cwd, "components.json"));
378
+ logger.break();
379
+ } catch (error) {
380
+ process.removeListener("exit", restoreBackupOnExit);
381
+ restoreBackupOnExit();
382
+ logger.break();
383
+ handleError(error);
384
+ } finally {
385
+ clearRegistryContext();
386
+ }
387
+ });
5
388
  //#endregion
6
389
  //#region src/index.ts
7
390
  process.on("SIGINT", () => process.exit(0));
8
391
  process.on("SIGTERM", () => process.exit(0));
9
392
  async function main() {
10
- new Command().name("sprawlify").description("add items from registries to your project").version(version || "1.0.0", "-v, --version", "display the version number").parse();
393
+ const program = new Command().name("sprawlify").description("add items from registries to your project").version(version || "1.0.0", "-v, --version", "display the version number");
394
+ program.addCommand(init);
395
+ program.parse();
11
396
  }
12
397
  main();
13
398
  //#endregion
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sprawlify",
3
- "version": "0.0.88",
3
+ "version": "0.0.90",
4
4
  "type": "module",
5
5
  "description": "A command-line interface for Sprawlify.",
6
6
  "author": "sprawlify <npm@sprawlify.com>",
@@ -17,6 +17,7 @@
17
17
  "dist"
18
18
  ],
19
19
  "dependencies": {
20
+ "@dotenvx/dotenvx": "^1.55.1",
20
21
  "commander": "^14.0.3",
21
22
  "fs-extra": "^11.3.4",
22
23
  "kleur": "^4.1.5",