sprawlify 0.0.91 → 0.0.92
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 +232 -141
- package/package.json +2 -1
package/dist/index.mjs
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { Command } from "commander";
|
|
3
|
-
import fsExtra from "fs-extra";
|
|
4
3
|
import path, { join } from "path";
|
|
5
|
-
import
|
|
6
|
-
import { z } from "zod";
|
|
4
|
+
import fsExtra from "fs-extra";
|
|
7
5
|
import { cyan, green, red, yellow } from "kleur/colors";
|
|
6
|
+
import { z } from "zod";
|
|
8
7
|
import { existsSync } from "fs";
|
|
8
|
+
import prompts from "prompts";
|
|
9
|
+
import dedent from "dedent";
|
|
9
10
|
//#region package.json
|
|
10
|
-
var version = "0.0.
|
|
11
|
+
var version = "0.0.92";
|
|
11
12
|
//#endregion
|
|
12
13
|
//#region src/utils/file-helper.ts
|
|
13
14
|
const FILE_BACKUP_SUFFIX = ".bak";
|
|
@@ -148,22 +149,27 @@ function clearRegistryContext() {
|
|
|
148
149
|
context.headers = {};
|
|
149
150
|
}
|
|
150
151
|
//#endregion
|
|
151
|
-
//#region src/
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
152
|
+
//#region src/utils/env-loader.ts
|
|
153
|
+
async function loadEnvFiles(cwd = process.cwd()) {
|
|
154
|
+
try {
|
|
155
|
+
const { config } = await import("@dotenvx/dotenvx");
|
|
156
|
+
for (const envFile of [
|
|
157
|
+
".env.local",
|
|
158
|
+
".env.development.local",
|
|
159
|
+
".env.development",
|
|
160
|
+
".env"
|
|
161
|
+
]) {
|
|
162
|
+
const envPath = join(cwd, envFile);
|
|
163
|
+
if (existsSync(envPath)) config({
|
|
164
|
+
path: envPath,
|
|
165
|
+
overload: false,
|
|
166
|
+
quiet: true
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
} catch (error) {
|
|
170
|
+
logger.warn("Failed to load env files:", error);
|
|
165
171
|
}
|
|
166
|
-
}
|
|
172
|
+
}
|
|
167
173
|
//#endregion
|
|
168
174
|
//#region src/frameworks/index.ts
|
|
169
175
|
const FRAMEWORKS = {
|
|
@@ -187,29 +193,24 @@ const METAFRAMEWORKS = {
|
|
|
187
193
|
}
|
|
188
194
|
};
|
|
189
195
|
//#endregion
|
|
190
|
-
//#region src/
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
quiet: true
|
|
205
|
-
});
|
|
206
|
-
}
|
|
207
|
-
} catch (error) {
|
|
208
|
-
logger.warn("Failed to load env files:", error);
|
|
196
|
+
//#region src/preset/presets.ts
|
|
197
|
+
const PRESETS = {
|
|
198
|
+
clay: {
|
|
199
|
+
name: "Clay",
|
|
200
|
+
frameworks: ["react"]
|
|
201
|
+
},
|
|
202
|
+
monochrome: {
|
|
203
|
+
name: "Monochrome",
|
|
204
|
+
frameworks: [
|
|
205
|
+
"react",
|
|
206
|
+
"solid",
|
|
207
|
+
"svelte",
|
|
208
|
+
"vue"
|
|
209
|
+
]
|
|
209
210
|
}
|
|
210
|
-
}
|
|
211
|
+
};
|
|
211
212
|
//#endregion
|
|
212
|
-
//#region src/commands/init.ts
|
|
213
|
+
//#region src/commands/init/options.ts
|
|
213
214
|
const initOptionsSchema = z.object({
|
|
214
215
|
cwd: z.string(),
|
|
215
216
|
name: z.string().optional(),
|
|
@@ -222,8 +223,189 @@ const initOptionsSchema = z.object({
|
|
|
222
223
|
framework: z.string().optional(),
|
|
223
224
|
metaframework: z.string().optional()
|
|
224
225
|
});
|
|
226
|
+
function parseInitOptions(opts) {
|
|
227
|
+
const parsed = opts;
|
|
228
|
+
return initOptionsSchema.parse({
|
|
229
|
+
...parsed,
|
|
230
|
+
reinstall: parsed.reinstall,
|
|
231
|
+
cwd: path.resolve(String(parsed.cwd ?? process.cwd()))
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
function applyDefaultInitOptions(options) {
|
|
235
|
+
if (!options.defaults) return;
|
|
236
|
+
options.preset = options.preset || "monochrome";
|
|
237
|
+
options.framework = options.framework || "react";
|
|
238
|
+
options.reinstall = options.reinstall ?? false;
|
|
239
|
+
}
|
|
240
|
+
function validateExplicitOptions(options) {
|
|
241
|
+
if (options.preset && !(options.preset in PRESETS)) exitForInvalidOption("preset", options.preset, Object.keys(PRESETS));
|
|
242
|
+
if (options.framework && !(options.framework in FRAMEWORKS)) exitForInvalidOption("framework", options.framework, Object.keys(FRAMEWORKS));
|
|
243
|
+
if (options.metaframework && !(options.metaframework in METAFRAMEWORKS)) exitForInvalidOption("metaframework", options.metaframework, Object.keys(METAFRAMEWORKS));
|
|
244
|
+
}
|
|
245
|
+
function exitForInvalidOption(optionName, receivedValue, allowedValues) {
|
|
246
|
+
logger.error(`Invalid ${optionName}: ${highlighter.info(receivedValue)}. Available ${optionName}s: ${allowedValues.map((value) => highlighter.info(value)).join(", ")}.`);
|
|
247
|
+
logger.break();
|
|
248
|
+
process.exit(1);
|
|
249
|
+
}
|
|
250
|
+
//#endregion
|
|
251
|
+
//#region src/commands/init/prompts.ts
|
|
252
|
+
async function promptForMissingSelections(options) {
|
|
253
|
+
if (!options.name) {
|
|
254
|
+
const { name } = await prompts({
|
|
255
|
+
type: "text",
|
|
256
|
+
name: "name",
|
|
257
|
+
message: "What is your project name?",
|
|
258
|
+
initial: "my-project",
|
|
259
|
+
validate: (value) => value.trim().length > 0 || "Project name is required."
|
|
260
|
+
});
|
|
261
|
+
if (!name) {
|
|
262
|
+
logger.error("Project name is required.");
|
|
263
|
+
process.exit(1);
|
|
264
|
+
}
|
|
265
|
+
options.name = name;
|
|
266
|
+
}
|
|
267
|
+
if (!options.framework) {
|
|
268
|
+
const { framework } = await prompts({
|
|
269
|
+
type: "select",
|
|
270
|
+
name: "framework",
|
|
271
|
+
message: "Which framework would you like to use?",
|
|
272
|
+
choices: Object.keys(FRAMEWORKS).map((frameworkKey) => ({
|
|
273
|
+
title: FRAMEWORKS[frameworkKey].title,
|
|
274
|
+
value: frameworkKey
|
|
275
|
+
})),
|
|
276
|
+
initial: 0
|
|
277
|
+
});
|
|
278
|
+
if (!framework) {
|
|
279
|
+
logger.error("Framework selection is required.");
|
|
280
|
+
process.exit(1);
|
|
281
|
+
}
|
|
282
|
+
options.framework = framework;
|
|
283
|
+
}
|
|
284
|
+
if (!options.preset) {
|
|
285
|
+
const { preset } = await prompts({
|
|
286
|
+
type: "select",
|
|
287
|
+
name: "preset",
|
|
288
|
+
message: "Which preset would you like to use?",
|
|
289
|
+
choices: Object.entries(PRESETS).map(([key, preset]) => ({
|
|
290
|
+
title: preset.name,
|
|
291
|
+
value: key,
|
|
292
|
+
disabled: !preset.frameworks.includes(options.framework)
|
|
293
|
+
})),
|
|
294
|
+
initial: 0
|
|
295
|
+
});
|
|
296
|
+
if (!preset) {
|
|
297
|
+
logger.error("Preset selection is required.");
|
|
298
|
+
process.exit(1);
|
|
299
|
+
}
|
|
300
|
+
options.preset = preset;
|
|
301
|
+
}
|
|
302
|
+
if (!options.metaframework) {
|
|
303
|
+
const { metaframework } = await prompts({
|
|
304
|
+
type: "select",
|
|
305
|
+
name: "metaframework",
|
|
306
|
+
message: "Which metaframework would you like to use (optional)?",
|
|
307
|
+
choices: [{
|
|
308
|
+
title: "None",
|
|
309
|
+
value: "none"
|
|
310
|
+
}, ...Object.entries(METAFRAMEWORKS).filter(([_, meta]) => meta.frameworks.includes(options.framework)).map(([key, meta]) => ({
|
|
311
|
+
title: meta.title,
|
|
312
|
+
value: key
|
|
313
|
+
}))],
|
|
314
|
+
initial: 0
|
|
315
|
+
});
|
|
316
|
+
options.metaframework = metaframework === "none" ? void 0 : metaframework;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
async function ensureOverwriteAllowed(options) {
|
|
320
|
+
if (!fsExtra.existsSync(path.resolve(options.cwd, "components.json")) || options.override) return;
|
|
321
|
+
const { overwrite } = await prompts({
|
|
322
|
+
type: "confirm",
|
|
323
|
+
name: "overwrite",
|
|
324
|
+
message: `A ${highlighter.info("components.json")} file already exists. Would you like to overwrite it?`,
|
|
325
|
+
initial: false
|
|
326
|
+
});
|
|
327
|
+
if (!overwrite) {
|
|
328
|
+
logger.info(` To start over, remove the ${highlighter.info("components.json")} file and run ${highlighter.info("init")} again.`);
|
|
329
|
+
logger.break();
|
|
330
|
+
process.exit(1);
|
|
331
|
+
}
|
|
332
|
+
options.override = true;
|
|
333
|
+
}
|
|
334
|
+
//#endregion
|
|
335
|
+
//#region src/templates/create-template.ts
|
|
336
|
+
function createTemplate(config) {
|
|
337
|
+
return {
|
|
338
|
+
...config,
|
|
339
|
+
frameworks: config.frameworks || []
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
//#endregion
|
|
343
|
+
//#region src/templates/index.ts
|
|
344
|
+
const templates = {
|
|
345
|
+
react: createTemplate({ files: [{
|
|
346
|
+
path: "tsconfig.app.json",
|
|
347
|
+
content: dedent`{
|
|
348
|
+
"compilerOptions": {
|
|
349
|
+
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
|
350
|
+
"target": "ES2023",
|
|
351
|
+
"useDefineForClassFields": true,
|
|
352
|
+
"lib": ["ES2023", "DOM", "DOM.Iterable"],
|
|
353
|
+
"module": "ESNext",
|
|
354
|
+
"types": ["vite/client"],
|
|
355
|
+
"skipLibCheck": true,
|
|
356
|
+
/* Bundler mode */
|
|
357
|
+
"moduleResolution": "bundler",
|
|
358
|
+
"allowImportingTsExtensions": true,
|
|
359
|
+
"verbatimModuleSyntax": true,
|
|
360
|
+
"moduleDetection": "force",
|
|
361
|
+
"noEmit": true,
|
|
362
|
+
"jsx": "react-jsx",
|
|
363
|
+
/* Linting */
|
|
364
|
+
"strict": true,
|
|
365
|
+
"noUnusedLocals": true,
|
|
366
|
+
"noUnusedParameters": true,
|
|
367
|
+
"erasableSyntaxOnly": true,
|
|
368
|
+
"noFallthroughCasesInSwitch": true,
|
|
369
|
+
"noUncheckedSideEffectImports": true
|
|
370
|
+
},
|
|
371
|
+
"include": ["src"]
|
|
372
|
+
}
|
|
373
|
+
`
|
|
374
|
+
}, {
|
|
375
|
+
path: "tsconfig.json",
|
|
376
|
+
content: dedent`{
|
|
377
|
+
"files": [],
|
|
378
|
+
"references": [
|
|
379
|
+
{ "path": "./tsconfig.app.json" },
|
|
380
|
+
{ "path": "./tsconfig.node.json" }
|
|
381
|
+
]
|
|
382
|
+
}`
|
|
383
|
+
}] }),
|
|
384
|
+
solid: createTemplate({}),
|
|
385
|
+
svelte: createTemplate({}),
|
|
386
|
+
vue: createTemplate({})
|
|
387
|
+
};
|
|
388
|
+
//#endregion
|
|
389
|
+
//#region src/commands/init/run-init.ts
|
|
225
390
|
async function runInit(options) {
|
|
226
|
-
|
|
391
|
+
let cwd = options.cwd;
|
|
392
|
+
if (options.name && options.name !== ".") {
|
|
393
|
+
cwd = path.resolve(options.cwd, options.name);
|
|
394
|
+
await fsExtra.ensureDir(cwd);
|
|
395
|
+
options.cwd = cwd;
|
|
396
|
+
logger.info(`Using project directory: ${highlighter.info(options.name)}`);
|
|
397
|
+
}
|
|
398
|
+
const selectedTemplate = options.framework && options.framework in templates ? templates[options.framework] : void 0;
|
|
399
|
+
if (selectedTemplate?.files.length) for (const file of selectedTemplate.files) {
|
|
400
|
+
const targetPath = path.resolve(cwd, file.path);
|
|
401
|
+
if (fsExtra.existsSync(targetPath) && !options.override) {
|
|
402
|
+
logger.warn(`Skipping ${highlighter.info(file.path)} because it already exists. Use ${highlighter.info("--override")} to replace it.`);
|
|
403
|
+
continue;
|
|
404
|
+
}
|
|
405
|
+
await fsExtra.ensureDir(path.dirname(targetPath));
|
|
406
|
+
await fsExtra.writeFile(targetPath, file.content, "utf8");
|
|
407
|
+
logger.success(`Created ${highlighter.info(file.path)} template file.`);
|
|
408
|
+
}
|
|
227
409
|
const componentsJsonPath = path.resolve(cwd, "components.json");
|
|
228
410
|
logger.info("Starting project initialization...");
|
|
229
411
|
const config = {
|
|
@@ -257,114 +439,23 @@ async function runInit(options) {
|
|
|
257
439
|
throw error;
|
|
258
440
|
}
|
|
259
441
|
}
|
|
442
|
+
//#endregion
|
|
443
|
+
//#region src/commands/init.ts
|
|
260
444
|
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
445
|
try {
|
|
265
|
-
const options =
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
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];
|
|
446
|
+
const options = parseInitOptions(opts);
|
|
447
|
+
applyDefaultInitOptions(options);
|
|
448
|
+
validateExplicitOptions(options);
|
|
449
|
+
await promptForMissingSelections(options);
|
|
450
|
+
await ensureOverwriteAllowed(options);
|
|
357
451
|
options.components = components;
|
|
358
452
|
await loadEnvFiles(options.cwd);
|
|
359
453
|
await runInit(options);
|
|
360
454
|
logger.break();
|
|
361
|
-
logger.log(`Project initialization completed.\nYou may now add components.`);
|
|
362
|
-
|
|
363
|
-
deleteFileBackup(path.resolve(cwd, "components.json"));
|
|
455
|
+
logger.log(`Project initialization completed in ${highlighter.info(options.cwd)}.\nYou may now add components.`);
|
|
456
|
+
deleteFileBackup(path.resolve(options.cwd, "components.json"));
|
|
364
457
|
logger.break();
|
|
365
458
|
} catch (error) {
|
|
366
|
-
process.removeListener("exit", restoreBackupOnExit);
|
|
367
|
-
restoreBackupOnExit();
|
|
368
459
|
logger.break();
|
|
369
460
|
handleError(error);
|
|
370
461
|
} finally {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sprawlify",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.92",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "A command-line interface for Sprawlify.",
|
|
6
6
|
"author": "sprawlify <npm@sprawlify.com>",
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
"dependencies": {
|
|
20
20
|
"@dotenvx/dotenvx": "^1.55.1",
|
|
21
21
|
"commander": "^14.0.3",
|
|
22
|
+
"dedent": "^1.7.2",
|
|
22
23
|
"fs-extra": "^11.3.4",
|
|
23
24
|
"kleur": "^4.1.5",
|
|
24
25
|
"prompts": "^2.4.2",
|