sprawlify 0.0.89 → 0.0.91
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/dist/index.mjs +373 -2
- package/package.json +2 -1
package/dist/index.mjs
CHANGED
|
@@ -1,13 +1,384 @@
|
|
|
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.
|
|
10
|
+
var version = "0.0.91";
|
|
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
|
+
react: { title: "React" },
|
|
171
|
+
solid: { title: "Solid" },
|
|
172
|
+
svelte: { title: "Svelte" },
|
|
173
|
+
vue: { title: "Vue" }
|
|
174
|
+
};
|
|
175
|
+
const METAFRAMEWORKS = {
|
|
176
|
+
next: {
|
|
177
|
+
title: "Next.js",
|
|
178
|
+
frameworks: ["react"]
|
|
179
|
+
},
|
|
180
|
+
nuxt: {
|
|
181
|
+
title: "Nuxt",
|
|
182
|
+
frameworks: ["vue"]
|
|
183
|
+
},
|
|
184
|
+
sveltekit: {
|
|
185
|
+
title: "SvelteKit",
|
|
186
|
+
frameworks: ["svelte"]
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
//#endregion
|
|
190
|
+
//#region src/utils/env-loader.ts
|
|
191
|
+
async function loadEnvFiles(cwd = process.cwd()) {
|
|
192
|
+
try {
|
|
193
|
+
const { config } = await import("@dotenvx/dotenvx");
|
|
194
|
+
for (const envFile of [
|
|
195
|
+
".env.local",
|
|
196
|
+
".env.development.local",
|
|
197
|
+
".env.development",
|
|
198
|
+
".env"
|
|
199
|
+
]) {
|
|
200
|
+
const envPath = join(cwd, envFile);
|
|
201
|
+
if (existsSync(envPath)) config({
|
|
202
|
+
path: envPath,
|
|
203
|
+
overload: false,
|
|
204
|
+
quiet: true
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
} catch (error) {
|
|
208
|
+
logger.warn("Failed to load env files:", error);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
//#endregion
|
|
212
|
+
//#region src/commands/init.ts
|
|
213
|
+
const initOptionsSchema = z.object({
|
|
214
|
+
cwd: z.string(),
|
|
215
|
+
name: z.string().optional(),
|
|
216
|
+
preset: z.string().optional(),
|
|
217
|
+
components: z.array(z.string()).optional(),
|
|
218
|
+
yes: z.boolean(),
|
|
219
|
+
defaults: z.boolean(),
|
|
220
|
+
override: z.boolean(),
|
|
221
|
+
reinstall: z.boolean().optional(),
|
|
222
|
+
framework: z.string().optional(),
|
|
223
|
+
metaframework: z.string().optional()
|
|
224
|
+
});
|
|
225
|
+
async function runInit(options) {
|
|
226
|
+
const cwd = options.cwd;
|
|
227
|
+
const componentsJsonPath = path.resolve(cwd, "components.json");
|
|
228
|
+
logger.info("Starting project initialization...");
|
|
229
|
+
const config = {
|
|
230
|
+
$schema: "https://ui.primitives.com/schema.json",
|
|
231
|
+
framework: options.framework,
|
|
232
|
+
preset: options.preset,
|
|
233
|
+
metaframework: options.metaframework,
|
|
234
|
+
aliases: {
|
|
235
|
+
components: "@/components",
|
|
236
|
+
ui: "@/components/ui",
|
|
237
|
+
utils: "@/lib/utils"
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
let backupPath = null;
|
|
241
|
+
if (fsExtra.existsSync(componentsJsonPath)) {
|
|
242
|
+
backupPath = `${componentsJsonPath}${FILE_BACKUP_SUFFIX}`;
|
|
243
|
+
fsExtra.copyFileSync(componentsJsonPath, backupPath);
|
|
244
|
+
logger.info(`Created backup of existing configuration: ${path.basename(backupPath)}`);
|
|
245
|
+
}
|
|
246
|
+
try {
|
|
247
|
+
await fsExtra.ensureDir(path.dirname(componentsJsonPath));
|
|
248
|
+
await fsExtra.writeJson(componentsJsonPath, config, { spaces: 2 });
|
|
249
|
+
logger.success(`Created ${highlighter.info("components.json")} configuration file.`);
|
|
250
|
+
} catch (error) {
|
|
251
|
+
logger.error(`Failed to create components.json: ${error}`);
|
|
252
|
+
if (backupPath && fsExtra.existsSync(backupPath)) {
|
|
253
|
+
fsExtra.copyFileSync(backupPath, componentsJsonPath);
|
|
254
|
+
fsExtra.unlinkSync(backupPath);
|
|
255
|
+
logger.info("Restored original configuration file.");
|
|
256
|
+
}
|
|
257
|
+
throw error;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
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("-o, --override", "override 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) => {
|
|
261
|
+
let reinstallComponents = [];
|
|
262
|
+
const restoreBackupOnExit = () => {};
|
|
263
|
+
process.on("exit", restoreBackupOnExit);
|
|
264
|
+
try {
|
|
265
|
+
const options = initOptionsSchema.parse({
|
|
266
|
+
...opts,
|
|
267
|
+
reinstall: opts.reinstall,
|
|
268
|
+
cwd: path.resolve(opts.cwd)
|
|
269
|
+
});
|
|
270
|
+
if (options.defaults) {
|
|
271
|
+
options.preset = options.preset || "monochrome";
|
|
272
|
+
options.framework = options.framework || "react";
|
|
273
|
+
options.reinstall = options.reinstall ?? false;
|
|
274
|
+
}
|
|
275
|
+
if (options.preset && !(options.preset in PRESETS)) {
|
|
276
|
+
logger.error(`Invalid preset: ${highlighter.info(options.preset)}. Available presets: ${Object.keys(PRESETS).map((f) => highlighter.info(f)).join(", ")}.`);
|
|
277
|
+
logger.break();
|
|
278
|
+
process.exit(1);
|
|
279
|
+
}
|
|
280
|
+
if (options.framework && !(options.framework in FRAMEWORKS)) {
|
|
281
|
+
logger.error(`Invalid framework: ${highlighter.info(options.framework)}. Available frameworks: ${Object.keys(FRAMEWORKS).map((f) => highlighter.info(f)).join(", ")}.`);
|
|
282
|
+
logger.break();
|
|
283
|
+
process.exit(1);
|
|
284
|
+
}
|
|
285
|
+
if (options.metaframework && !(options.metaframework in METAFRAMEWORKS)) {
|
|
286
|
+
logger.error(`Invalid metaframework: ${highlighter.info(options.metaframework)}. Available metaframeworks: ${Object.keys(METAFRAMEWORKS).map((f) => highlighter.info(f)).join(", ")}.`);
|
|
287
|
+
logger.break();
|
|
288
|
+
process.exit(1);
|
|
289
|
+
}
|
|
290
|
+
if (!options.framework) {
|
|
291
|
+
const { framework } = await prompts({
|
|
292
|
+
type: "select",
|
|
293
|
+
name: "framework",
|
|
294
|
+
message: "Which framework would you like to use?",
|
|
295
|
+
choices: Object.keys(FRAMEWORKS).map((framework) => ({
|
|
296
|
+
title: FRAMEWORKS[framework].title,
|
|
297
|
+
value: framework
|
|
298
|
+
})),
|
|
299
|
+
initial: 0
|
|
300
|
+
});
|
|
301
|
+
if (!framework) {
|
|
302
|
+
logger.error("Framework selection is required.");
|
|
303
|
+
process.exit(1);
|
|
304
|
+
}
|
|
305
|
+
options.framework = framework;
|
|
306
|
+
}
|
|
307
|
+
if (!options.preset) {
|
|
308
|
+
const { preset } = await prompts({
|
|
309
|
+
type: "select",
|
|
310
|
+
name: "preset",
|
|
311
|
+
message: "Which preset would you like to use?",
|
|
312
|
+
choices: Object.entries(PRESETS).map(([key, preset]) => ({
|
|
313
|
+
title: preset.name,
|
|
314
|
+
value: key,
|
|
315
|
+
disabled: !preset.frameworks.includes(options.framework)
|
|
316
|
+
})),
|
|
317
|
+
initial: 0
|
|
318
|
+
});
|
|
319
|
+
if (!preset) {
|
|
320
|
+
logger.error("Preset selection is required.");
|
|
321
|
+
process.exit(1);
|
|
322
|
+
}
|
|
323
|
+
options.preset = preset;
|
|
324
|
+
}
|
|
325
|
+
if (!options.metaframework) {
|
|
326
|
+
const { metaframework } = await prompts({
|
|
327
|
+
type: "select",
|
|
328
|
+
name: "metaframework",
|
|
329
|
+
message: "Which metaframework would you like to use (optional)?",
|
|
330
|
+
choices: [{
|
|
331
|
+
title: "None",
|
|
332
|
+
value: "none"
|
|
333
|
+
}, ...Object.entries(METAFRAMEWORKS).filter(([_, meta]) => meta.frameworks.includes(options.framework)).map(([key, meta]) => ({
|
|
334
|
+
title: meta.title,
|
|
335
|
+
value: key
|
|
336
|
+
}))],
|
|
337
|
+
initial: 0
|
|
338
|
+
});
|
|
339
|
+
options.metaframework = metaframework === "none" ? void 0 : metaframework;
|
|
340
|
+
}
|
|
341
|
+
const cwd = options.cwd;
|
|
342
|
+
if (fsExtra.existsSync(path.resolve(cwd, "components.json")) && !options.override) {
|
|
343
|
+
const { overwrite } = await prompts({
|
|
344
|
+
type: "confirm",
|
|
345
|
+
name: "overwrite",
|
|
346
|
+
message: `A ${highlighter.info("components.json")} file already exists. Would you like to overwrite it?`,
|
|
347
|
+
initial: false
|
|
348
|
+
});
|
|
349
|
+
if (!overwrite) {
|
|
350
|
+
logger.info(` To start over, remove the ${highlighter.info("components.json")} file and run ${highlighter.info("init")} again.`);
|
|
351
|
+
logger.break();
|
|
352
|
+
process.exit(1);
|
|
353
|
+
}
|
|
354
|
+
options.override = true;
|
|
355
|
+
}
|
|
356
|
+
if (reinstallComponents.length) components = [...components, ...reinstallComponents];
|
|
357
|
+
options.components = components;
|
|
358
|
+
await loadEnvFiles(options.cwd);
|
|
359
|
+
await runInit(options);
|
|
360
|
+
logger.break();
|
|
361
|
+
logger.log(`Project initialization completed.\nYou may now add components.`);
|
|
362
|
+
process.removeListener("exit", restoreBackupOnExit);
|
|
363
|
+
deleteFileBackup(path.resolve(cwd, "components.json"));
|
|
364
|
+
logger.break();
|
|
365
|
+
} catch (error) {
|
|
366
|
+
process.removeListener("exit", restoreBackupOnExit);
|
|
367
|
+
restoreBackupOnExit();
|
|
368
|
+
logger.break();
|
|
369
|
+
handleError(error);
|
|
370
|
+
} finally {
|
|
371
|
+
clearRegistryContext();
|
|
372
|
+
}
|
|
373
|
+
});
|
|
5
374
|
//#endregion
|
|
6
375
|
//#region src/index.ts
|
|
7
376
|
process.on("SIGINT", () => process.exit(0));
|
|
8
377
|
process.on("SIGTERM", () => process.exit(0));
|
|
9
378
|
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")
|
|
379
|
+
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");
|
|
380
|
+
program.addCommand(init);
|
|
381
|
+
program.parse();
|
|
11
382
|
}
|
|
12
383
|
main();
|
|
13
384
|
//#endregion
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sprawlify",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.91",
|
|
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",
|