@codecanvascollective/scaffold 0.1.0 → 0.1.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/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 CodeCanvas Collective
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2026 CodeCanvas Collective
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -24,13 +24,13 @@ npx @codecanvascollective/scaffold create my-app --express
24
24
 
25
25
  ## Supported Frameworks
26
26
 
27
- | Framework | Type | Variants |
28
- |-----------|------|----------|
29
- | React + Vite | Frontend | Base, Tailwind, shadcn/ui |
30
- | Next.js (App Router) | Frontend | Base, NextAuth, Prisma |
31
- | Angular 18 | Frontend | Base |
32
- | Express.js | Backend | Base, Prisma |
33
- | FastAPI | Backend | Base |
27
+ | Framework | Type | Variants |
28
+ | -------------------- | -------- | ------------------------- |
29
+ | React + Vite | Frontend | Base, Tailwind, shadcn/ui |
30
+ | Next.js (App Router) | Frontend | Base, NextAuth, Prisma |
31
+ | Angular 18 | Frontend | Base |
32
+ | Express.js | Backend | Base, Prisma |
33
+ | FastAPI | Backend | Base |
34
34
 
35
35
  ## Features
36
36
 
package/dist/index.js CHANGED
@@ -1,18 +1,12 @@
1
1
  #!/usr/bin/env node
2
- import {
3
- createDir,
4
- directoryExists,
5
- getTemplatesDir,
6
- renderAndWrite
7
- } from "./chunk-2A65KFCS.js";
8
2
 
9
3
  // src/cli.ts
10
4
  import { Command as Command4 } from "commander";
11
5
 
12
6
  // src/commands/create.ts
13
7
  import { Command } from "commander";
14
- import path4 from "path";
15
- import fs2 from "fs-extra";
8
+ import path5 from "path";
9
+ import fs3 from "fs-extra";
16
10
 
17
11
  // src/prompts/framework.ts
18
12
  import inquirer from "inquirer";
@@ -87,13 +81,23 @@ async function promptFeatures(projectType, framework) {
87
81
  checked: true,
88
82
  disabled: isPython ? "N/A for Python" : false
89
83
  },
90
- { name: "ESLint + Prettier", value: "eslint", checked: !isPython, disabled: isPython ? "N/A for Python" : false },
84
+ {
85
+ name: "ESLint + Prettier",
86
+ value: "eslint",
87
+ checked: !isPython,
88
+ disabled: isPython ? "N/A for Python" : false
89
+ },
91
90
  { name: "Tailwind CSS", value: "tailwind", checked: false },
92
91
  { name: "shadcn/ui components", value: "shadcn", checked: false },
93
92
  { name: isPython ? "Pytest testing" : "Vitest testing", value: "testing", checked: true },
94
93
  { name: "GitHub Actions CI/CD", value: "githubActions", checked: false },
95
94
  { name: "Docker setup", value: "docker", checked: false },
96
- { name: "Husky pre-commit hooks", value: "husky", checked: false, disabled: isPython ? "N/A for Python" : false },
95
+ {
96
+ name: "Husky pre-commit hooks",
97
+ value: "husky",
98
+ checked: false,
99
+ disabled: isPython ? "N/A for Python" : false
100
+ },
97
101
  { name: ".env example file", value: "envExample", checked: false }
98
102
  ];
99
103
  const filteredChoices = projectType === "backend" ? choices.filter((c) => !["tailwind", "shadcn"].includes(c.value)) : choices;
@@ -241,11 +245,11 @@ async function runPrompts(projectName) {
241
245
  }
242
246
 
243
247
  // src/generators/react.ts
244
- import path2 from "path";
248
+ import path3 from "path";
245
249
 
246
250
  // src/generators/base.ts
247
- import path from "path";
248
- import fs from "fs-extra";
251
+ import path2 from "path";
252
+ import fs2 from "fs-extra";
249
253
  import { execSync } from "child_process";
250
254
 
251
255
  // src/utils/logger.ts
@@ -276,6 +280,53 @@ function banner(text) {
276
280
  console.log(chalk.bold.cyan(text));
277
281
  }
278
282
 
283
+ // src/utils/file.ts
284
+ import path from "path";
285
+ import fs from "fs-extra";
286
+ import Handlebars from "handlebars";
287
+ import { fileURLToPath } from "url";
288
+ var __filename2 = fileURLToPath(import.meta.url);
289
+ var __dirname2 = path.dirname(__filename2);
290
+ Handlebars.registerHelper("eq", (a, b) => a === b);
291
+ Handlebars.registerHelper("neq", (a, b) => a !== b);
292
+ Handlebars.registerHelper("or", (a, b) => a || b);
293
+ Handlebars.registerHelper("and", (a, b) => a && b);
294
+ Handlebars.registerHelper("lowercase", (str) => str?.toLowerCase());
295
+ Handlebars.registerHelper("year", () => (/* @__PURE__ */ new Date()).getFullYear());
296
+ Handlebars.registerHelper(
297
+ "join",
298
+ (arr, sep) => Array.isArray(arr) ? arr.join(typeof sep === "string" ? sep : ", ") : ""
299
+ );
300
+ function getTemplatesDir() {
301
+ const isBundled = __dirname2.replace(/\\/g, "/").endsWith("/dist") || __dirname2.replace(/\\/g, "/").includes("/dist/");
302
+ const projectRoot = isBundled ? path.resolve(__dirname2, "..") : path.resolve(__dirname2, "..", "..");
303
+ return path.resolve(projectRoot, "src", "templates");
304
+ }
305
+ async function createDir(dirPath) {
306
+ await fs.ensureDir(dirPath);
307
+ }
308
+ async function writeFile(filePath, content) {
309
+ await fs.ensureDir(path.dirname(filePath));
310
+ await fs.writeFile(filePath, content, "utf-8");
311
+ }
312
+ async function renderTemplate(templatePath, data) {
313
+ const templateContent = await fs.readFile(templatePath, "utf-8");
314
+ const template = Handlebars.compile(templateContent, { noEscape: true });
315
+ return template(data);
316
+ }
317
+ async function renderAndWrite(templatePath, outputPath, data) {
318
+ const content = await renderTemplate(templatePath, data);
319
+ await writeFile(outputPath, content);
320
+ }
321
+ async function directoryExists(dirPath) {
322
+ try {
323
+ const stat = await fs.stat(dirPath);
324
+ return stat.isDirectory();
325
+ } catch {
326
+ return false;
327
+ }
328
+ }
329
+
279
330
  // src/utils/validator.ts
280
331
  var VALID_PROJECT_NAME = /^(?:@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/;
281
332
  function validateProjectName(name) {
@@ -320,7 +371,7 @@ var BaseGenerator = class {
320
371
  async applyVariant() {
321
372
  if (this.config.variant === "base") return;
322
373
  const variantDir = this.getVariantTemplateDir();
323
- if (await fs.pathExists(variantDir)) {
374
+ if (await fs2.pathExists(variantDir)) {
324
375
  const s = spinner(`Applying ${this.config.variant} variant`);
325
376
  s.start();
326
377
  await this.renderDirectory(variantDir, this.targetDir);
@@ -329,46 +380,46 @@ var BaseGenerator = class {
329
380
  }
330
381
  }
331
382
  async applySharedConfigs() {
332
- const sharedDir = path.join(this.templatesDir, "shared");
383
+ const sharedDir = path2.join(this.templatesDir, "shared");
333
384
  if (this.config.features.eslint) {
334
385
  const s = spinner("Setting up ESLint + Prettier");
335
386
  s.start();
336
387
  await this.renderTemplateFile(
337
- path.join(sharedDir, "eslint.config.js.hbs"),
338
- path.join(this.targetDir, "eslint.config.js")
388
+ path2.join(sharedDir, "eslint.config.js.hbs"),
389
+ path2.join(this.targetDir, "eslint.config.js")
339
390
  );
340
391
  await this.renderTemplateFile(
341
- path.join(sharedDir, "prettier.config.js.hbs"),
342
- path.join(this.targetDir, ".prettierrc")
392
+ path2.join(sharedDir, "prettier.config.js.hbs"),
393
+ path2.join(this.targetDir, ".prettierrc")
343
394
  );
344
395
  s.stop();
345
396
  success("Setting up ESLint + Prettier");
346
397
  }
347
398
  await this.renderTemplateFile(
348
- path.join(sharedDir, "gitignore.hbs"),
349
- path.join(this.targetDir, ".gitignore")
399
+ path2.join(sharedDir, "gitignore.hbs"),
400
+ path2.join(this.targetDir, ".gitignore")
350
401
  );
351
402
  const s2 = spinner("Generating README.md");
352
403
  s2.start();
353
404
  await this.renderTemplateFile(
354
- path.join(sharedDir, "readme.md.hbs"),
355
- path.join(this.targetDir, "README.md")
405
+ path2.join(sharedDir, "readme.md.hbs"),
406
+ path2.join(this.targetDir, "README.md")
356
407
  );
357
408
  s2.stop();
358
409
  success("Generating README.md");
359
410
  await this.renderTemplateFile(
360
- path.join(sharedDir, "license.hbs"),
361
- path.join(this.targetDir, "LICENSE")
411
+ path2.join(sharedDir, "license.hbs"),
412
+ path2.join(this.targetDir, "LICENSE")
362
413
  );
363
414
  }
364
415
  async applyFeatures() {
365
- const sharedDir = path.join(this.templatesDir, "shared");
416
+ const sharedDir = path2.join(this.templatesDir, "shared");
366
417
  if (this.config.features.githubActions) {
367
418
  const s = spinner("Creating GitHub Actions workflow");
368
419
  s.start();
369
420
  await this.renderTemplateFile(
370
- path.join(sharedDir, "github-ci.yml.hbs"),
371
- path.join(this.targetDir, ".github", "workflows", "ci.yml")
421
+ path2.join(sharedDir, "github-ci.yml.hbs"),
422
+ path2.join(this.targetDir, ".github", "workflows", "ci.yml")
372
423
  );
373
424
  s.stop();
374
425
  success("Creating GitHub Actions workflow");
@@ -377,12 +428,12 @@ var BaseGenerator = class {
377
428
  const s = spinner("Adding Docker configuration");
378
429
  s.start();
379
430
  await this.renderTemplateFile(
380
- path.join(sharedDir, "docker", "Dockerfile.hbs"),
381
- path.join(this.targetDir, "Dockerfile")
431
+ path2.join(sharedDir, "docker", "Dockerfile.hbs"),
432
+ path2.join(this.targetDir, "Dockerfile")
382
433
  );
383
434
  await this.renderTemplateFile(
384
- path.join(sharedDir, "docker", "docker-compose.yml.hbs"),
385
- path.join(this.targetDir, "docker-compose.yml")
435
+ path2.join(sharedDir, "docker", "docker-compose.yml.hbs"),
436
+ path2.join(this.targetDir, "docker-compose.yml")
386
437
  );
387
438
  s.stop();
388
439
  success("Adding Docker configuration");
@@ -415,7 +466,7 @@ var BaseGenerator = class {
415
466
  }
416
467
  async renderTemplateFile(templatePath, outputPath) {
417
468
  const templateData = this.getTemplateData();
418
- if (await fs.pathExists(templatePath)) {
469
+ if (await fs2.pathExists(templatePath)) {
419
470
  await renderAndWrite(templatePath, outputPath, templateData);
420
471
  this.result.filesCreated.push(outputPath);
421
472
  } else {
@@ -423,18 +474,18 @@ var BaseGenerator = class {
423
474
  }
424
475
  }
425
476
  async renderDirectory(srcDir, destDir) {
426
- const entries = await fs.readdir(srcDir, { withFileTypes: true });
477
+ const entries = await fs2.readdir(srcDir, { withFileTypes: true });
427
478
  for (const entry of entries) {
428
- const srcPath = path.join(srcDir, entry.name);
479
+ const srcPath = path2.join(srcDir, entry.name);
429
480
  const destName = entry.name.replace(/\.hbs$/, "");
430
- const destPath = path.join(destDir, destName);
481
+ const destPath = path2.join(destDir, destName);
431
482
  if (entry.isDirectory()) {
432
483
  await this.renderDirectory(srcPath, destPath);
433
484
  } else if (entry.name.endsWith(".hbs")) {
434
485
  await this.renderTemplateFile(srcPath, destPath);
435
486
  } else {
436
- await fs.ensureDir(path.dirname(destPath));
437
- await fs.copy(srcPath, destPath);
487
+ await fs2.ensureDir(path2.dirname(destPath));
488
+ await fs2.copy(srcPath, destPath);
438
489
  this.result.filesCreated.push(destPath);
439
490
  }
440
491
  }
@@ -446,10 +497,10 @@ var BaseGenerator = class {
446
497
  };
447
498
  }
448
499
  getBaseTemplateDir() {
449
- return path.join(this.templatesDir, this.config.framework, "base");
500
+ return path2.join(this.templatesDir, this.config.framework, "base");
450
501
  }
451
502
  getVariantTemplateDir() {
452
- return path.join(this.templatesDir, this.config.framework, this.config.variant);
503
+ return path2.join(this.templatesDir, this.config.framework, this.config.variant);
453
504
  }
454
505
  };
455
506
 
@@ -467,7 +518,7 @@ var ReactGenerator = class extends BaseGenerator {
467
518
  }
468
519
  }
469
520
  getVariantPath(variant) {
470
- return path2.join(this.templatesDir, "react", variant);
521
+ return path3.join(this.templatesDir, "react", variant);
471
522
  }
472
523
  };
473
524
 
@@ -527,35 +578,35 @@ var FastAPIGenerator = class extends BaseGenerator {
527
578
  }
528
579
  }
529
580
  async applySharedConfigs() {
530
- const path5 = await import("path");
531
- const sharedDir = path5.join(this.templatesDir, "shared");
581
+ const path6 = await import("path");
582
+ const sharedDir = path6.join(this.templatesDir, "shared");
532
583
  await this.renderTemplateFile(
533
- path5.join(sharedDir, "gitignore.hbs"),
534
- path5.join(this.targetDir, ".gitignore")
584
+ path6.join(sharedDir, "gitignore.hbs"),
585
+ path6.join(this.targetDir, ".gitignore")
535
586
  );
536
587
  const s = spinner("Generating README.md");
537
588
  s.start();
538
589
  await this.renderTemplateFile(
539
- path5.join(sharedDir, "readme.md.hbs"),
540
- path5.join(this.targetDir, "README.md")
590
+ path6.join(sharedDir, "readme.md.hbs"),
591
+ path6.join(this.targetDir, "README.md")
541
592
  );
542
593
  s.stop();
543
594
  success("Generating README.md");
544
595
  await this.renderTemplateFile(
545
- path5.join(sharedDir, "license.hbs"),
546
- path5.join(this.targetDir, "LICENSE")
596
+ path6.join(sharedDir, "license.hbs"),
597
+ path6.join(this.targetDir, "LICENSE")
547
598
  );
548
599
  }
549
600
  };
550
601
 
551
602
  // src/generators/fullstack.ts
552
- import path3 from "path";
603
+ import path4 from "path";
553
604
  var FullstackGenerator = class extends BaseGenerator {
554
605
  async generateBase() {
555
606
  const s = spinner("Setting up full-stack monorepo");
556
607
  s.start();
557
- const webDir = path3.join(this.targetDir, "apps", "web");
558
- const apiDir = path3.join(this.targetDir, "apps", "api");
608
+ const webDir = path4.join(this.targetDir, "apps", "web");
609
+ const apiDir = path4.join(this.targetDir, "apps", "api");
559
610
  await createDir(webDir);
560
611
  await createDir(apiDir);
561
612
  s.stop();
@@ -565,9 +616,8 @@ var FullstackGenerator = class extends BaseGenerator {
565
616
  type: "frontend",
566
617
  gitInit: false
567
618
  };
568
- const FrontendGenerator = this.getFrontendGeneratorClass();
569
- const frontendGen = new FrontendGenerator(frontendConfig, webDir);
570
- await frontendGen.generateBase();
619
+ const frontendGen = this.createFrontendGenerator(frontendConfig, webDir);
620
+ await frontendGen.generate();
571
621
  const backendConfig = {
572
622
  ...this.config,
573
623
  type: "backend",
@@ -575,8 +625,8 @@ var FullstackGenerator = class extends BaseGenerator {
575
625
  gitInit: false
576
626
  };
577
627
  const backendGen = new ExpressGenerator(backendConfig, apiDir);
578
- await backendGen.generateBase();
579
- const rootPkgPath = path3.join(this.targetDir, "package.json");
628
+ await backendGen.generate();
629
+ const rootPkgPath = path4.join(this.targetDir, "package.json");
580
630
  const rootPkg = {
581
631
  name: this.config.name,
582
632
  private: true,
@@ -588,18 +638,17 @@ var FullstackGenerator = class extends BaseGenerator {
588
638
  test: "npm run --workspaces test"
589
639
  }
590
640
  };
591
- const { writeFile: writeFile2 } = await import("./file-5IKT7CEX.js");
592
- await writeFile2(rootPkgPath, JSON.stringify(rootPkg, null, 2) + "\n");
641
+ await writeFile(rootPkgPath, JSON.stringify(rootPkg, null, 2) + "\n");
593
642
  }
594
- getFrontendGeneratorClass() {
595
- switch (this.config.framework) {
643
+ createFrontendGenerator(config, targetDir) {
644
+ switch (config.framework) {
596
645
  case "nextjs":
597
- return NextjsGenerator;
646
+ return new NextjsGenerator(config, targetDir);
598
647
  case "angular":
599
- return AngularGenerator;
648
+ return new AngularGenerator(config, targetDir);
600
649
  case "react":
601
650
  default:
602
- return ReactGenerator;
651
+ return new ReactGenerator(config, targetDir);
603
652
  }
604
653
  }
605
654
  };
@@ -665,7 +714,7 @@ async function handleCreate(projectName, options) {
665
714
  if (nameValidation !== true) {
666
715
  throw new Error(nameValidation);
667
716
  }
668
- const targetDir = path4.resolve(process.cwd(), projectName);
717
+ const targetDir = path5.resolve(process.cwd(), projectName);
669
718
  if (!options.force) {
670
719
  const dirValidation = await validateDirectory(targetDir);
671
720
  if (dirValidation !== true) {
@@ -725,8 +774,8 @@ function buildQuickConfig(projectName, options) {
725
774
  return config;
726
775
  }
727
776
  async function loadConfigFromFile(configPath, projectName) {
728
- const resolvedPath = path4.resolve(process.cwd(), configPath);
729
- const content = await fs2.readJSON(resolvedPath);
777
+ const resolvedPath = path5.resolve(process.cwd(), configPath);
778
+ const content = await fs3.readJSON(resolvedPath);
730
779
  return { ...DEFAULT_CONFIG, ...content, name: projectName };
731
780
  }
732
781
 
@@ -748,7 +797,9 @@ function listCommand() {
748
797
  newLine();
749
798
  for (const fw of frameworks) {
750
799
  const meta = FRAMEWORKS[fw];
751
- console.log(` ${chalk2.green(meta.displayName.padEnd(25))} ${chalk2.gray(meta.description)}`);
800
+ console.log(
801
+ ` ${chalk2.green(meta.displayName.padEnd(25))} ${chalk2.gray(meta.description)}`
802
+ );
752
803
  for (const variant of meta.variants) {
753
804
  const label = VARIANT_DISPLAY_NAMES[variant];
754
805
  console.log(` ${chalk2.gray("\u2022")} ${label}`);
@@ -795,10 +846,14 @@ function doctorCommand() {
795
846
  console.log(` ${chalk3.green("\u2714")} ${check.name.padEnd(12)} ${chalk3.gray(versionStr)}`);
796
847
  } catch {
797
848
  if (check.required) {
798
- console.log(` ${chalk3.red("\u2716")} ${check.name.padEnd(12)} ${chalk3.red("not found (required)")}`);
849
+ console.log(
850
+ ` ${chalk3.red("\u2716")} ${check.name.padEnd(12)} ${chalk3.red("not found (required)")}`
851
+ );
799
852
  allGood = false;
800
853
  } else {
801
- console.log(` ${chalk3.yellow("\u2013")} ${check.name.padEnd(12)} ${chalk3.gray("not found (optional)")}`);
854
+ console.log(
855
+ ` ${chalk3.yellow("\u2013")} ${check.name.padEnd(12)} ${chalk3.gray("not found (optional)")}`
856
+ );
802
857
  }
803
858
  }
804
859
  }
@@ -815,7 +870,7 @@ function doctorCommand() {
815
870
  // src/cli.ts
816
871
  function createCli() {
817
872
  const program2 = new Command4();
818
- program2.name("scaffold").description("CLI tool for scaffolding modern full-stack projects").version("0.1.0").option("--verbose", "Enable verbose output").hook("preAction", (thisCommand) => {
873
+ program2.name("scaffold").description("CLI tool for scaffolding modern full-stack projects").version("0.1.1").option("--verbose", "Enable verbose output").hook("preAction", (thisCommand) => {
819
874
  const opts = thisCommand.opts();
820
875
  if (opts.verbose) {
821
876
  setVerbose(true);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts","../src/commands/create.ts","../src/prompts/framework.ts","../src/prompts/features.ts","../src/prompts/config.ts","../src/constants.ts","../src/prompts/index.ts","../src/generators/react.ts","../src/generators/base.ts","../src/utils/logger.ts","../src/utils/validator.ts","../src/generators/nextjs.ts","../src/generators/angular.ts","../src/generators/express.ts","../src/generators/fastapi.ts","../src/generators/fullstack.ts","../src/generators/index.ts","../src/types/config.ts","../src/commands/list.ts","../src/commands/doctor.ts","../src/index.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { createCommand } from './commands/create.js';\nimport { listCommand } from './commands/list.js';\nimport { doctorCommand } from './commands/doctor.js';\nimport { setVerbose } from './utils/logger.js';\n\nexport function createCli(): Command {\n const program = new Command();\n\n program\n .name('scaffold')\n .description('CLI tool for scaffolding modern full-stack projects')\n .version('0.1.0')\n .option('--verbose', 'Enable verbose output')\n .hook('preAction', (thisCommand) => {\n const opts = thisCommand.opts();\n if (opts.verbose) {\n setVerbose(true);\n }\n });\n\n program.addCommand(createCommand());\n program.addCommand(listCommand());\n program.addCommand(doctorCommand());\n\n return program;\n}\n","import { Command } from 'commander';\nimport path from 'node:path';\nimport fs from 'fs-extra';\nimport { runPrompts } from '../prompts/index.js';\nimport { createGenerator } from '../generators/index.js';\nimport { validateProjectName, validateDirectory, success, error, newLine, banner } from '../utils/index.js';\nimport type { ProjectConfig } from '../types/index.js';\nimport { DEFAULT_CONFIG } from '../types/index.js';\n\ninterface CreateOptions {\n react?: boolean;\n nextjs?: boolean;\n angular?: boolean;\n express?: boolean;\n fastapi?: boolean;\n yes?: boolean;\n from?: string;\n force?: boolean;\n}\n\nexport function createCommand(): Command {\n const cmd = new Command('create')\n .description('Create a new project')\n .argument('<project-name>', 'Name of the project')\n .option('--react', 'Create a React + Vite project')\n .option('--nextjs', 'Create a Next.js project')\n .option('--angular', 'Create an Angular project')\n .option('--express', 'Create an Express.js project')\n .option('--fastapi', 'Create a FastAPI project')\n .option('-y, --yes', 'Skip prompts and use defaults')\n .option('--from <path>', 'Create from a config file')\n .option('--force', 'Overwrite existing directory')\n .action(async (projectName: string, options: CreateOptions) => {\n try {\n await handleCreate(projectName, options);\n } catch (err) {\n error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n });\n\n return cmd;\n}\n\nasync function handleCreate(projectName: string, options: CreateOptions): Promise<void> {\n const nameValidation = validateProjectName(projectName);\n if (nameValidation !== true) {\n throw new Error(nameValidation);\n }\n\n const targetDir = path.resolve(process.cwd(), projectName);\n\n if (!options.force) {\n const dirValidation = await validateDirectory(targetDir);\n if (dirValidation !== true) {\n throw new Error(dirValidation);\n }\n }\n\n let config: ProjectConfig;\n\n if (options.from) {\n config = await loadConfigFromFile(options.from, projectName);\n } else if (options.yes || hasFrameworkFlag(options)) {\n config = buildQuickConfig(projectName, options);\n } else {\n config = await runPrompts(projectName);\n }\n\n newLine();\n banner(`Creating project \"${config.name}\"...`);\n newLine();\n\n const generator = createGenerator(config, targetDir);\n await generator.generate();\n\n newLine();\n success(`Project \"${config.name}\" created successfully! 🎉`);\n newLine();\n console.log('Next steps:');\n console.log(` cd ${config.name}`);\n\n if (config.framework === 'fastapi') {\n console.log(' pip install -r requirements.txt');\n console.log(' uvicorn app.main:app --reload');\n } else {\n console.log(` ${config.packageManager} install`);\n console.log(` ${config.packageManager} run dev`);\n }\n\n newLine();\n console.log('Happy coding! 🚀');\n newLine();\n}\n\nfunction hasFrameworkFlag(options: CreateOptions): boolean {\n return !!(options.react || options.nextjs || options.angular || options.express || options.fastapi);\n}\n\nfunction buildQuickConfig(projectName: string, options: CreateOptions): ProjectConfig {\n const config: ProjectConfig = { ...DEFAULT_CONFIG, name: projectName };\n\n if (options.react) {\n config.type = 'frontend';\n config.framework = 'react';\n } else if (options.nextjs) {\n config.type = 'frontend';\n config.framework = 'nextjs';\n } else if (options.angular) {\n config.type = 'frontend';\n config.framework = 'angular';\n } else if (options.express) {\n config.type = 'backend';\n config.framework = 'express';\n } else if (options.fastapi) {\n config.type = 'backend';\n config.framework = 'fastapi';\n }\n\n return config;\n}\n\nasync function loadConfigFromFile(configPath: string, projectName: string): Promise<ProjectConfig> {\n const resolvedPath = path.resolve(process.cwd(), configPath);\n const content = await fs.readJSON(resolvedPath);\n return { ...DEFAULT_CONFIG, ...content, name: projectName };\n}\n","import inquirer from 'inquirer';\nimport type { ProjectType, FrameworkType } from '../types/index.js';\n\nexport async function promptProjectType(): Promise<ProjectType> {\n const { projectType } = await inquirer.prompt([\n {\n type: 'list',\n name: 'projectType',\n message: 'What type of project?',\n choices: [\n { name: 'Frontend (React, Next.js, Angular)', value: 'frontend' },\n { name: 'Backend (Express, FastAPI)', value: 'backend' },\n { name: 'Full-Stack (Frontend + Backend)', value: 'fullstack' },\n ],\n },\n ]);\n\n return projectType;\n}\n\nexport async function promptFramework(projectType: ProjectType): Promise<FrameworkType> {\n if (projectType === 'frontend') {\n const { framework } = await inquirer.prompt([\n {\n type: 'list',\n name: 'framework',\n message: 'Which frontend framework?',\n choices: [\n { name: 'React + Vite', value: 'react' },\n { name: 'Next.js (App Router)', value: 'nextjs' },\n { name: 'Angular 18', value: 'angular' },\n ],\n },\n ]);\n return framework;\n }\n\n if (projectType === 'backend') {\n const { framework } = await inquirer.prompt([\n {\n type: 'list',\n name: 'framework',\n message: 'Which backend framework?',\n choices: [\n { name: 'Express.js', value: 'express' },\n { name: 'FastAPI (Python)', value: 'fastapi' },\n ],\n },\n ]);\n return framework;\n }\n\n // fullstack — prompt for frontend (we'll use express as the backend)\n const { framework } = await inquirer.prompt([\n {\n type: 'list',\n name: 'framework',\n message: 'Which frontend framework?',\n choices: [\n { name: 'React + Vite', value: 'react' },\n { name: 'Next.js', value: 'nextjs' },\n { name: 'Angular 18', value: 'angular' },\n ],\n },\n ]);\n return framework;\n}\n","import inquirer from 'inquirer';\nimport type { FeatureFlags, ProjectType, FrameworkType } from '../types/index.js';\n\ninterface FeatureChoice {\n name: string;\n value: keyof FeatureFlags;\n checked: boolean;\n disabled?: string | false;\n}\n\nexport async function promptFeatures(\n projectType: ProjectType,\n framework: FrameworkType,\n): Promise<FeatureFlags> {\n const isPython = framework === 'fastapi';\n\n const choices: FeatureChoice[] = [\n {\n name: 'TypeScript',\n value: 'typescript',\n checked: true,\n disabled: isPython ? 'N/A for Python' : false,\n },\n { name: 'ESLint + Prettier', value: 'eslint', checked: !isPython, disabled: isPython ? 'N/A for Python' : false },\n { name: 'Tailwind CSS', value: 'tailwind', checked: false },\n { name: 'shadcn/ui components', value: 'shadcn', checked: false },\n { name: isPython ? 'Pytest testing' : 'Vitest testing', value: 'testing', checked: true },\n { name: 'GitHub Actions CI/CD', value: 'githubActions', checked: false },\n { name: 'Docker setup', value: 'docker', checked: false },\n { name: 'Husky pre-commit hooks', value: 'husky', checked: false, disabled: isPython ? 'N/A for Python' : false },\n { name: '.env example file', value: 'envExample', checked: false },\n ];\n\n // Filter out frontend-only features for backend projects\n const filteredChoices =\n projectType === 'backend'\n ? choices.filter((c) => !['tailwind', 'shadcn'].includes(c.value))\n : choices;\n\n const { features } = await inquirer.prompt([\n {\n type: 'checkbox',\n name: 'features',\n message: 'Select features:',\n choices: filteredChoices,\n },\n ]);\n\n const selectedFeatures = features as (keyof FeatureFlags)[];\n\n return {\n typescript: !isPython && selectedFeatures.includes('typescript'),\n eslint: !isPython && selectedFeatures.includes('eslint'),\n prettier: !isPython && selectedFeatures.includes('eslint'),\n tailwind: selectedFeatures.includes('tailwind'),\n shadcn: selectedFeatures.includes('shadcn'),\n testing: selectedFeatures.includes('testing'),\n githubActions: selectedFeatures.includes('githubActions'),\n docker: selectedFeatures.includes('docker'),\n husky: !isPython && selectedFeatures.includes('husky'),\n envExample: selectedFeatures.includes('envExample'),\n };\n}\n","import inquirer from 'inquirer';\nimport type { VariantType, PackageManager, FrameworkType } from '../types/index.js';\nimport { FRAMEWORKS, VARIANT_DISPLAY_NAMES } from '../constants.js';\n\nexport async function promptVariant(framework: FrameworkType): Promise<VariantType> {\n const meta = FRAMEWORKS[framework];\n\n if (meta.variants.length <= 1) {\n return 'base';\n }\n\n const { variant } = await inquirer.prompt([\n {\n type: 'list',\n name: 'variant',\n message: 'Select a template variant:',\n choices: meta.variants.map((v) => ({\n name: VARIANT_DISPLAY_NAMES[v],\n value: v,\n })),\n },\n ]);\n\n return variant;\n}\n\nexport async function promptPackageManager(): Promise<PackageManager> {\n const { packageManager } = await inquirer.prompt([\n {\n type: 'list',\n name: 'packageManager',\n message: 'Package manager?',\n choices: [\n { name: 'npm', value: 'npm' },\n { name: 'yarn', value: 'yarn' },\n { name: 'pnpm', value: 'pnpm' },\n ],\n },\n ]);\n\n return packageManager;\n}\n\nexport async function promptGitInit(): Promise<boolean> {\n const { gitInit } = await inquirer.prompt([\n {\n type: 'confirm',\n name: 'gitInit',\n message: 'Initialize git repository?',\n default: true,\n },\n ]);\n\n return gitInit;\n}\n","import type { FrameworkMeta, FrameworkType, VariantType } from './types/index.js';\n\nexport const FRAMEWORKS: Record<FrameworkType, FrameworkMeta> = {\n react: {\n name: 'react',\n displayName: 'React + Vite',\n description: 'React 19 with Vite and TypeScript',\n type: 'frontend',\n variants: ['base', 'with-tailwind', 'with-shadcn'],\n language: 'typescript',\n },\n nextjs: {\n name: 'nextjs',\n displayName: 'Next.js (App Router)',\n description: 'Next.js 15 with App Router and TypeScript',\n type: 'frontend',\n variants: ['base', 'with-auth', 'with-prisma'],\n language: 'typescript',\n },\n angular: {\n name: 'angular',\n displayName: 'Angular 18',\n description: 'Angular 18 standalone with TypeScript',\n type: 'frontend',\n variants: ['base'],\n language: 'typescript',\n },\n express: {\n name: 'express',\n displayName: 'Express.js',\n description: 'Express 5 with TypeScript',\n type: 'backend',\n variants: ['base', 'with-prisma'],\n language: 'typescript',\n },\n fastapi: {\n name: 'fastapi',\n displayName: 'FastAPI',\n description: 'FastAPI with Pydantic and Python',\n type: 'backend',\n variants: ['base'],\n language: 'python',\n },\n};\n\nexport const FRONTEND_FRAMEWORKS: FrameworkType[] = ['react', 'nextjs', 'angular'];\nexport const BACKEND_FRAMEWORKS: FrameworkType[] = ['express', 'fastapi'];\n\nexport const VARIANT_DISPLAY_NAMES: Record<VariantType, string> = {\n base: 'Base (minimal setup)',\n 'with-tailwind': 'With Tailwind CSS',\n 'with-shadcn': 'With shadcn/ui',\n 'with-auth': 'With NextAuth.js',\n 'with-prisma': 'With Prisma ORM',\n};\n","import type { ProjectConfig } from '../types/index.js';\nimport { promptProjectType, promptFramework } from './framework.js';\nimport { promptFeatures } from './features.js';\nimport { promptVariant, promptPackageManager, promptGitInit } from './config.js';\n\nexport async function runPrompts(projectName: string): Promise<ProjectConfig> {\n const type = await promptProjectType();\n const framework = await promptFramework(type);\n const variant = await promptVariant(framework);\n const features = await promptFeatures(type, framework);\n\n const isPython = framework === 'fastapi';\n const packageManager = isPython ? 'npm' : await promptPackageManager();\n const gitInit = await promptGitInit();\n\n return {\n name: projectName,\n type,\n framework,\n variant,\n features,\n packageManager,\n gitInit,\n };\n}\n","import path from 'node:path';\nimport { BaseGenerator } from './base.js';\nimport { spinner, success } from '../utils/index.js';\n\nexport class ReactGenerator extends BaseGenerator {\n protected async generateBase(): Promise<void> {\n const baseDir = this.getBaseTemplateDir();\n\n const s = spinner('Configuring React + Vite + TypeScript');\n s.start();\n await this.renderDirectory(baseDir, this.targetDir);\n s.stop();\n success('Configuring React + Vite + TypeScript');\n\n if (this.config.features.testing) {\n success('Configuring Vitest');\n }\n }\n\n private getVariantPath(variant: string): string {\n return path.join(this.templatesDir, 'react', variant);\n }\n}\n","import path from 'node:path';\nimport fs from 'fs-extra';\nimport { execSync } from 'node:child_process';\nimport { createDir, renderAndWrite, getTemplatesDir, spinner, success, debug } from '../utils/index.js';\nimport type { ProjectConfig } from '../types/index.js';\nimport type { GeneratorResult } from '../types/generator.js';\n\nexport abstract class BaseGenerator {\n protected config: ProjectConfig;\n protected targetDir: string;\n protected templatesDir: string;\n protected result: GeneratorResult = { filesCreated: [], warnings: [] };\n\n constructor(config: ProjectConfig, targetDir: string) {\n this.config = config;\n this.targetDir = targetDir;\n this.templatesDir = getTemplatesDir();\n }\n\n async generate(): Promise<GeneratorResult> {\n await this.createProjectDir();\n await this.generateBase();\n await this.applyVariant();\n await this.applySharedConfigs();\n await this.applyFeatures();\n await this.initGit();\n return this.result;\n }\n\n protected abstract generateBase(): Promise<void>;\n\n protected async applyVariant(): Promise<void> {\n if (this.config.variant === 'base') return;\n\n const variantDir = this.getVariantTemplateDir();\n if (await fs.pathExists(variantDir)) {\n const s = spinner(`Applying ${this.config.variant} variant`);\n s.start();\n await this.renderDirectory(variantDir, this.targetDir);\n s.stop();\n success(`Applied ${this.config.variant} variant`);\n }\n }\n\n protected async applySharedConfigs(): Promise<void> {\n const sharedDir = path.join(this.templatesDir, 'shared');\n\n if (this.config.features.eslint) {\n const s = spinner('Setting up ESLint + Prettier');\n s.start();\n await this.renderTemplateFile(\n path.join(sharedDir, 'eslint.config.js.hbs'),\n path.join(this.targetDir, 'eslint.config.js'),\n );\n await this.renderTemplateFile(\n path.join(sharedDir, 'prettier.config.js.hbs'),\n path.join(this.targetDir, '.prettierrc'),\n );\n s.stop();\n success('Setting up ESLint + Prettier');\n }\n\n // Gitignore\n await this.renderTemplateFile(\n path.join(sharedDir, 'gitignore.hbs'),\n path.join(this.targetDir, '.gitignore'),\n );\n\n // README\n const s2 = spinner('Generating README.md');\n s2.start();\n await this.renderTemplateFile(\n path.join(sharedDir, 'readme.md.hbs'),\n path.join(this.targetDir, 'README.md'),\n );\n s2.stop();\n success('Generating README.md');\n\n // License\n await this.renderTemplateFile(\n path.join(sharedDir, 'license.hbs'),\n path.join(this.targetDir, 'LICENSE'),\n );\n }\n\n protected async applyFeatures(): Promise<void> {\n const sharedDir = path.join(this.templatesDir, 'shared');\n\n if (this.config.features.githubActions) {\n const s = spinner('Creating GitHub Actions workflow');\n s.start();\n await this.renderTemplateFile(\n path.join(sharedDir, 'github-ci.yml.hbs'),\n path.join(this.targetDir, '.github', 'workflows', 'ci.yml'),\n );\n s.stop();\n success('Creating GitHub Actions workflow');\n }\n\n if (this.config.features.docker) {\n const s = spinner('Adding Docker configuration');\n s.start();\n await this.renderTemplateFile(\n path.join(sharedDir, 'docker', 'Dockerfile.hbs'),\n path.join(this.targetDir, 'Dockerfile'),\n );\n await this.renderTemplateFile(\n path.join(sharedDir, 'docker', 'docker-compose.yml.hbs'),\n path.join(this.targetDir, 'docker-compose.yml'),\n );\n s.stop();\n success('Adding Docker configuration');\n }\n }\n\n protected async createProjectDir(): Promise<void> {\n const s = spinner('Creating project structure');\n s.start();\n await createDir(this.targetDir);\n s.stop();\n success('Creating project structure');\n }\n\n protected async initGit(): Promise<void> {\n if (!this.config.gitInit) return;\n\n const s = spinner('Initializing git repository');\n s.start();\n try {\n execSync('git init', { cwd: this.targetDir, stdio: 'pipe' });\n execSync('git add -A', { cwd: this.targetDir, stdio: 'pipe' });\n execSync('git commit -m \"Initial commit from scaffold\"', {\n cwd: this.targetDir,\n stdio: 'pipe',\n });\n s.stop();\n success('Initializing git repository');\n } catch {\n s.stop();\n debug('Git initialization skipped (git not available)');\n }\n }\n\n protected async renderTemplateFile(\n templatePath: string,\n outputPath: string,\n ): Promise<void> {\n const templateData = this.getTemplateData();\n\n if (await fs.pathExists(templatePath)) {\n await renderAndWrite(templatePath, outputPath, templateData);\n this.result.filesCreated.push(outputPath);\n } else {\n debug(`Template not found: ${templatePath}`);\n }\n }\n\n protected async renderDirectory(srcDir: string, destDir: string): Promise<void> {\n const entries = await fs.readdir(srcDir, { withFileTypes: true });\n\n for (const entry of entries) {\n const srcPath = path.join(srcDir, entry.name);\n const destName = entry.name.replace(/\\.hbs$/, '');\n const destPath = path.join(destDir, destName);\n\n if (entry.isDirectory()) {\n await this.renderDirectory(srcPath, destPath);\n } else if (entry.name.endsWith('.hbs')) {\n await this.renderTemplateFile(srcPath, destPath);\n } else {\n await fs.ensureDir(path.dirname(destPath));\n await fs.copy(srcPath, destPath);\n this.result.filesCreated.push(destPath);\n }\n }\n }\n\n protected getTemplateData(): object {\n return {\n ...this.config,\n year: new Date().getFullYear(),\n };\n }\n\n protected getBaseTemplateDir(): string {\n return path.join(this.templatesDir, this.config.framework, 'base');\n }\n\n protected getVariantTemplateDir(): string {\n return path.join(this.templatesDir, this.config.framework, this.config.variant);\n }\n}\n","import chalk from 'chalk';\nimport ora, { type Ora } from 'ora';\n\nlet verbose = false;\n\nexport function setVerbose(value: boolean): void {\n verbose = value;\n}\n\nexport function info(message: string): void {\n console.log(chalk.blue('ℹ'), message);\n}\n\nexport function success(message: string): void {\n console.log(chalk.green('✔'), message);\n}\n\nexport function warn(message: string): void {\n console.log(chalk.yellow('⚠'), message);\n}\n\nexport function error(message: string): void {\n console.log(chalk.red('✖'), message);\n}\n\nexport function debug(message: string): void {\n if (verbose) {\n console.log(chalk.gray('⬥'), chalk.gray(message));\n }\n}\n\nexport function spinner(text: string): Ora {\n return ora({ text, color: 'cyan' });\n}\n\nexport function newLine(): void {\n console.log();\n}\n\nexport function banner(text: string): void {\n console.log(chalk.bold.cyan(text));\n}\n","import { directoryExists } from './file.js';\n\nconst VALID_PROJECT_NAME = /^(?:@[a-z0-9-~][a-z0-9-._~]*\\/)?[a-z0-9-~][a-z0-9-._~]*$/;\n\nexport function validateProjectName(name: string): string | true {\n if (!name || name.trim().length === 0) {\n return 'Project name is required.';\n }\n\n if (!VALID_PROJECT_NAME.test(name)) {\n return 'Project name must be a valid npm package name (lowercase, no spaces, can use hyphens and dots).';\n }\n\n if (name.length > 214) {\n return 'Project name must be less than 214 characters.';\n }\n\n return true;\n}\n\nexport async function validateDirectory(dirPath: string): Promise<string | true> {\n if (await directoryExists(dirPath)) {\n return `Directory \"${dirPath}\" already exists. Use --force to overwrite.`;\n }\n return true;\n}\n\nexport function checkNodeVersion(minMajor: number = 20): string | true {\n const version = process.version;\n const major = parseInt(version.slice(1).split('.')[0], 10);\n\n if (major < minMajor) {\n return `Node.js ${minMajor}+ is required. You are using ${version}.`;\n }\n\n return true;\n}\n","import { BaseGenerator } from './base.js';\nimport { spinner, success } from '../utils/index.js';\n\nexport class NextjsGenerator extends BaseGenerator {\n protected async generateBase(): Promise<void> {\n const baseDir = this.getBaseTemplateDir();\n\n const s = spinner('Configuring Next.js + App Router + TypeScript');\n s.start();\n await this.renderDirectory(baseDir, this.targetDir);\n s.stop();\n success('Configuring Next.js + App Router + TypeScript');\n\n if (this.config.features.testing) {\n success('Configuring Vitest');\n }\n }\n}\n","import { BaseGenerator } from './base.js';\nimport { spinner, success } from '../utils/index.js';\n\nexport class AngularGenerator extends BaseGenerator {\n protected async generateBase(): Promise<void> {\n const baseDir = this.getBaseTemplateDir();\n\n const s = spinner('Configuring Angular 18 + TypeScript');\n s.start();\n await this.renderDirectory(baseDir, this.targetDir);\n s.stop();\n success('Configuring Angular 18 + TypeScript');\n }\n}\n","import { BaseGenerator } from './base.js';\nimport { spinner, success } from '../utils/index.js';\n\nexport class ExpressGenerator extends BaseGenerator {\n protected async generateBase(): Promise<void> {\n const baseDir = this.getBaseTemplateDir();\n\n const s = spinner('Configuring Express 5 + TypeScript');\n s.start();\n await this.renderDirectory(baseDir, this.targetDir);\n s.stop();\n success('Configuring Express 5 + TypeScript');\n\n if (this.config.features.testing) {\n success('Configuring Vitest');\n }\n }\n}\n","import { BaseGenerator } from './base.js';\nimport { spinner, success } from '../utils/index.js';\n\nexport class FastAPIGenerator extends BaseGenerator {\n protected async generateBase(): Promise<void> {\n const baseDir = this.getBaseTemplateDir();\n\n const s = spinner('Configuring FastAPI + Pydantic');\n s.start();\n await this.renderDirectory(baseDir, this.targetDir);\n s.stop();\n success('Configuring FastAPI + Pydantic');\n\n if (this.config.features.testing) {\n success('Configuring Pytest');\n }\n }\n\n protected override async applySharedConfigs(): Promise<void> {\n // Python projects don't use ESLint/Prettier/tsconfig\n const path = await import('node:path');\n const sharedDir = path.join(this.templatesDir, 'shared');\n\n // Still apply gitignore, readme, license\n await this.renderTemplateFile(\n path.join(sharedDir, 'gitignore.hbs'),\n path.join(this.targetDir, '.gitignore'),\n );\n\n const s = spinner('Generating README.md');\n s.start();\n await this.renderTemplateFile(\n path.join(sharedDir, 'readme.md.hbs'),\n path.join(this.targetDir, 'README.md'),\n );\n s.stop();\n success('Generating README.md');\n\n await this.renderTemplateFile(\n path.join(sharedDir, 'license.hbs'),\n path.join(this.targetDir, 'LICENSE'),\n );\n }\n}\n","import path from 'node:path';\nimport { BaseGenerator } from './base.js';\nimport { ReactGenerator } from './react.js';\nimport { NextjsGenerator } from './nextjs.js';\nimport { AngularGenerator } from './angular.js';\nimport { ExpressGenerator } from './express.js';\nimport { spinner, success, createDir } from '../utils/index.js';\nimport { renderAndWrite, getTemplatesDir } from '../utils/file.js';\nimport type { ProjectConfig } from '../types/index.js';\n\nexport class FullstackGenerator extends BaseGenerator {\n protected async generateBase(): Promise<void> {\n const s = spinner('Setting up full-stack monorepo');\n s.start();\n\n // Create apps directories\n const webDir = path.join(this.targetDir, 'apps', 'web');\n const apiDir = path.join(this.targetDir, 'apps', 'api');\n await createDir(webDir);\n await createDir(apiDir);\n\n s.stop();\n success('Setting up full-stack monorepo');\n\n // Generate frontend in apps/web\n const frontendConfig: ProjectConfig = {\n ...this.config,\n type: 'frontend',\n gitInit: false,\n };\n\n const FrontendGenerator = this.getFrontendGeneratorClass();\n const frontendGen = new FrontendGenerator(frontendConfig, webDir);\n await frontendGen.generateBase();\n\n // Generate backend in apps/api\n const backendConfig: ProjectConfig = {\n ...this.config,\n type: 'backend',\n framework: 'express',\n gitInit: false,\n };\n\n const backendGen = new ExpressGenerator(backendConfig, apiDir);\n await backendGen.generateBase();\n\n // Write root package.json for workspaces\n const rootPkgPath = path.join(this.targetDir, 'package.json');\n const rootPkg = {\n name: this.config.name,\n private: true,\n workspaces: ['apps/*'],\n scripts: {\n dev: 'npm run --workspaces dev',\n build: 'npm run --workspaces build',\n lint: 'npm run --workspaces lint',\n test: 'npm run --workspaces test',\n },\n };\n const { writeFile } = await import('../utils/file.js');\n await writeFile(rootPkgPath, JSON.stringify(rootPkg, null, 2) + '\\n');\n }\n\n private getFrontendGeneratorClass() {\n switch (this.config.framework) {\n case 'nextjs':\n return NextjsGenerator;\n case 'angular':\n return AngularGenerator;\n case 'react':\n default:\n return ReactGenerator;\n }\n }\n}\n","import type { ProjectConfig } from '../types/index.js';\nimport { BaseGenerator } from './base.js';\nimport { ReactGenerator } from './react.js';\nimport { NextjsGenerator } from './nextjs.js';\nimport { AngularGenerator } from './angular.js';\nimport { ExpressGenerator } from './express.js';\nimport { FastAPIGenerator } from './fastapi.js';\nimport { FullstackGenerator } from './fullstack.js';\n\nexport function createGenerator(config: ProjectConfig, targetDir: string): BaseGenerator {\n if (config.type === 'fullstack') {\n return new FullstackGenerator(config, targetDir);\n }\n\n switch (config.framework) {\n case 'react':\n return new ReactGenerator(config, targetDir);\n case 'nextjs':\n return new NextjsGenerator(config, targetDir);\n case 'angular':\n return new AngularGenerator(config, targetDir);\n case 'express':\n return new ExpressGenerator(config, targetDir);\n case 'fastapi':\n return new FastAPIGenerator(config, targetDir);\n default:\n throw new Error(`Unknown framework: ${config.framework}`);\n }\n}\n\nexport { BaseGenerator } from './base.js';\n","export type ProjectType = 'frontend' | 'backend' | 'fullstack';\n\nexport type FrameworkType = 'react' | 'nextjs' | 'angular' | 'express' | 'fastapi';\n\nexport type VariantType =\n | 'base'\n | 'with-tailwind'\n | 'with-shadcn'\n | 'with-auth'\n | 'with-prisma';\n\nexport type PackageManager = 'npm' | 'yarn' | 'pnpm';\n\nexport interface FeatureFlags {\n typescript: boolean;\n eslint: boolean;\n prettier: boolean;\n tailwind: boolean;\n shadcn: boolean;\n testing: boolean;\n githubActions: boolean;\n docker: boolean;\n husky: boolean;\n envExample: boolean;\n}\n\nexport interface ProjectConfig {\n name: string;\n type: ProjectType;\n framework: FrameworkType;\n variant: VariantType;\n features: FeatureFlags;\n packageManager: PackageManager;\n gitInit: boolean;\n}\n\nexport interface FrameworkMeta {\n name: string;\n displayName: string;\n description: string;\n type: ProjectType;\n variants: VariantType[];\n language: 'typescript' | 'python';\n}\n\nexport const DEFAULT_FEATURES: FeatureFlags = {\n typescript: true,\n eslint: true,\n prettier: true,\n tailwind: false,\n shadcn: false,\n testing: true,\n githubActions: false,\n docker: false,\n husky: false,\n envExample: false,\n};\n\nexport const DEFAULT_CONFIG: ProjectConfig = {\n name: '',\n type: 'frontend',\n framework: 'react',\n variant: 'base',\n features: { ...DEFAULT_FEATURES },\n packageManager: 'npm',\n gitInit: true,\n};\n","import { Command } from 'commander';\nimport chalk from 'chalk';\nimport { FRAMEWORKS, VARIANT_DISPLAY_NAMES } from '../constants.js';\nimport type { FrameworkType } from '../types/index.js';\nimport { newLine } from '../utils/logger.js';\n\nexport function listCommand(): Command {\n return new Command('list')\n .description('List all available templates')\n .action(() => {\n newLine();\n console.log(chalk.bold.cyan('Available Templates'));\n console.log(chalk.gray('─'.repeat(60)));\n newLine();\n\n const categories = {\n Frontend: ['react', 'nextjs', 'angular'] as FrameworkType[],\n Backend: ['express', 'fastapi'] as FrameworkType[],\n };\n\n for (const [category, frameworks] of Object.entries(categories)) {\n console.log(chalk.bold.white(` ${category}`));\n newLine();\n\n for (const fw of frameworks) {\n const meta = FRAMEWORKS[fw];\n console.log(` ${chalk.green(meta.displayName.padEnd(25))} ${chalk.gray(meta.description)}`);\n\n for (const variant of meta.variants) {\n const label = VARIANT_DISPLAY_NAMES[variant];\n console.log(` ${chalk.gray('•')} ${label}`);\n }\n newLine();\n }\n }\n\n console.log(chalk.gray('─'.repeat(60)));\n console.log(\n chalk.gray(' Use'),\n chalk.cyan('scaffold create <name> --<framework>'),\n chalk.gray('for quick setup'),\n );\n newLine();\n });\n}\n","import { Command } from 'commander';\nimport { execSync } from 'node:child_process';\nimport chalk from 'chalk';\nimport { newLine } from '../utils/logger.js';\n\ninterface Check {\n name: string;\n command: string;\n versionFlag?: string;\n required: boolean;\n}\n\nconst CHECKS: Check[] = [\n { name: 'Node.js', command: 'node', versionFlag: '--version', required: true },\n { name: 'npm', command: 'npm', versionFlag: '--version', required: false },\n { name: 'yarn', command: 'yarn', versionFlag: '--version', required: false },\n { name: 'pnpm', command: 'pnpm', versionFlag: '--version', required: false },\n { name: 'git', command: 'git', versionFlag: '--version', required: true },\n { name: 'Python', command: 'python3', versionFlag: '--version', required: false },\n];\n\nexport function doctorCommand(): Command {\n return new Command('doctor')\n .description('Check system dependencies')\n .action(() => {\n newLine();\n console.log(chalk.bold.cyan('System Check'));\n console.log(chalk.gray('─'.repeat(40)));\n newLine();\n\n let allGood = true;\n\n for (const check of CHECKS) {\n try {\n const version = execSync(`${check.command} ${check.versionFlag ?? '--version'}`, {\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n }).trim();\n\n const versionStr = version.split('\\n')[0];\n console.log(` ${chalk.green('✔')} ${check.name.padEnd(12)} ${chalk.gray(versionStr)}`);\n } catch {\n if (check.required) {\n console.log(` ${chalk.red('✖')} ${check.name.padEnd(12)} ${chalk.red('not found (required)')}`);\n allGood = false;\n } else {\n console.log(` ${chalk.yellow('–')} ${check.name.padEnd(12)} ${chalk.gray('not found (optional)')}`);\n }\n }\n }\n\n newLine();\n\n if (allGood) {\n console.log(chalk.green(' All required dependencies are installed!'));\n } else {\n console.log(chalk.red(' Some required dependencies are missing.'));\n }\n\n newLine();\n });\n}\n","import { createCli } from './cli.js';\n\nconst program = createCli();\nprogram.parse();\n"],"mappings":";;;;;;;;;AAAA,SAAS,WAAAA,gBAAe;;;ACAxB,SAAS,eAAe;AACxB,OAAOC,WAAU;AACjB,OAAOC,SAAQ;;;ACFf,OAAO,cAAc;AAGrB,eAAsB,oBAA0C;AAC9D,QAAM,EAAE,YAAY,IAAI,MAAM,SAAS,OAAO;AAAA,IAC5C;AAAA,MACE,MAAM;AAAA,MACN,MAAM;AAAA,MACN,SAAS;AAAA,MACT,SAAS;AAAA,QACP,EAAE,MAAM,sCAAsC,OAAO,WAAW;AAAA,QAChE,EAAE,MAAM,8BAA8B,OAAO,UAAU;AAAA,QACvD,EAAE,MAAM,mCAAmC,OAAO,YAAY;AAAA,MAChE;AAAA,IACF;AAAA,EACF,CAAC;AAED,SAAO;AACT;AAEA,eAAsB,gBAAgB,aAAkD;AACtF,MAAI,gBAAgB,YAAY;AAC9B,UAAM,EAAE,WAAAC,WAAU,IAAI,MAAM,SAAS,OAAO;AAAA,MAC1C;AAAA,QACE,MAAM;AAAA,QACN,MAAM;AAAA,QACN,SAAS;AAAA,QACT,SAAS;AAAA,UACP,EAAE,MAAM,gBAAgB,OAAO,QAAQ;AAAA,UACvC,EAAE,MAAM,wBAAwB,OAAO,SAAS;AAAA,UAChD,EAAE,MAAM,cAAc,OAAO,UAAU;AAAA,QACzC;AAAA,MACF;AAAA,IACF,CAAC;AACD,WAAOA;AAAA,EACT;AAEA,MAAI,gBAAgB,WAAW;AAC7B,UAAM,EAAE,WAAAA,WAAU,IAAI,MAAM,SAAS,OAAO;AAAA,MAC1C;AAAA,QACE,MAAM;AAAA,QACN,MAAM;AAAA,QACN,SAAS;AAAA,QACT,SAAS;AAAA,UACP,EAAE,MAAM,cAAc,OAAO,UAAU;AAAA,UACvC,EAAE,MAAM,oBAAoB,OAAO,UAAU;AAAA,QAC/C;AAAA,MACF;AAAA,IACF,CAAC;AACD,WAAOA;AAAA,EACT;AAGA,QAAM,EAAE,UAAU,IAAI,MAAM,SAAS,OAAO;AAAA,IAC1C;AAAA,MACE,MAAM;AAAA,MACN,MAAM;AAAA,MACN,SAAS;AAAA,MACT,SAAS;AAAA,QACP,EAAE,MAAM,gBAAgB,OAAO,QAAQ;AAAA,QACvC,EAAE,MAAM,WAAW,OAAO,SAAS;AAAA,QACnC,EAAE,MAAM,cAAc,OAAO,UAAU;AAAA,MACzC;AAAA,IACF;AAAA,EACF,CAAC;AACD,SAAO;AACT;;;AClEA,OAAOC,eAAc;AAUrB,eAAsB,eACpB,aACA,WACuB;AACvB,QAAM,WAAW,cAAc;AAE/B,QAAM,UAA2B;AAAA,IAC/B;AAAA,MACE,MAAM;AAAA,MACN,OAAO;AAAA,MACP,SAAS;AAAA,MACT,UAAU,WAAW,mBAAmB;AAAA,IAC1C;AAAA,IACA,EAAE,MAAM,qBAAqB,OAAO,UAAU,SAAS,CAAC,UAAU,UAAU,WAAW,mBAAmB,MAAM;AAAA,IAChH,EAAE,MAAM,gBAAgB,OAAO,YAAY,SAAS,MAAM;AAAA,IAC1D,EAAE,MAAM,wBAAwB,OAAO,UAAU,SAAS,MAAM;AAAA,IAChE,EAAE,MAAM,WAAW,mBAAmB,kBAAkB,OAAO,WAAW,SAAS,KAAK;AAAA,IACxF,EAAE,MAAM,wBAAwB,OAAO,iBAAiB,SAAS,MAAM;AAAA,IACvE,EAAE,MAAM,gBAAgB,OAAO,UAAU,SAAS,MAAM;AAAA,IACxD,EAAE,MAAM,0BAA0B,OAAO,SAAS,SAAS,OAAO,UAAU,WAAW,mBAAmB,MAAM;AAAA,IAChH,EAAE,MAAM,qBAAqB,OAAO,cAAc,SAAS,MAAM;AAAA,EACnE;AAGA,QAAM,kBACJ,gBAAgB,YACZ,QAAQ,OAAO,CAAC,MAAM,CAAC,CAAC,YAAY,QAAQ,EAAE,SAAS,EAAE,KAAK,CAAC,IAC/D;AAEN,QAAM,EAAE,SAAS,IAAI,MAAMA,UAAS,OAAO;AAAA,IACzC;AAAA,MACE,MAAM;AAAA,MACN,MAAM;AAAA,MACN,SAAS;AAAA,MACT,SAAS;AAAA,IACX;AAAA,EACF,CAAC;AAED,QAAM,mBAAmB;AAEzB,SAAO;AAAA,IACL,YAAY,CAAC,YAAY,iBAAiB,SAAS,YAAY;AAAA,IAC/D,QAAQ,CAAC,YAAY,iBAAiB,SAAS,QAAQ;AAAA,IACvD,UAAU,CAAC,YAAY,iBAAiB,SAAS,QAAQ;AAAA,IACzD,UAAU,iBAAiB,SAAS,UAAU;AAAA,IAC9C,QAAQ,iBAAiB,SAAS,QAAQ;AAAA,IAC1C,SAAS,iBAAiB,SAAS,SAAS;AAAA,IAC5C,eAAe,iBAAiB,SAAS,eAAe;AAAA,IACxD,QAAQ,iBAAiB,SAAS,QAAQ;AAAA,IAC1C,OAAO,CAAC,YAAY,iBAAiB,SAAS,OAAO;AAAA,IACrD,YAAY,iBAAiB,SAAS,YAAY;AAAA,EACpD;AACF;;;AC9DA,OAAOC,eAAc;;;ACEd,IAAM,aAAmD;AAAA,EAC9D,OAAO;AAAA,IACL,MAAM;AAAA,IACN,aAAa;AAAA,IACb,aAAa;AAAA,IACb,MAAM;AAAA,IACN,UAAU,CAAC,QAAQ,iBAAiB,aAAa;AAAA,IACjD,UAAU;AAAA,EACZ;AAAA,EACA,QAAQ;AAAA,IACN,MAAM;AAAA,IACN,aAAa;AAAA,IACb,aAAa;AAAA,IACb,MAAM;AAAA,IACN,UAAU,CAAC,QAAQ,aAAa,aAAa;AAAA,IAC7C,UAAU;AAAA,EACZ;AAAA,EACA,SAAS;AAAA,IACP,MAAM;AAAA,IACN,aAAa;AAAA,IACb,aAAa;AAAA,IACb,MAAM;AAAA,IACN,UAAU,CAAC,MAAM;AAAA,IACjB,UAAU;AAAA,EACZ;AAAA,EACA,SAAS;AAAA,IACP,MAAM;AAAA,IACN,aAAa;AAAA,IACb,aAAa;AAAA,IACb,MAAM;AAAA,IACN,UAAU,CAAC,QAAQ,aAAa;AAAA,IAChC,UAAU;AAAA,EACZ;AAAA,EACA,SAAS;AAAA,IACP,MAAM;AAAA,IACN,aAAa;AAAA,IACb,aAAa;AAAA,IACb,MAAM;AAAA,IACN,UAAU,CAAC,MAAM;AAAA,IACjB,UAAU;AAAA,EACZ;AACF;AAKO,IAAM,wBAAqD;AAAA,EAChE,MAAM;AAAA,EACN,iBAAiB;AAAA,EACjB,eAAe;AAAA,EACf,aAAa;AAAA,EACb,eAAe;AACjB;;;ADlDA,eAAsB,cAAc,WAAgD;AAClF,QAAM,OAAO,WAAW,SAAS;AAEjC,MAAI,KAAK,SAAS,UAAU,GAAG;AAC7B,WAAO;AAAA,EACT;AAEA,QAAM,EAAE,QAAQ,IAAI,MAAMC,UAAS,OAAO;AAAA,IACxC;AAAA,MACE,MAAM;AAAA,MACN,MAAM;AAAA,MACN,SAAS;AAAA,MACT,SAAS,KAAK,SAAS,IAAI,CAAC,OAAO;AAAA,QACjC,MAAM,sBAAsB,CAAC;AAAA,QAC7B,OAAO;AAAA,MACT,EAAE;AAAA,IACJ;AAAA,EACF,CAAC;AAED,SAAO;AACT;AAEA,eAAsB,uBAAgD;AACpE,QAAM,EAAE,eAAe,IAAI,MAAMA,UAAS,OAAO;AAAA,IAC/C;AAAA,MACE,MAAM;AAAA,MACN,MAAM;AAAA,MACN,SAAS;AAAA,MACT,SAAS;AAAA,QACP,EAAE,MAAM,OAAO,OAAO,MAAM;AAAA,QAC5B,EAAE,MAAM,QAAQ,OAAO,OAAO;AAAA,QAC9B,EAAE,MAAM,QAAQ,OAAO,OAAO;AAAA,MAChC;AAAA,IACF;AAAA,EACF,CAAC;AAED,SAAO;AACT;AAEA,eAAsB,gBAAkC;AACtD,QAAM,EAAE,QAAQ,IAAI,MAAMA,UAAS,OAAO;AAAA,IACxC;AAAA,MACE,MAAM;AAAA,MACN,MAAM;AAAA,MACN,SAAS;AAAA,MACT,SAAS;AAAA,IACX;AAAA,EACF,CAAC;AAED,SAAO;AACT;;;AEjDA,eAAsB,WAAW,aAA6C;AAC5E,QAAM,OAAO,MAAM,kBAAkB;AACrC,QAAM,YAAY,MAAM,gBAAgB,IAAI;AAC5C,QAAM,UAAU,MAAM,cAAc,SAAS;AAC7C,QAAM,WAAW,MAAM,eAAe,MAAM,SAAS;AAErD,QAAM,WAAW,cAAc;AAC/B,QAAM,iBAAiB,WAAW,QAAQ,MAAM,qBAAqB;AACrE,QAAM,UAAU,MAAM,cAAc;AAEpC,SAAO;AAAA,IACL,MAAM;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;ACxBA,OAAOC,WAAU;;;ACAjB,OAAO,UAAU;AACjB,OAAO,QAAQ;AACf,SAAS,gBAAgB;;;ACFzB,OAAO,WAAW;AAClB,OAAO,SAAuB;AAE9B,IAAI,UAAU;AAEP,SAAS,WAAW,OAAsB;AAC/C,YAAU;AACZ;AAMO,SAAS,QAAQ,SAAuB;AAC7C,UAAQ,IAAI,MAAM,MAAM,QAAG,GAAG,OAAO;AACvC;AAMO,SAAS,MAAM,SAAuB;AAC3C,UAAQ,IAAI,MAAM,IAAI,QAAG,GAAG,OAAO;AACrC;AAEO,SAAS,MAAM,SAAuB;AAC3C,MAAI,SAAS;AACX,YAAQ,IAAI,MAAM,KAAK,QAAG,GAAG,MAAM,KAAK,OAAO,CAAC;AAAA,EAClD;AACF;AAEO,SAAS,QAAQ,MAAmB;AACzC,SAAO,IAAI,EAAE,MAAM,OAAO,OAAO,CAAC;AACpC;AAEO,SAAS,UAAgB;AAC9B,UAAQ,IAAI;AACd;AAEO,SAAS,OAAO,MAAoB;AACzC,UAAQ,IAAI,MAAM,KAAK,KAAK,IAAI,CAAC;AACnC;;;ACvCA,IAAM,qBAAqB;AAEpB,SAAS,oBAAoB,MAA6B;AAC/D,MAAI,CAAC,QAAQ,KAAK,KAAK,EAAE,WAAW,GAAG;AACrC,WAAO;AAAA,EACT;AAEA,MAAI,CAAC,mBAAmB,KAAK,IAAI,GAAG;AAClC,WAAO;AAAA,EACT;AAEA,MAAI,KAAK,SAAS,KAAK;AACrB,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAEA,eAAsB,kBAAkB,SAAyC;AAC/E,MAAI,MAAM,gBAAgB,OAAO,GAAG;AAClC,WAAO,cAAc,OAAO;AAAA,EAC9B;AACA,SAAO;AACT;;;AFlBO,IAAe,gBAAf,MAA6B;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA,SAA0B,EAAE,cAAc,CAAC,GAAG,UAAU,CAAC,EAAE;AAAA,EAErE,YAAY,QAAuB,WAAmB;AACpD,SAAK,SAAS;AACd,SAAK,YAAY;AACjB,SAAK,eAAe,gBAAgB;AAAA,EACtC;AAAA,EAEA,MAAM,WAAqC;AACzC,UAAM,KAAK,iBAAiB;AAC5B,UAAM,KAAK,aAAa;AACxB,UAAM,KAAK,aAAa;AACxB,UAAM,KAAK,mBAAmB;AAC9B,UAAM,KAAK,cAAc;AACzB,UAAM,KAAK,QAAQ;AACnB,WAAO,KAAK;AAAA,EACd;AAAA,EAIA,MAAgB,eAA8B;AAC5C,QAAI,KAAK,OAAO,YAAY,OAAQ;AAEpC,UAAM,aAAa,KAAK,sBAAsB;AAC9C,QAAI,MAAM,GAAG,WAAW,UAAU,GAAG;AACnC,YAAM,IAAI,QAAQ,YAAY,KAAK,OAAO,OAAO,UAAU;AAC3D,QAAE,MAAM;AACR,YAAM,KAAK,gBAAgB,YAAY,KAAK,SAAS;AACrD,QAAE,KAAK;AACP,cAAQ,WAAW,KAAK,OAAO,OAAO,UAAU;AAAA,IAClD;AAAA,EACF;AAAA,EAEA,MAAgB,qBAAoC;AAClD,UAAM,YAAY,KAAK,KAAK,KAAK,cAAc,QAAQ;AAEvD,QAAI,KAAK,OAAO,SAAS,QAAQ;AAC/B,YAAM,IAAI,QAAQ,8BAA8B;AAChD,QAAE,MAAM;AACR,YAAM,KAAK;AAAA,QACT,KAAK,KAAK,WAAW,sBAAsB;AAAA,QAC3C,KAAK,KAAK,KAAK,WAAW,kBAAkB;AAAA,MAC9C;AACA,YAAM,KAAK;AAAA,QACT,KAAK,KAAK,WAAW,wBAAwB;AAAA,QAC7C,KAAK,KAAK,KAAK,WAAW,aAAa;AAAA,MACzC;AACA,QAAE,KAAK;AACP,cAAQ,8BAA8B;AAAA,IACxC;AAGA,UAAM,KAAK;AAAA,MACT,KAAK,KAAK,WAAW,eAAe;AAAA,MACpC,KAAK,KAAK,KAAK,WAAW,YAAY;AAAA,IACxC;AAGA,UAAM,KAAK,QAAQ,sBAAsB;AACzC,OAAG,MAAM;AACT,UAAM,KAAK;AAAA,MACT,KAAK,KAAK,WAAW,eAAe;AAAA,MACpC,KAAK,KAAK,KAAK,WAAW,WAAW;AAAA,IACvC;AACA,OAAG,KAAK;AACR,YAAQ,sBAAsB;AAG9B,UAAM,KAAK;AAAA,MACT,KAAK,KAAK,WAAW,aAAa;AAAA,MAClC,KAAK,KAAK,KAAK,WAAW,SAAS;AAAA,IACrC;AAAA,EACF;AAAA,EAEA,MAAgB,gBAA+B;AAC7C,UAAM,YAAY,KAAK,KAAK,KAAK,cAAc,QAAQ;AAEvD,QAAI,KAAK,OAAO,SAAS,eAAe;AACtC,YAAM,IAAI,QAAQ,kCAAkC;AACpD,QAAE,MAAM;AACR,YAAM,KAAK;AAAA,QACT,KAAK,KAAK,WAAW,mBAAmB;AAAA,QACxC,KAAK,KAAK,KAAK,WAAW,WAAW,aAAa,QAAQ;AAAA,MAC5D;AACA,QAAE,KAAK;AACP,cAAQ,kCAAkC;AAAA,IAC5C;AAEA,QAAI,KAAK,OAAO,SAAS,QAAQ;AAC/B,YAAM,IAAI,QAAQ,6BAA6B;AAC/C,QAAE,MAAM;AACR,YAAM,KAAK;AAAA,QACT,KAAK,KAAK,WAAW,UAAU,gBAAgB;AAAA,QAC/C,KAAK,KAAK,KAAK,WAAW,YAAY;AAAA,MACxC;AACA,YAAM,KAAK;AAAA,QACT,KAAK,KAAK,WAAW,UAAU,wBAAwB;AAAA,QACvD,KAAK,KAAK,KAAK,WAAW,oBAAoB;AAAA,MAChD;AACA,QAAE,KAAK;AACP,cAAQ,6BAA6B;AAAA,IACvC;AAAA,EACF;AAAA,EAEA,MAAgB,mBAAkC;AAChD,UAAM,IAAI,QAAQ,4BAA4B;AAC9C,MAAE,MAAM;AACR,UAAM,UAAU,KAAK,SAAS;AAC9B,MAAE,KAAK;AACP,YAAQ,4BAA4B;AAAA,EACtC;AAAA,EAEA,MAAgB,UAAyB;AACvC,QAAI,CAAC,KAAK,OAAO,QAAS;AAE1B,UAAM,IAAI,QAAQ,6BAA6B;AAC/C,MAAE,MAAM;AACR,QAAI;AACF,eAAS,YAAY,EAAE,KAAK,KAAK,WAAW,OAAO,OAAO,CAAC;AAC3D,eAAS,cAAc,EAAE,KAAK,KAAK,WAAW,OAAO,OAAO,CAAC;AAC7D,eAAS,gDAAgD;AAAA,QACvD,KAAK,KAAK;AAAA,QACV,OAAO;AAAA,MACT,CAAC;AACD,QAAE,KAAK;AACP,cAAQ,6BAA6B;AAAA,IACvC,QAAQ;AACN,QAAE,KAAK;AACP,YAAM,gDAAgD;AAAA,IACxD;AAAA,EACF;AAAA,EAEA,MAAgB,mBACd,cACA,YACe;AACf,UAAM,eAAe,KAAK,gBAAgB;AAE1C,QAAI,MAAM,GAAG,WAAW,YAAY,GAAG;AACrC,YAAM,eAAe,cAAc,YAAY,YAAY;AAC3D,WAAK,OAAO,aAAa,KAAK,UAAU;AAAA,IAC1C,OAAO;AACL,YAAM,uBAAuB,YAAY,EAAE;AAAA,IAC7C;AAAA,EACF;AAAA,EAEA,MAAgB,gBAAgB,QAAgB,SAAgC;AAC9E,UAAM,UAAU,MAAM,GAAG,QAAQ,QAAQ,EAAE,eAAe,KAAK,CAAC;AAEhE,eAAW,SAAS,SAAS;AAC3B,YAAM,UAAU,KAAK,KAAK,QAAQ,MAAM,IAAI;AAC5C,YAAM,WAAW,MAAM,KAAK,QAAQ,UAAU,EAAE;AAChD,YAAM,WAAW,KAAK,KAAK,SAAS,QAAQ;AAE5C,UAAI,MAAM,YAAY,GAAG;AACvB,cAAM,KAAK,gBAAgB,SAAS,QAAQ;AAAA,MAC9C,WAAW,MAAM,KAAK,SAAS,MAAM,GAAG;AACtC,cAAM,KAAK,mBAAmB,SAAS,QAAQ;AAAA,MACjD,OAAO;AACL,cAAM,GAAG,UAAU,KAAK,QAAQ,QAAQ,CAAC;AACzC,cAAM,GAAG,KAAK,SAAS,QAAQ;AAC/B,aAAK,OAAO,aAAa,KAAK,QAAQ;AAAA,MACxC;AAAA,IACF;AAAA,EACF;AAAA,EAEU,kBAA0B;AAClC,WAAO;AAAA,MACL,GAAG,KAAK;AAAA,MACR,OAAM,oBAAI,KAAK,GAAE,YAAY;AAAA,IAC/B;AAAA,EACF;AAAA,EAEU,qBAA6B;AACrC,WAAO,KAAK,KAAK,KAAK,cAAc,KAAK,OAAO,WAAW,MAAM;AAAA,EACnE;AAAA,EAEU,wBAAgC;AACxC,WAAO,KAAK,KAAK,KAAK,cAAc,KAAK,OAAO,WAAW,KAAK,OAAO,OAAO;AAAA,EAChF;AACF;;;AD3LO,IAAM,iBAAN,cAA6B,cAAc;AAAA,EAChD,MAAgB,eAA8B;AAC5C,UAAM,UAAU,KAAK,mBAAmB;AAExC,UAAM,IAAI,QAAQ,uCAAuC;AACzD,MAAE,MAAM;AACR,UAAM,KAAK,gBAAgB,SAAS,KAAK,SAAS;AAClD,MAAE,KAAK;AACP,YAAQ,uCAAuC;AAE/C,QAAI,KAAK,OAAO,SAAS,SAAS;AAChC,cAAQ,oBAAoB;AAAA,IAC9B;AAAA,EACF;AAAA,EAEQ,eAAe,SAAyB;AAC9C,WAAOC,MAAK,KAAK,KAAK,cAAc,SAAS,OAAO;AAAA,EACtD;AACF;;;AInBO,IAAM,kBAAN,cAA8B,cAAc;AAAA,EACjD,MAAgB,eAA8B;AAC5C,UAAM,UAAU,KAAK,mBAAmB;AAExC,UAAM,IAAI,QAAQ,+CAA+C;AACjE,MAAE,MAAM;AACR,UAAM,KAAK,gBAAgB,SAAS,KAAK,SAAS;AAClD,MAAE,KAAK;AACP,YAAQ,+CAA+C;AAEvD,QAAI,KAAK,OAAO,SAAS,SAAS;AAChC,cAAQ,oBAAoB;AAAA,IAC9B;AAAA,EACF;AACF;;;ACdO,IAAM,mBAAN,cAA+B,cAAc;AAAA,EAClD,MAAgB,eAA8B;AAC5C,UAAM,UAAU,KAAK,mBAAmB;AAExC,UAAM,IAAI,QAAQ,qCAAqC;AACvD,MAAE,MAAM;AACR,UAAM,KAAK,gBAAgB,SAAS,KAAK,SAAS;AAClD,MAAE,KAAK;AACP,YAAQ,qCAAqC;AAAA,EAC/C;AACF;;;ACVO,IAAM,mBAAN,cAA+B,cAAc;AAAA,EAClD,MAAgB,eAA8B;AAC5C,UAAM,UAAU,KAAK,mBAAmB;AAExC,UAAM,IAAI,QAAQ,oCAAoC;AACtD,MAAE,MAAM;AACR,UAAM,KAAK,gBAAgB,SAAS,KAAK,SAAS;AAClD,MAAE,KAAK;AACP,YAAQ,oCAAoC;AAE5C,QAAI,KAAK,OAAO,SAAS,SAAS;AAChC,cAAQ,oBAAoB;AAAA,IAC9B;AAAA,EACF;AACF;;;ACdO,IAAM,mBAAN,cAA+B,cAAc;AAAA,EAClD,MAAgB,eAA8B;AAC5C,UAAM,UAAU,KAAK,mBAAmB;AAExC,UAAM,IAAI,QAAQ,gCAAgC;AAClD,MAAE,MAAM;AACR,UAAM,KAAK,gBAAgB,SAAS,KAAK,SAAS;AAClD,MAAE,KAAK;AACP,YAAQ,gCAAgC;AAExC,QAAI,KAAK,OAAO,SAAS,SAAS;AAChC,cAAQ,oBAAoB;AAAA,IAC9B;AAAA,EACF;AAAA,EAEA,MAAyB,qBAAoC;AAE3D,UAAMC,QAAO,MAAM,OAAO,MAAW;AACrC,UAAM,YAAYA,MAAK,KAAK,KAAK,cAAc,QAAQ;AAGvD,UAAM,KAAK;AAAA,MACTA,MAAK,KAAK,WAAW,eAAe;AAAA,MACpCA,MAAK,KAAK,KAAK,WAAW,YAAY;AAAA,IACxC;AAEA,UAAM,IAAI,QAAQ,sBAAsB;AACxC,MAAE,MAAM;AACR,UAAM,KAAK;AAAA,MACTA,MAAK,KAAK,WAAW,eAAe;AAAA,MACpCA,MAAK,KAAK,KAAK,WAAW,WAAW;AAAA,IACvC;AACA,MAAE,KAAK;AACP,YAAQ,sBAAsB;AAE9B,UAAM,KAAK;AAAA,MACTA,MAAK,KAAK,WAAW,aAAa;AAAA,MAClCA,MAAK,KAAK,KAAK,WAAW,SAAS;AAAA,IACrC;AAAA,EACF;AACF;;;AC3CA,OAAOC,WAAU;AAUV,IAAM,qBAAN,cAAiC,cAAc;AAAA,EACpD,MAAgB,eAA8B;AAC5C,UAAM,IAAI,QAAQ,gCAAgC;AAClD,MAAE,MAAM;AAGR,UAAM,SAASC,MAAK,KAAK,KAAK,WAAW,QAAQ,KAAK;AACtD,UAAM,SAASA,MAAK,KAAK,KAAK,WAAW,QAAQ,KAAK;AACtD,UAAM,UAAU,MAAM;AACtB,UAAM,UAAU,MAAM;AAEtB,MAAE,KAAK;AACP,YAAQ,gCAAgC;AAGxC,UAAM,iBAAgC;AAAA,MACpC,GAAG,KAAK;AAAA,MACR,MAAM;AAAA,MACN,SAAS;AAAA,IACX;AAEA,UAAM,oBAAoB,KAAK,0BAA0B;AACzD,UAAM,cAAc,IAAI,kBAAkB,gBAAgB,MAAM;AAChE,UAAM,YAAY,aAAa;AAG/B,UAAM,gBAA+B;AAAA,MACnC,GAAG,KAAK;AAAA,MACR,MAAM;AAAA,MACN,WAAW;AAAA,MACX,SAAS;AAAA,IACX;AAEA,UAAM,aAAa,IAAI,iBAAiB,eAAe,MAAM;AAC7D,UAAM,WAAW,aAAa;AAG9B,UAAM,cAAcA,MAAK,KAAK,KAAK,WAAW,cAAc;AAC5D,UAAM,UAAU;AAAA,MACd,MAAM,KAAK,OAAO;AAAA,MAClB,SAAS;AAAA,MACT,YAAY,CAAC,QAAQ;AAAA,MACrB,SAAS;AAAA,QACP,KAAK;AAAA,QACL,OAAO;AAAA,QACP,MAAM;AAAA,QACN,MAAM;AAAA,MACR;AAAA,IACF;AACA,UAAM,EAAE,WAAAC,WAAU,IAAI,MAAM,OAAO,oBAAkB;AACrD,UAAMA,WAAU,aAAa,KAAK,UAAU,SAAS,MAAM,CAAC,IAAI,IAAI;AAAA,EACtE;AAAA,EAEQ,4BAA4B;AAClC,YAAQ,KAAK,OAAO,WAAW;AAAA,MAC7B,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AAAA,MACL;AACE,eAAO;AAAA,IACX;AAAA,EACF;AACF;;;ACjEO,SAAS,gBAAgB,QAAuB,WAAkC;AACvF,MAAI,OAAO,SAAS,aAAa;AAC/B,WAAO,IAAI,mBAAmB,QAAQ,SAAS;AAAA,EACjD;AAEA,UAAQ,OAAO,WAAW;AAAA,IACxB,KAAK;AACH,aAAO,IAAI,eAAe,QAAQ,SAAS;AAAA,IAC7C,KAAK;AACH,aAAO,IAAI,gBAAgB,QAAQ,SAAS;AAAA,IAC9C,KAAK;AACH,aAAO,IAAI,iBAAiB,QAAQ,SAAS;AAAA,IAC/C,KAAK;AACH,aAAO,IAAI,iBAAiB,QAAQ,SAAS;AAAA,IAC/C,KAAK;AACH,aAAO,IAAI,iBAAiB,QAAQ,SAAS;AAAA,IAC/C;AACE,YAAM,IAAI,MAAM,sBAAsB,OAAO,SAAS,EAAE;AAAA,EAC5D;AACF;;;ACiBO,IAAM,mBAAiC;AAAA,EAC5C,YAAY;AAAA,EACZ,QAAQ;AAAA,EACR,UAAU;AAAA,EACV,UAAU;AAAA,EACV,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,eAAe;AAAA,EACf,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,YAAY;AACd;AAEO,IAAM,iBAAgC;AAAA,EAC3C,MAAM;AAAA,EACN,MAAM;AAAA,EACN,WAAW;AAAA,EACX,SAAS;AAAA,EACT,UAAU,EAAE,GAAG,iBAAiB;AAAA,EAChC,gBAAgB;AAAA,EAChB,SAAS;AACX;;;AhB9CO,SAAS,gBAAyB;AACvC,QAAM,MAAM,IAAI,QAAQ,QAAQ,EAC7B,YAAY,sBAAsB,EAClC,SAAS,kBAAkB,qBAAqB,EAChD,OAAO,WAAW,+BAA+B,EACjD,OAAO,YAAY,0BAA0B,EAC7C,OAAO,aAAa,2BAA2B,EAC/C,OAAO,aAAa,8BAA8B,EAClD,OAAO,aAAa,0BAA0B,EAC9C,OAAO,aAAa,+BAA+B,EACnD,OAAO,iBAAiB,2BAA2B,EACnD,OAAO,WAAW,8BAA8B,EAChD,OAAO,OAAO,aAAqB,YAA2B;AAC7D,QAAI;AACF,YAAM,aAAa,aAAa,OAAO;AAAA,IACzC,SAAS,KAAK;AACZ,YAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AACtD,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF,CAAC;AAEH,SAAO;AACT;AAEA,eAAe,aAAa,aAAqB,SAAuC;AACtF,QAAM,iBAAiB,oBAAoB,WAAW;AACtD,MAAI,mBAAmB,MAAM;AAC3B,UAAM,IAAI,MAAM,cAAc;AAAA,EAChC;AAEA,QAAM,YAAYC,MAAK,QAAQ,QAAQ,IAAI,GAAG,WAAW;AAEzD,MAAI,CAAC,QAAQ,OAAO;AAClB,UAAM,gBAAgB,MAAM,kBAAkB,SAAS;AACvD,QAAI,kBAAkB,MAAM;AAC1B,YAAM,IAAI,MAAM,aAAa;AAAA,IAC/B;AAAA,EACF;AAEA,MAAI;AAEJ,MAAI,QAAQ,MAAM;AAChB,aAAS,MAAM,mBAAmB,QAAQ,MAAM,WAAW;AAAA,EAC7D,WAAW,QAAQ,OAAO,iBAAiB,OAAO,GAAG;AACnD,aAAS,iBAAiB,aAAa,OAAO;AAAA,EAChD,OAAO;AACL,aAAS,MAAM,WAAW,WAAW;AAAA,EACvC;AAEA,UAAQ;AACR,SAAO,qBAAqB,OAAO,IAAI,MAAM;AAC7C,UAAQ;AAER,QAAM,YAAY,gBAAgB,QAAQ,SAAS;AACnD,QAAM,UAAU,SAAS;AAEzB,UAAQ;AACR,UAAQ,YAAY,OAAO,IAAI,mCAA4B;AAC3D,UAAQ;AACR,UAAQ,IAAI,aAAa;AACzB,UAAQ,IAAI,QAAQ,OAAO,IAAI,EAAE;AAEjC,MAAI,OAAO,cAAc,WAAW;AAClC,YAAQ,IAAI,mCAAmC;AAC/C,YAAQ,IAAI,iCAAiC;AAAA,EAC/C,OAAO;AACL,YAAQ,IAAI,KAAK,OAAO,cAAc,UAAU;AAChD,YAAQ,IAAI,KAAK,OAAO,cAAc,UAAU;AAAA,EAClD;AAEA,UAAQ;AACR,UAAQ,IAAI,yBAAkB;AAC9B,UAAQ;AACV;AAEA,SAAS,iBAAiB,SAAiC;AACzD,SAAO,CAAC,EAAE,QAAQ,SAAS,QAAQ,UAAU,QAAQ,WAAW,QAAQ,WAAW,QAAQ;AAC7F;AAEA,SAAS,iBAAiB,aAAqB,SAAuC;AACpF,QAAM,SAAwB,EAAE,GAAG,gBAAgB,MAAM,YAAY;AAErE,MAAI,QAAQ,OAAO;AACjB,WAAO,OAAO;AACd,WAAO,YAAY;AAAA,EACrB,WAAW,QAAQ,QAAQ;AACzB,WAAO,OAAO;AACd,WAAO,YAAY;AAAA,EACrB,WAAW,QAAQ,SAAS;AAC1B,WAAO,OAAO;AACd,WAAO,YAAY;AAAA,EACrB,WAAW,QAAQ,SAAS;AAC1B,WAAO,OAAO;AACd,WAAO,YAAY;AAAA,EACrB,WAAW,QAAQ,SAAS;AAC1B,WAAO,OAAO;AACd,WAAO,YAAY;AAAA,EACrB;AAEA,SAAO;AACT;AAEA,eAAe,mBAAmB,YAAoB,aAA6C;AACjG,QAAM,eAAeA,MAAK,QAAQ,QAAQ,IAAI,GAAG,UAAU;AAC3D,QAAM,UAAU,MAAMC,IAAG,SAAS,YAAY;AAC9C,SAAO,EAAE,GAAG,gBAAgB,GAAG,SAAS,MAAM,YAAY;AAC5D;;;AiB9HA,SAAS,WAAAC,gBAAe;AACxB,OAAOC,YAAW;AAKX,SAAS,cAAuB;AACrC,SAAO,IAAIC,SAAQ,MAAM,EACtB,YAAY,8BAA8B,EAC1C,OAAO,MAAM;AACZ,YAAQ;AACR,YAAQ,IAAIC,OAAM,KAAK,KAAK,qBAAqB,CAAC;AAClD,YAAQ,IAAIA,OAAM,KAAK,SAAI,OAAO,EAAE,CAAC,CAAC;AACtC,YAAQ;AAER,UAAM,aAAa;AAAA,MACjB,UAAU,CAAC,SAAS,UAAU,SAAS;AAAA,MACvC,SAAS,CAAC,WAAW,SAAS;AAAA,IAChC;AAEA,eAAW,CAAC,UAAU,UAAU,KAAK,OAAO,QAAQ,UAAU,GAAG;AAC/D,cAAQ,IAAIA,OAAM,KAAK,MAAM,KAAK,QAAQ,EAAE,CAAC;AAC7C,cAAQ;AAER,iBAAW,MAAM,YAAY;AAC3B,cAAM,OAAO,WAAW,EAAE;AAC1B,gBAAQ,IAAI,KAAKA,OAAM,MAAM,KAAK,YAAY,OAAO,EAAE,CAAC,CAAC,IAAIA,OAAM,KAAK,KAAK,WAAW,CAAC,EAAE;AAE3F,mBAAW,WAAW,KAAK,UAAU;AACnC,gBAAM,QAAQ,sBAAsB,OAAO;AAC3C,kBAAQ,IAAI,OAAOA,OAAM,KAAK,QAAG,CAAC,IAAI,KAAK,EAAE;AAAA,QAC/C;AACA,gBAAQ;AAAA,MACV;AAAA,IACF;AAEA,YAAQ,IAAIA,OAAM,KAAK,SAAI,OAAO,EAAE,CAAC,CAAC;AACtC,YAAQ;AAAA,MACNA,OAAM,KAAK,OAAO;AAAA,MAClBA,OAAM,KAAK,sCAAsC;AAAA,MACjDA,OAAM,KAAK,iBAAiB;AAAA,IAC9B;AACA,YAAQ;AAAA,EACV,CAAC;AACL;;;AC5CA,SAAS,WAAAC,gBAAe;AACxB,SAAS,YAAAC,iBAAgB;AACzB,OAAOC,YAAW;AAUlB,IAAM,SAAkB;AAAA,EACtB,EAAE,MAAM,WAAW,SAAS,QAAQ,aAAa,aAAa,UAAU,KAAK;AAAA,EAC7E,EAAE,MAAM,OAAO,SAAS,OAAO,aAAa,aAAa,UAAU,MAAM;AAAA,EACzE,EAAE,MAAM,QAAQ,SAAS,QAAQ,aAAa,aAAa,UAAU,MAAM;AAAA,EAC3E,EAAE,MAAM,QAAQ,SAAS,QAAQ,aAAa,aAAa,UAAU,MAAM;AAAA,EAC3E,EAAE,MAAM,OAAO,SAAS,OAAO,aAAa,aAAa,UAAU,KAAK;AAAA,EACxE,EAAE,MAAM,UAAU,SAAS,WAAW,aAAa,aAAa,UAAU,MAAM;AAClF;AAEO,SAAS,gBAAyB;AACvC,SAAO,IAAIC,SAAQ,QAAQ,EACxB,YAAY,2BAA2B,EACvC,OAAO,MAAM;AACZ,YAAQ;AACR,YAAQ,IAAIC,OAAM,KAAK,KAAK,cAAc,CAAC;AAC3C,YAAQ,IAAIA,OAAM,KAAK,SAAI,OAAO,EAAE,CAAC,CAAC;AACtC,YAAQ;AAER,QAAI,UAAU;AAEd,eAAW,SAAS,QAAQ;AAC1B,UAAI;AACF,cAAM,UAAUC,UAAS,GAAG,MAAM,OAAO,IAAI,MAAM,eAAe,WAAW,IAAI;AAAA,UAC/E,UAAU;AAAA,UACV,OAAO,CAAC,QAAQ,QAAQ,MAAM;AAAA,QAChC,CAAC,EAAE,KAAK;AAER,cAAM,aAAa,QAAQ,MAAM,IAAI,EAAE,CAAC;AACxC,gBAAQ,IAAI,KAAKD,OAAM,MAAM,QAAG,CAAC,IAAI,MAAM,KAAK,OAAO,EAAE,CAAC,IAAIA,OAAM,KAAK,UAAU,CAAC,EAAE;AAAA,MACxF,QAAQ;AACN,YAAI,MAAM,UAAU;AAClB,kBAAQ,IAAI,KAAKA,OAAM,IAAI,QAAG,CAAC,IAAI,MAAM,KAAK,OAAO,EAAE,CAAC,IAAIA,OAAM,IAAI,sBAAsB,CAAC,EAAE;AAC/F,oBAAU;AAAA,QACZ,OAAO;AACL,kBAAQ,IAAI,KAAKA,OAAM,OAAO,QAAG,CAAC,IAAI,MAAM,KAAK,OAAO,EAAE,CAAC,IAAIA,OAAM,KAAK,sBAAsB,CAAC,EAAE;AAAA,QACrG;AAAA,MACF;AAAA,IACF;AAEA,YAAQ;AAER,QAAI,SAAS;AACX,cAAQ,IAAIA,OAAM,MAAM,4CAA4C,CAAC;AAAA,IACvE,OAAO;AACL,cAAQ,IAAIA,OAAM,IAAI,2CAA2C,CAAC;AAAA,IACpE;AAEA,YAAQ;AAAA,EACV,CAAC;AACL;;;AnBvDO,SAAS,YAAqB;AACnC,QAAME,WAAU,IAAIC,SAAQ;AAE5B,EAAAD,SACG,KAAK,UAAU,EACf,YAAY,qDAAqD,EACjE,QAAQ,OAAO,EACf,OAAO,aAAa,uBAAuB,EAC3C,KAAK,aAAa,CAAC,gBAAgB;AAClC,UAAM,OAAO,YAAY,KAAK;AAC9B,QAAI,KAAK,SAAS;AAChB,iBAAW,IAAI;AAAA,IACjB;AAAA,EACF,CAAC;AAEH,EAAAA,SAAQ,WAAW,cAAc,CAAC;AAClC,EAAAA,SAAQ,WAAW,YAAY,CAAC;AAChC,EAAAA,SAAQ,WAAW,cAAc,CAAC;AAElC,SAAOA;AACT;;;AoBxBA,IAAM,UAAU,UAAU;AAC1B,QAAQ,MAAM;","names":["Command","path","fs","framework","inquirer","inquirer","inquirer","path","path","path","path","path","writeFile","path","fs","Command","chalk","Command","chalk","Command","execSync","chalk","Command","chalk","execSync","program","Command"]}
1
+ {"version":3,"sources":["../src/cli.ts","../src/commands/create.ts","../src/prompts/framework.ts","../src/prompts/features.ts","../src/prompts/config.ts","../src/constants.ts","../src/prompts/index.ts","../src/generators/react.ts","../src/generators/base.ts","../src/utils/logger.ts","../src/utils/file.ts","../src/utils/validator.ts","../src/generators/nextjs.ts","../src/generators/angular.ts","../src/generators/express.ts","../src/generators/fastapi.ts","../src/generators/fullstack.ts","../src/generators/index.ts","../src/types/config.ts","../src/commands/list.ts","../src/commands/doctor.ts","../src/index.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { createCommand } from './commands/create.js';\nimport { listCommand } from './commands/list.js';\nimport { doctorCommand } from './commands/doctor.js';\nimport { setVerbose } from './utils/logger.js';\n\nexport function createCli(): Command {\n const program = new Command();\n\n program\n .name('scaffold')\n .description('CLI tool for scaffolding modern full-stack projects')\n .version('0.1.1')\n .option('--verbose', 'Enable verbose output')\n .hook('preAction', (thisCommand) => {\n const opts = thisCommand.opts();\n if (opts.verbose) {\n setVerbose(true);\n }\n });\n\n program.addCommand(createCommand());\n program.addCommand(listCommand());\n program.addCommand(doctorCommand());\n\n return program;\n}\n","import { Command } from 'commander';\nimport path from 'node:path';\nimport fs from 'fs-extra';\nimport { runPrompts } from '../prompts/index.js';\nimport { createGenerator } from '../generators/index.js';\nimport {\n validateProjectName,\n validateDirectory,\n success,\n error,\n newLine,\n banner,\n} from '../utils/index.js';\nimport type { ProjectConfig } from '../types/index.js';\nimport { DEFAULT_CONFIG } from '../types/index.js';\n\ninterface CreateOptions {\n react?: boolean;\n nextjs?: boolean;\n angular?: boolean;\n express?: boolean;\n fastapi?: boolean;\n yes?: boolean;\n from?: string;\n force?: boolean;\n}\n\nexport function createCommand(): Command {\n const cmd = new Command('create')\n .description('Create a new project')\n .argument('<project-name>', 'Name of the project')\n .option('--react', 'Create a React + Vite project')\n .option('--nextjs', 'Create a Next.js project')\n .option('--angular', 'Create an Angular project')\n .option('--express', 'Create an Express.js project')\n .option('--fastapi', 'Create a FastAPI project')\n .option('-y, --yes', 'Skip prompts and use defaults')\n .option('--from <path>', 'Create from a config file')\n .option('--force', 'Overwrite existing directory')\n .action(async (projectName: string, options: CreateOptions) => {\n try {\n await handleCreate(projectName, options);\n } catch (err) {\n error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n });\n\n return cmd;\n}\n\nasync function handleCreate(projectName: string, options: CreateOptions): Promise<void> {\n const nameValidation = validateProjectName(projectName);\n if (nameValidation !== true) {\n throw new Error(nameValidation);\n }\n\n const targetDir = path.resolve(process.cwd(), projectName);\n\n if (!options.force) {\n const dirValidation = await validateDirectory(targetDir);\n if (dirValidation !== true) {\n throw new Error(dirValidation);\n }\n }\n\n let config: ProjectConfig;\n\n if (options.from) {\n config = await loadConfigFromFile(options.from, projectName);\n } else if (options.yes || hasFrameworkFlag(options)) {\n config = buildQuickConfig(projectName, options);\n } else {\n config = await runPrompts(projectName);\n }\n\n newLine();\n banner(`Creating project \"${config.name}\"...`);\n newLine();\n\n const generator = createGenerator(config, targetDir);\n await generator.generate();\n\n newLine();\n success(`Project \"${config.name}\" created successfully! 🎉`);\n newLine();\n console.log('Next steps:');\n console.log(` cd ${config.name}`);\n\n if (config.framework === 'fastapi') {\n console.log(' pip install -r requirements.txt');\n console.log(' uvicorn app.main:app --reload');\n } else {\n console.log(` ${config.packageManager} install`);\n console.log(` ${config.packageManager} run dev`);\n }\n\n newLine();\n console.log('Happy coding! 🚀');\n newLine();\n}\n\nfunction hasFrameworkFlag(options: CreateOptions): boolean {\n return !!(\n options.react ||\n options.nextjs ||\n options.angular ||\n options.express ||\n options.fastapi\n );\n}\n\nfunction buildQuickConfig(projectName: string, options: CreateOptions): ProjectConfig {\n const config: ProjectConfig = { ...DEFAULT_CONFIG, name: projectName };\n\n if (options.react) {\n config.type = 'frontend';\n config.framework = 'react';\n } else if (options.nextjs) {\n config.type = 'frontend';\n config.framework = 'nextjs';\n } else if (options.angular) {\n config.type = 'frontend';\n config.framework = 'angular';\n } else if (options.express) {\n config.type = 'backend';\n config.framework = 'express';\n } else if (options.fastapi) {\n config.type = 'backend';\n config.framework = 'fastapi';\n }\n\n return config;\n}\n\nasync function loadConfigFromFile(configPath: string, projectName: string): Promise<ProjectConfig> {\n const resolvedPath = path.resolve(process.cwd(), configPath);\n const content = await fs.readJSON(resolvedPath);\n return { ...DEFAULT_CONFIG, ...content, name: projectName };\n}\n","import inquirer from 'inquirer';\nimport type { ProjectType, FrameworkType } from '../types/index.js';\n\nexport async function promptProjectType(): Promise<ProjectType> {\n const { projectType } = await inquirer.prompt([\n {\n type: 'list',\n name: 'projectType',\n message: 'What type of project?',\n choices: [\n { name: 'Frontend (React, Next.js, Angular)', value: 'frontend' },\n { name: 'Backend (Express, FastAPI)', value: 'backend' },\n { name: 'Full-Stack (Frontend + Backend)', value: 'fullstack' },\n ],\n },\n ]);\n\n return projectType;\n}\n\nexport async function promptFramework(projectType: ProjectType): Promise<FrameworkType> {\n if (projectType === 'frontend') {\n const { framework } = await inquirer.prompt([\n {\n type: 'list',\n name: 'framework',\n message: 'Which frontend framework?',\n choices: [\n { name: 'React + Vite', value: 'react' },\n { name: 'Next.js (App Router)', value: 'nextjs' },\n { name: 'Angular 18', value: 'angular' },\n ],\n },\n ]);\n return framework;\n }\n\n if (projectType === 'backend') {\n const { framework } = await inquirer.prompt([\n {\n type: 'list',\n name: 'framework',\n message: 'Which backend framework?',\n choices: [\n { name: 'Express.js', value: 'express' },\n { name: 'FastAPI (Python)', value: 'fastapi' },\n ],\n },\n ]);\n return framework;\n }\n\n // fullstack — prompt for frontend (we'll use express as the backend)\n const { framework } = await inquirer.prompt([\n {\n type: 'list',\n name: 'framework',\n message: 'Which frontend framework?',\n choices: [\n { name: 'React + Vite', value: 'react' },\n { name: 'Next.js', value: 'nextjs' },\n { name: 'Angular 18', value: 'angular' },\n ],\n },\n ]);\n return framework;\n}\n","import inquirer from 'inquirer';\nimport type { FeatureFlags, ProjectType, FrameworkType } from '../types/index.js';\n\ninterface FeatureChoice {\n name: string;\n value: keyof FeatureFlags;\n checked: boolean;\n disabled?: string | false;\n}\n\nexport async function promptFeatures(\n projectType: ProjectType,\n framework: FrameworkType,\n): Promise<FeatureFlags> {\n const isPython = framework === 'fastapi';\n\n const choices: FeatureChoice[] = [\n {\n name: 'TypeScript',\n value: 'typescript',\n checked: true,\n disabled: isPython ? 'N/A for Python' : false,\n },\n {\n name: 'ESLint + Prettier',\n value: 'eslint',\n checked: !isPython,\n disabled: isPython ? 'N/A for Python' : false,\n },\n { name: 'Tailwind CSS', value: 'tailwind', checked: false },\n { name: 'shadcn/ui components', value: 'shadcn', checked: false },\n { name: isPython ? 'Pytest testing' : 'Vitest testing', value: 'testing', checked: true },\n { name: 'GitHub Actions CI/CD', value: 'githubActions', checked: false },\n { name: 'Docker setup', value: 'docker', checked: false },\n {\n name: 'Husky pre-commit hooks',\n value: 'husky',\n checked: false,\n disabled: isPython ? 'N/A for Python' : false,\n },\n { name: '.env example file', value: 'envExample', checked: false },\n ];\n\n // Filter out frontend-only features for backend projects\n const filteredChoices =\n projectType === 'backend'\n ? choices.filter((c) => !['tailwind', 'shadcn'].includes(c.value))\n : choices;\n\n const { features } = await inquirer.prompt([\n {\n type: 'checkbox',\n name: 'features',\n message: 'Select features:',\n choices: filteredChoices,\n },\n ]);\n\n const selectedFeatures = features as (keyof FeatureFlags)[];\n\n return {\n typescript: !isPython && selectedFeatures.includes('typescript'),\n eslint: !isPython && selectedFeatures.includes('eslint'),\n prettier: !isPython && selectedFeatures.includes('eslint'),\n tailwind: selectedFeatures.includes('tailwind'),\n shadcn: selectedFeatures.includes('shadcn'),\n testing: selectedFeatures.includes('testing'),\n githubActions: selectedFeatures.includes('githubActions'),\n docker: selectedFeatures.includes('docker'),\n husky: !isPython && selectedFeatures.includes('husky'),\n envExample: selectedFeatures.includes('envExample'),\n };\n}\n","import inquirer from 'inquirer';\nimport type { VariantType, PackageManager, FrameworkType } from '../types/index.js';\nimport { FRAMEWORKS, VARIANT_DISPLAY_NAMES } from '../constants.js';\n\nexport async function promptVariant(framework: FrameworkType): Promise<VariantType> {\n const meta = FRAMEWORKS[framework];\n\n if (meta.variants.length <= 1) {\n return 'base';\n }\n\n const { variant } = await inquirer.prompt([\n {\n type: 'list',\n name: 'variant',\n message: 'Select a template variant:',\n choices: meta.variants.map((v) => ({\n name: VARIANT_DISPLAY_NAMES[v],\n value: v,\n })),\n },\n ]);\n\n return variant;\n}\n\nexport async function promptPackageManager(): Promise<PackageManager> {\n const { packageManager } = await inquirer.prompt([\n {\n type: 'list',\n name: 'packageManager',\n message: 'Package manager?',\n choices: [\n { name: 'npm', value: 'npm' },\n { name: 'yarn', value: 'yarn' },\n { name: 'pnpm', value: 'pnpm' },\n ],\n },\n ]);\n\n return packageManager;\n}\n\nexport async function promptGitInit(): Promise<boolean> {\n const { gitInit } = await inquirer.prompt([\n {\n type: 'confirm',\n name: 'gitInit',\n message: 'Initialize git repository?',\n default: true,\n },\n ]);\n\n return gitInit;\n}\n","import type { FrameworkMeta, FrameworkType, VariantType } from './types/index.js';\n\nexport const FRAMEWORKS: Record<FrameworkType, FrameworkMeta> = {\n react: {\n name: 'react',\n displayName: 'React + Vite',\n description: 'React 19 with Vite and TypeScript',\n type: 'frontend',\n variants: ['base', 'with-tailwind', 'with-shadcn'],\n language: 'typescript',\n },\n nextjs: {\n name: 'nextjs',\n displayName: 'Next.js (App Router)',\n description: 'Next.js 15 with App Router and TypeScript',\n type: 'frontend',\n variants: ['base', 'with-auth', 'with-prisma'],\n language: 'typescript',\n },\n angular: {\n name: 'angular',\n displayName: 'Angular 18',\n description: 'Angular 18 standalone with TypeScript',\n type: 'frontend',\n variants: ['base'],\n language: 'typescript',\n },\n express: {\n name: 'express',\n displayName: 'Express.js',\n description: 'Express 5 with TypeScript',\n type: 'backend',\n variants: ['base', 'with-prisma'],\n language: 'typescript',\n },\n fastapi: {\n name: 'fastapi',\n displayName: 'FastAPI',\n description: 'FastAPI with Pydantic and Python',\n type: 'backend',\n variants: ['base'],\n language: 'python',\n },\n};\n\nexport const FRONTEND_FRAMEWORKS: FrameworkType[] = ['react', 'nextjs', 'angular'];\nexport const BACKEND_FRAMEWORKS: FrameworkType[] = ['express', 'fastapi'];\n\nexport const VARIANT_DISPLAY_NAMES: Record<VariantType, string> = {\n base: 'Base (minimal setup)',\n 'with-tailwind': 'With Tailwind CSS',\n 'with-shadcn': 'With shadcn/ui',\n 'with-auth': 'With NextAuth.js',\n 'with-prisma': 'With Prisma ORM',\n};\n","import type { ProjectConfig } from '../types/index.js';\nimport { promptProjectType, promptFramework } from './framework.js';\nimport { promptFeatures } from './features.js';\nimport { promptVariant, promptPackageManager, promptGitInit } from './config.js';\n\nexport async function runPrompts(projectName: string): Promise<ProjectConfig> {\n const type = await promptProjectType();\n const framework = await promptFramework(type);\n const variant = await promptVariant(framework);\n const features = await promptFeatures(type, framework);\n\n const isPython = framework === 'fastapi';\n const packageManager = isPython ? 'npm' : await promptPackageManager();\n const gitInit = await promptGitInit();\n\n return {\n name: projectName,\n type,\n framework,\n variant,\n features,\n packageManager,\n gitInit,\n };\n}\n","import path from 'node:path';\nimport { BaseGenerator } from './base.js';\nimport { spinner, success } from '../utils/index.js';\n\nexport class ReactGenerator extends BaseGenerator {\n protected async generateBase(): Promise<void> {\n const baseDir = this.getBaseTemplateDir();\n\n const s = spinner('Configuring React + Vite + TypeScript');\n s.start();\n await this.renderDirectory(baseDir, this.targetDir);\n s.stop();\n success('Configuring React + Vite + TypeScript');\n\n if (this.config.features.testing) {\n success('Configuring Vitest');\n }\n }\n\n private getVariantPath(variant: string): string {\n return path.join(this.templatesDir, 'react', variant);\n }\n}\n","import path from 'node:path';\nimport fs from 'fs-extra';\nimport { execSync } from 'node:child_process';\nimport {\n createDir,\n renderAndWrite,\n getTemplatesDir,\n spinner,\n success,\n debug,\n} from '../utils/index.js';\nimport type { ProjectConfig } from '../types/index.js';\nimport type { GeneratorResult } from '../types/generator.js';\n\nexport abstract class BaseGenerator {\n protected config: ProjectConfig;\n protected targetDir: string;\n protected templatesDir: string;\n protected result: GeneratorResult = { filesCreated: [], warnings: [] };\n\n constructor(config: ProjectConfig, targetDir: string) {\n this.config = config;\n this.targetDir = targetDir;\n this.templatesDir = getTemplatesDir();\n }\n\n async generate(): Promise<GeneratorResult> {\n await this.createProjectDir();\n await this.generateBase();\n await this.applyVariant();\n await this.applySharedConfigs();\n await this.applyFeatures();\n await this.initGit();\n return this.result;\n }\n\n protected abstract generateBase(): Promise<void>;\n\n protected async applyVariant(): Promise<void> {\n if (this.config.variant === 'base') return;\n\n const variantDir = this.getVariantTemplateDir();\n if (await fs.pathExists(variantDir)) {\n const s = spinner(`Applying ${this.config.variant} variant`);\n s.start();\n await this.renderDirectory(variantDir, this.targetDir);\n s.stop();\n success(`Applied ${this.config.variant} variant`);\n }\n }\n\n protected async applySharedConfigs(): Promise<void> {\n const sharedDir = path.join(this.templatesDir, 'shared');\n\n if (this.config.features.eslint) {\n const s = spinner('Setting up ESLint + Prettier');\n s.start();\n await this.renderTemplateFile(\n path.join(sharedDir, 'eslint.config.js.hbs'),\n path.join(this.targetDir, 'eslint.config.js'),\n );\n await this.renderTemplateFile(\n path.join(sharedDir, 'prettier.config.js.hbs'),\n path.join(this.targetDir, '.prettierrc'),\n );\n s.stop();\n success('Setting up ESLint + Prettier');\n }\n\n // Gitignore\n await this.renderTemplateFile(\n path.join(sharedDir, 'gitignore.hbs'),\n path.join(this.targetDir, '.gitignore'),\n );\n\n // README\n const s2 = spinner('Generating README.md');\n s2.start();\n await this.renderTemplateFile(\n path.join(sharedDir, 'readme.md.hbs'),\n path.join(this.targetDir, 'README.md'),\n );\n s2.stop();\n success('Generating README.md');\n\n // License\n await this.renderTemplateFile(\n path.join(sharedDir, 'license.hbs'),\n path.join(this.targetDir, 'LICENSE'),\n );\n }\n\n protected async applyFeatures(): Promise<void> {\n const sharedDir = path.join(this.templatesDir, 'shared');\n\n if (this.config.features.githubActions) {\n const s = spinner('Creating GitHub Actions workflow');\n s.start();\n await this.renderTemplateFile(\n path.join(sharedDir, 'github-ci.yml.hbs'),\n path.join(this.targetDir, '.github', 'workflows', 'ci.yml'),\n );\n s.stop();\n success('Creating GitHub Actions workflow');\n }\n\n if (this.config.features.docker) {\n const s = spinner('Adding Docker configuration');\n s.start();\n await this.renderTemplateFile(\n path.join(sharedDir, 'docker', 'Dockerfile.hbs'),\n path.join(this.targetDir, 'Dockerfile'),\n );\n await this.renderTemplateFile(\n path.join(sharedDir, 'docker', 'docker-compose.yml.hbs'),\n path.join(this.targetDir, 'docker-compose.yml'),\n );\n s.stop();\n success('Adding Docker configuration');\n }\n }\n\n protected async createProjectDir(): Promise<void> {\n const s = spinner('Creating project structure');\n s.start();\n await createDir(this.targetDir);\n s.stop();\n success('Creating project structure');\n }\n\n protected async initGit(): Promise<void> {\n if (!this.config.gitInit) return;\n\n const s = spinner('Initializing git repository');\n s.start();\n try {\n execSync('git init', { cwd: this.targetDir, stdio: 'pipe' });\n execSync('git add -A', { cwd: this.targetDir, stdio: 'pipe' });\n execSync('git commit -m \"Initial commit from scaffold\"', {\n cwd: this.targetDir,\n stdio: 'pipe',\n });\n s.stop();\n success('Initializing git repository');\n } catch {\n s.stop();\n debug('Git initialization skipped (git not available)');\n }\n }\n\n protected async renderTemplateFile(templatePath: string, outputPath: string): Promise<void> {\n const templateData = this.getTemplateData();\n\n if (await fs.pathExists(templatePath)) {\n await renderAndWrite(templatePath, outputPath, templateData);\n this.result.filesCreated.push(outputPath);\n } else {\n debug(`Template not found: ${templatePath}`);\n }\n }\n\n protected async renderDirectory(srcDir: string, destDir: string): Promise<void> {\n const entries = await fs.readdir(srcDir, { withFileTypes: true });\n\n for (const entry of entries) {\n const srcPath = path.join(srcDir, entry.name);\n const destName = entry.name.replace(/\\.hbs$/, '');\n const destPath = path.join(destDir, destName);\n\n if (entry.isDirectory()) {\n await this.renderDirectory(srcPath, destPath);\n } else if (entry.name.endsWith('.hbs')) {\n await this.renderTemplateFile(srcPath, destPath);\n } else {\n await fs.ensureDir(path.dirname(destPath));\n await fs.copy(srcPath, destPath);\n this.result.filesCreated.push(destPath);\n }\n }\n }\n\n protected getTemplateData(): object {\n return {\n ...this.config,\n year: new Date().getFullYear(),\n };\n }\n\n protected getBaseTemplateDir(): string {\n return path.join(this.templatesDir, this.config.framework, 'base');\n }\n\n protected getVariantTemplateDir(): string {\n return path.join(this.templatesDir, this.config.framework, this.config.variant);\n }\n}\n","import chalk from 'chalk';\nimport ora, { type Ora } from 'ora';\n\nlet verbose = false;\n\nexport function setVerbose(value: boolean): void {\n verbose = value;\n}\n\nexport function info(message: string): void {\n console.log(chalk.blue('ℹ'), message);\n}\n\nexport function success(message: string): void {\n console.log(chalk.green('✔'), message);\n}\n\nexport function warn(message: string): void {\n console.log(chalk.yellow('⚠'), message);\n}\n\nexport function error(message: string): void {\n console.log(chalk.red('✖'), message);\n}\n\nexport function debug(message: string): void {\n if (verbose) {\n console.log(chalk.gray('⬥'), chalk.gray(message));\n }\n}\n\nexport function spinner(text: string): Ora {\n return ora({ text, color: 'cyan' });\n}\n\nexport function newLine(): void {\n console.log();\n}\n\nexport function banner(text: string): void {\n console.log(chalk.bold.cyan(text));\n}\n","import path from 'node:path';\nimport fs from 'fs-extra';\nimport Handlebars from 'handlebars';\nimport { fileURLToPath } from 'node:url';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\n// Register custom Handlebars helpers\nHandlebars.registerHelper('eq', (a: unknown, b: unknown) => a === b);\nHandlebars.registerHelper('neq', (a: unknown, b: unknown) => a !== b);\nHandlebars.registerHelper('or', (a: unknown, b: unknown) => a || b);\nHandlebars.registerHelper('and', (a: unknown, b: unknown) => a && b);\nHandlebars.registerHelper('lowercase', (str: string) => str?.toLowerCase());\nHandlebars.registerHelper('year', () => new Date().getFullYear());\nHandlebars.registerHelper('join', (arr: string[], sep: string) =>\n Array.isArray(arr) ? arr.join(typeof sep === 'string' ? sep : ', ') : '',\n);\n\nexport function getTemplatesDir(): string {\n // When bundled with tsup, __dirname is dist/ → go up 1 level to project root\n // When running unbundled (vitest), __dirname is src/utils/ → go up 2 levels to project root\n // In both cases, templates live at <projectRoot>/src/templates\n const isBundled =\n __dirname.replace(/\\\\/g, '/').endsWith('/dist') ||\n __dirname.replace(/\\\\/g, '/').includes('/dist/');\n const projectRoot = isBundled\n ? path.resolve(__dirname, '..')\n : path.resolve(__dirname, '..', '..');\n return path.resolve(projectRoot, 'src', 'templates');\n}\n\nexport async function createDir(dirPath: string): Promise<void> {\n await fs.ensureDir(dirPath);\n}\n\nexport async function writeFile(filePath: string, content: string): Promise<void> {\n await fs.ensureDir(path.dirname(filePath));\n await fs.writeFile(filePath, content, 'utf-8');\n}\n\nexport async function copyFile(src: string, dest: string): Promise<void> {\n await fs.ensureDir(path.dirname(dest));\n await fs.copy(src, dest);\n}\n\nexport async function renderTemplate(templatePath: string, data: object): Promise<string> {\n const templateContent = await fs.readFile(templatePath, 'utf-8');\n const template = Handlebars.compile(templateContent, { noEscape: true });\n return template(data);\n}\n\nexport async function renderAndWrite(\n templatePath: string,\n outputPath: string,\n data: object,\n): Promise<void> {\n const content = await renderTemplate(templatePath, data);\n await writeFile(outputPath, content);\n}\n\nexport async function directoryExists(dirPath: string): Promise<boolean> {\n try {\n const stat = await fs.stat(dirPath);\n return stat.isDirectory();\n } catch {\n return false;\n }\n}\n\nexport async function fileExists(filePath: string): Promise<boolean> {\n try {\n const stat = await fs.stat(filePath);\n return stat.isFile();\n } catch {\n return false;\n }\n}\n\nexport function getOutputFileName(templateName: string): string {\n return templateName.replace(/\\.hbs$/, '');\n}\n","import { directoryExists } from './file.js';\n\nconst VALID_PROJECT_NAME = /^(?:@[a-z0-9-~][a-z0-9-._~]*\\/)?[a-z0-9-~][a-z0-9-._~]*$/;\n\nexport function validateProjectName(name: string): string | true {\n if (!name || name.trim().length === 0) {\n return 'Project name is required.';\n }\n\n if (!VALID_PROJECT_NAME.test(name)) {\n return 'Project name must be a valid npm package name (lowercase, no spaces, can use hyphens and dots).';\n }\n\n if (name.length > 214) {\n return 'Project name must be less than 214 characters.';\n }\n\n return true;\n}\n\nexport async function validateDirectory(dirPath: string): Promise<string | true> {\n if (await directoryExists(dirPath)) {\n return `Directory \"${dirPath}\" already exists. Use --force to overwrite.`;\n }\n return true;\n}\n\nexport function checkNodeVersion(minMajor: number = 20): string | true {\n const version = process.version;\n const major = parseInt(version.slice(1).split('.')[0], 10);\n\n if (major < minMajor) {\n return `Node.js ${minMajor}+ is required. You are using ${version}.`;\n }\n\n return true;\n}\n","import { BaseGenerator } from './base.js';\nimport { spinner, success } from '../utils/index.js';\n\nexport class NextjsGenerator extends BaseGenerator {\n protected async generateBase(): Promise<void> {\n const baseDir = this.getBaseTemplateDir();\n\n const s = spinner('Configuring Next.js + App Router + TypeScript');\n s.start();\n await this.renderDirectory(baseDir, this.targetDir);\n s.stop();\n success('Configuring Next.js + App Router + TypeScript');\n\n if (this.config.features.testing) {\n success('Configuring Vitest');\n }\n }\n}\n","import { BaseGenerator } from './base.js';\nimport { spinner, success } from '../utils/index.js';\n\nexport class AngularGenerator extends BaseGenerator {\n protected async generateBase(): Promise<void> {\n const baseDir = this.getBaseTemplateDir();\n\n const s = spinner('Configuring Angular 18 + TypeScript');\n s.start();\n await this.renderDirectory(baseDir, this.targetDir);\n s.stop();\n success('Configuring Angular 18 + TypeScript');\n }\n}\n","import { BaseGenerator } from './base.js';\nimport { spinner, success } from '../utils/index.js';\n\nexport class ExpressGenerator extends BaseGenerator {\n protected async generateBase(): Promise<void> {\n const baseDir = this.getBaseTemplateDir();\n\n const s = spinner('Configuring Express 5 + TypeScript');\n s.start();\n await this.renderDirectory(baseDir, this.targetDir);\n s.stop();\n success('Configuring Express 5 + TypeScript');\n\n if (this.config.features.testing) {\n success('Configuring Vitest');\n }\n }\n}\n","import { BaseGenerator } from './base.js';\nimport { spinner, success } from '../utils/index.js';\n\nexport class FastAPIGenerator extends BaseGenerator {\n protected async generateBase(): Promise<void> {\n const baseDir = this.getBaseTemplateDir();\n\n const s = spinner('Configuring FastAPI + Pydantic');\n s.start();\n await this.renderDirectory(baseDir, this.targetDir);\n s.stop();\n success('Configuring FastAPI + Pydantic');\n\n if (this.config.features.testing) {\n success('Configuring Pytest');\n }\n }\n\n protected override async applySharedConfigs(): Promise<void> {\n // Python projects don't use ESLint/Prettier/tsconfig\n const path = await import('node:path');\n const sharedDir = path.join(this.templatesDir, 'shared');\n\n // Still apply gitignore, readme, license\n await this.renderTemplateFile(\n path.join(sharedDir, 'gitignore.hbs'),\n path.join(this.targetDir, '.gitignore'),\n );\n\n const s = spinner('Generating README.md');\n s.start();\n await this.renderTemplateFile(\n path.join(sharedDir, 'readme.md.hbs'),\n path.join(this.targetDir, 'README.md'),\n );\n s.stop();\n success('Generating README.md');\n\n await this.renderTemplateFile(\n path.join(sharedDir, 'license.hbs'),\n path.join(this.targetDir, 'LICENSE'),\n );\n }\n}\n","import path from 'node:path';\nimport { BaseGenerator } from './base.js';\nimport { ReactGenerator } from './react.js';\nimport { NextjsGenerator } from './nextjs.js';\nimport { AngularGenerator } from './angular.js';\nimport { ExpressGenerator } from './express.js';\nimport { spinner, success, createDir, writeFile } from '../utils/index.js';\nimport type { ProjectConfig } from '../types/index.js';\n\nexport class FullstackGenerator extends BaseGenerator {\n protected async generateBase(): Promise<void> {\n const s = spinner('Setting up full-stack monorepo');\n s.start();\n\n // Create apps directories\n const webDir = path.join(this.targetDir, 'apps', 'web');\n const apiDir = path.join(this.targetDir, 'apps', 'api');\n await createDir(webDir);\n await createDir(apiDir);\n\n s.stop();\n success('Setting up full-stack monorepo');\n\n // Generate frontend in apps/web\n const frontendConfig: ProjectConfig = {\n ...this.config,\n type: 'frontend',\n gitInit: false,\n };\n\n const frontendGen = this.createFrontendGenerator(frontendConfig, webDir);\n await frontendGen.generate();\n\n // Generate backend in apps/api\n const backendConfig: ProjectConfig = {\n ...this.config,\n type: 'backend',\n framework: 'express',\n gitInit: false,\n };\n\n const backendGen = new ExpressGenerator(backendConfig, apiDir);\n await backendGen.generate();\n\n // Write root package.json for workspaces\n const rootPkgPath = path.join(this.targetDir, 'package.json');\n const rootPkg = {\n name: this.config.name,\n private: true,\n workspaces: ['apps/*'],\n scripts: {\n dev: 'npm run --workspaces dev',\n build: 'npm run --workspaces build',\n lint: 'npm run --workspaces lint',\n test: 'npm run --workspaces test',\n },\n };\n await writeFile(rootPkgPath, JSON.stringify(rootPkg, null, 2) + '\\n');\n }\n\n private createFrontendGenerator(config: ProjectConfig, targetDir: string): BaseGenerator {\n switch (config.framework) {\n case 'nextjs':\n return new NextjsGenerator(config, targetDir);\n case 'angular':\n return new AngularGenerator(config, targetDir);\n case 'react':\n default:\n return new ReactGenerator(config, targetDir);\n }\n }\n}\n","import type { ProjectConfig } from '../types/index.js';\nimport { BaseGenerator } from './base.js';\nimport { ReactGenerator } from './react.js';\nimport { NextjsGenerator } from './nextjs.js';\nimport { AngularGenerator } from './angular.js';\nimport { ExpressGenerator } from './express.js';\nimport { FastAPIGenerator } from './fastapi.js';\nimport { FullstackGenerator } from './fullstack.js';\n\nexport function createGenerator(config: ProjectConfig, targetDir: string): BaseGenerator {\n if (config.type === 'fullstack') {\n return new FullstackGenerator(config, targetDir);\n }\n\n switch (config.framework) {\n case 'react':\n return new ReactGenerator(config, targetDir);\n case 'nextjs':\n return new NextjsGenerator(config, targetDir);\n case 'angular':\n return new AngularGenerator(config, targetDir);\n case 'express':\n return new ExpressGenerator(config, targetDir);\n case 'fastapi':\n return new FastAPIGenerator(config, targetDir);\n default:\n throw new Error(`Unknown framework: ${config.framework}`);\n }\n}\n\nexport { BaseGenerator } from './base.js';\n","export type ProjectType = 'frontend' | 'backend' | 'fullstack';\n\nexport type FrameworkType = 'react' | 'nextjs' | 'angular' | 'express' | 'fastapi';\n\nexport type VariantType = 'base' | 'with-tailwind' | 'with-shadcn' | 'with-auth' | 'with-prisma';\n\nexport type PackageManager = 'npm' | 'yarn' | 'pnpm';\n\nexport interface FeatureFlags {\n typescript: boolean;\n eslint: boolean;\n prettier: boolean;\n tailwind: boolean;\n shadcn: boolean;\n testing: boolean;\n githubActions: boolean;\n docker: boolean;\n husky: boolean;\n envExample: boolean;\n}\n\nexport interface ProjectConfig {\n name: string;\n type: ProjectType;\n framework: FrameworkType;\n variant: VariantType;\n features: FeatureFlags;\n packageManager: PackageManager;\n gitInit: boolean;\n}\n\nexport interface FrameworkMeta {\n name: string;\n displayName: string;\n description: string;\n type: ProjectType;\n variants: VariantType[];\n language: 'typescript' | 'python';\n}\n\nexport const DEFAULT_FEATURES: FeatureFlags = {\n typescript: true,\n eslint: true,\n prettier: true,\n tailwind: false,\n shadcn: false,\n testing: true,\n githubActions: false,\n docker: false,\n husky: false,\n envExample: false,\n};\n\nexport const DEFAULT_CONFIG: ProjectConfig = {\n name: '',\n type: 'frontend',\n framework: 'react',\n variant: 'base',\n features: { ...DEFAULT_FEATURES },\n packageManager: 'npm',\n gitInit: true,\n};\n","import { Command } from 'commander';\nimport chalk from 'chalk';\nimport { FRAMEWORKS, VARIANT_DISPLAY_NAMES } from '../constants.js';\nimport type { FrameworkType } from '../types/index.js';\nimport { newLine } from '../utils/logger.js';\n\nexport function listCommand(): Command {\n return new Command('list').description('List all available templates').action(() => {\n newLine();\n console.log(chalk.bold.cyan('Available Templates'));\n console.log(chalk.gray('─'.repeat(60)));\n newLine();\n\n const categories = {\n Frontend: ['react', 'nextjs', 'angular'] as FrameworkType[],\n Backend: ['express', 'fastapi'] as FrameworkType[],\n };\n\n for (const [category, frameworks] of Object.entries(categories)) {\n console.log(chalk.bold.white(` ${category}`));\n newLine();\n\n for (const fw of frameworks) {\n const meta = FRAMEWORKS[fw];\n console.log(\n ` ${chalk.green(meta.displayName.padEnd(25))} ${chalk.gray(meta.description)}`,\n );\n\n for (const variant of meta.variants) {\n const label = VARIANT_DISPLAY_NAMES[variant];\n console.log(` ${chalk.gray('•')} ${label}`);\n }\n newLine();\n }\n }\n\n console.log(chalk.gray('─'.repeat(60)));\n console.log(\n chalk.gray(' Use'),\n chalk.cyan('scaffold create <name> --<framework>'),\n chalk.gray('for quick setup'),\n );\n newLine();\n });\n}\n","import { Command } from 'commander';\nimport { execSync } from 'node:child_process';\nimport chalk from 'chalk';\nimport { newLine } from '../utils/logger.js';\n\ninterface Check {\n name: string;\n command: string;\n versionFlag?: string;\n required: boolean;\n}\n\nconst CHECKS: Check[] = [\n { name: 'Node.js', command: 'node', versionFlag: '--version', required: true },\n { name: 'npm', command: 'npm', versionFlag: '--version', required: false },\n { name: 'yarn', command: 'yarn', versionFlag: '--version', required: false },\n { name: 'pnpm', command: 'pnpm', versionFlag: '--version', required: false },\n { name: 'git', command: 'git', versionFlag: '--version', required: true },\n { name: 'Python', command: 'python3', versionFlag: '--version', required: false },\n];\n\nexport function doctorCommand(): Command {\n return new Command('doctor').description('Check system dependencies').action(() => {\n newLine();\n console.log(chalk.bold.cyan('System Check'));\n console.log(chalk.gray('─'.repeat(40)));\n newLine();\n\n let allGood = true;\n\n for (const check of CHECKS) {\n try {\n const version = execSync(`${check.command} ${check.versionFlag ?? '--version'}`, {\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n }).trim();\n\n const versionStr = version.split('\\n')[0];\n console.log(` ${chalk.green('✔')} ${check.name.padEnd(12)} ${chalk.gray(versionStr)}`);\n } catch {\n if (check.required) {\n console.log(\n ` ${chalk.red('✖')} ${check.name.padEnd(12)} ${chalk.red('not found (required)')}`,\n );\n allGood = false;\n } else {\n console.log(\n ` ${chalk.yellow('–')} ${check.name.padEnd(12)} ${chalk.gray('not found (optional)')}`,\n );\n }\n }\n }\n\n newLine();\n\n if (allGood) {\n console.log(chalk.green(' All required dependencies are installed!'));\n } else {\n console.log(chalk.red(' Some required dependencies are missing.'));\n }\n\n newLine();\n });\n}\n","import { createCli } from './cli.js';\n\nconst program = createCli();\nprogram.parse();\n"],"mappings":"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","names":["Command","path","fs","framework","inquirer","inquirer","inquirer","path","path","fs","__filename","__dirname","fs","path","path","path","path","path","path","fs","Command","chalk","Command","chalk","Command","execSync","chalk","Command","chalk","execSync","program","Command"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codecanvascollective/scaffold",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "CLI tool for scaffolding modern full-stack projects",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,7 +1,5 @@
1
1
  import js from '@eslint/js';
2
2
  import tseslint from 'typescript-eslint';
3
- {{#if features.tailwind}}
4
- {{/if}}
5
3
 
6
4
  export default tseslint.config(
7
5
  js.configs.recommended,
@@ -1,76 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- // src/utils/file.ts
4
- import path from "path";
5
- import fs from "fs-extra";
6
- import Handlebars from "handlebars";
7
- import { fileURLToPath } from "url";
8
- var __filename = fileURLToPath(import.meta.url);
9
- var __dirname = path.dirname(__filename);
10
- Handlebars.registerHelper("eq", (a, b) => a === b);
11
- Handlebars.registerHelper("neq", (a, b) => a !== b);
12
- Handlebars.registerHelper("or", (a, b) => a || b);
13
- Handlebars.registerHelper("and", (a, b) => a && b);
14
- Handlebars.registerHelper("lowercase", (str) => str?.toLowerCase());
15
- Handlebars.registerHelper("year", () => (/* @__PURE__ */ new Date()).getFullYear());
16
- Handlebars.registerHelper(
17
- "join",
18
- (arr, sep) => Array.isArray(arr) ? arr.join(typeof sep === "string" ? sep : ", ") : ""
19
- );
20
- function getTemplatesDir() {
21
- const isBundled = __dirname.replace(/\\/g, "/").endsWith("/dist") || __dirname.replace(/\\/g, "/").includes("/dist/");
22
- const projectRoot = isBundled ? path.resolve(__dirname, "..") : path.resolve(__dirname, "..", "..");
23
- return path.resolve(projectRoot, "src", "templates");
24
- }
25
- async function createDir(dirPath) {
26
- await fs.ensureDir(dirPath);
27
- }
28
- async function writeFile(filePath, content) {
29
- await fs.ensureDir(path.dirname(filePath));
30
- await fs.writeFile(filePath, content, "utf-8");
31
- }
32
- async function copyFile(src, dest) {
33
- await fs.ensureDir(path.dirname(dest));
34
- await fs.copy(src, dest);
35
- }
36
- async function renderTemplate(templatePath, data) {
37
- const templateContent = await fs.readFile(templatePath, "utf-8");
38
- const template = Handlebars.compile(templateContent, { noEscape: true });
39
- return template(data);
40
- }
41
- async function renderAndWrite(templatePath, outputPath, data) {
42
- const content = await renderTemplate(templatePath, data);
43
- await writeFile(outputPath, content);
44
- }
45
- async function directoryExists(dirPath) {
46
- try {
47
- const stat = await fs.stat(dirPath);
48
- return stat.isDirectory();
49
- } catch {
50
- return false;
51
- }
52
- }
53
- async function fileExists(filePath) {
54
- try {
55
- const stat = await fs.stat(filePath);
56
- return stat.isFile();
57
- } catch {
58
- return false;
59
- }
60
- }
61
- function getOutputFileName(templateName) {
62
- return templateName.replace(/\.hbs$/, "");
63
- }
64
-
65
- export {
66
- getTemplatesDir,
67
- createDir,
68
- writeFile,
69
- copyFile,
70
- renderTemplate,
71
- renderAndWrite,
72
- directoryExists,
73
- fileExists,
74
- getOutputFileName
75
- };
76
- //# sourceMappingURL=chunk-2A65KFCS.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/utils/file.ts"],"sourcesContent":["import path from 'node:path';\nimport fs from 'fs-extra';\nimport Handlebars from 'handlebars';\nimport { fileURLToPath } from 'node:url';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\n// Register custom Handlebars helpers\nHandlebars.registerHelper('eq', (a: unknown, b: unknown) => a === b);\nHandlebars.registerHelper('neq', (a: unknown, b: unknown) => a !== b);\nHandlebars.registerHelper('or', (a: unknown, b: unknown) => a || b);\nHandlebars.registerHelper('and', (a: unknown, b: unknown) => a && b);\nHandlebars.registerHelper('lowercase', (str: string) => str?.toLowerCase());\nHandlebars.registerHelper('year', () => new Date().getFullYear());\nHandlebars.registerHelper('join', (arr: string[], sep: string) =>\n Array.isArray(arr) ? arr.join(typeof sep === 'string' ? sep : ', ') : '',\n);\n\nexport function getTemplatesDir(): string {\n // When bundled with tsup, __dirname is dist/ → go up 1 level to project root\n // When running unbundled (vitest), __dirname is src/utils/ → go up 2 levels to project root\n // In both cases, templates live at <projectRoot>/src/templates\n const isBundled = __dirname.replace(/\\\\/g, '/').endsWith('/dist') ||\n __dirname.replace(/\\\\/g, '/').includes('/dist/');\n const projectRoot = isBundled\n ? path.resolve(__dirname, '..')\n : path.resolve(__dirname, '..', '..');\n return path.resolve(projectRoot, 'src', 'templates');\n}\n\nexport async function createDir(dirPath: string): Promise<void> {\n await fs.ensureDir(dirPath);\n}\n\nexport async function writeFile(filePath: string, content: string): Promise<void> {\n await fs.ensureDir(path.dirname(filePath));\n await fs.writeFile(filePath, content, 'utf-8');\n}\n\nexport async function copyFile(src: string, dest: string): Promise<void> {\n await fs.ensureDir(path.dirname(dest));\n await fs.copy(src, dest);\n}\n\nexport async function renderTemplate(templatePath: string, data: object): Promise<string> {\n const templateContent = await fs.readFile(templatePath, 'utf-8');\n const template = Handlebars.compile(templateContent, { noEscape: true });\n return template(data);\n}\n\nexport async function renderAndWrite(\n templatePath: string,\n outputPath: string,\n data: object,\n): Promise<void> {\n const content = await renderTemplate(templatePath, data);\n await writeFile(outputPath, content);\n}\n\nexport async function directoryExists(dirPath: string): Promise<boolean> {\n try {\n const stat = await fs.stat(dirPath);\n return stat.isDirectory();\n } catch {\n return false;\n }\n}\n\nexport async function fileExists(filePath: string): Promise<boolean> {\n try {\n const stat = await fs.stat(filePath);\n return stat.isFile();\n } catch {\n return false;\n }\n}\n\nexport function getOutputFileName(templateName: string): string {\n return templateName.replace(/\\.hbs$/, '');\n}\n"],"mappings":";;;AAAA,OAAO,UAAU;AACjB,OAAO,QAAQ;AACf,OAAO,gBAAgB;AACvB,SAAS,qBAAqB;AAE9B,IAAM,aAAa,cAAc,YAAY,GAAG;AAChD,IAAM,YAAY,KAAK,QAAQ,UAAU;AAGzC,WAAW,eAAe,MAAM,CAAC,GAAY,MAAe,MAAM,CAAC;AACnE,WAAW,eAAe,OAAO,CAAC,GAAY,MAAe,MAAM,CAAC;AACpE,WAAW,eAAe,MAAM,CAAC,GAAY,MAAe,KAAK,CAAC;AAClE,WAAW,eAAe,OAAO,CAAC,GAAY,MAAe,KAAK,CAAC;AACnE,WAAW,eAAe,aAAa,CAAC,QAAgB,KAAK,YAAY,CAAC;AAC1E,WAAW,eAAe,QAAQ,OAAM,oBAAI,KAAK,GAAE,YAAY,CAAC;AAChE,WAAW;AAAA,EAAe;AAAA,EAAQ,CAAC,KAAe,QAChD,MAAM,QAAQ,GAAG,IAAI,IAAI,KAAK,OAAO,QAAQ,WAAW,MAAM,IAAI,IAAI;AACxE;AAEO,SAAS,kBAA0B;AAIxC,QAAM,YAAY,UAAU,QAAQ,OAAO,GAAG,EAAE,SAAS,OAAO,KAC9D,UAAU,QAAQ,OAAO,GAAG,EAAE,SAAS,QAAQ;AACjD,QAAM,cAAc,YAChB,KAAK,QAAQ,WAAW,IAAI,IAC5B,KAAK,QAAQ,WAAW,MAAM,IAAI;AACtC,SAAO,KAAK,QAAQ,aAAa,OAAO,WAAW;AACrD;AAEA,eAAsB,UAAU,SAAgC;AAC9D,QAAM,GAAG,UAAU,OAAO;AAC5B;AAEA,eAAsB,UAAU,UAAkB,SAAgC;AAChF,QAAM,GAAG,UAAU,KAAK,QAAQ,QAAQ,CAAC;AACzC,QAAM,GAAG,UAAU,UAAU,SAAS,OAAO;AAC/C;AAEA,eAAsB,SAAS,KAAa,MAA6B;AACvE,QAAM,GAAG,UAAU,KAAK,QAAQ,IAAI,CAAC;AACrC,QAAM,GAAG,KAAK,KAAK,IAAI;AACzB;AAEA,eAAsB,eAAe,cAAsB,MAA+B;AACxF,QAAM,kBAAkB,MAAM,GAAG,SAAS,cAAc,OAAO;AAC/D,QAAM,WAAW,WAAW,QAAQ,iBAAiB,EAAE,UAAU,KAAK,CAAC;AACvE,SAAO,SAAS,IAAI;AACtB;AAEA,eAAsB,eACpB,cACA,YACA,MACe;AACf,QAAM,UAAU,MAAM,eAAe,cAAc,IAAI;AACvD,QAAM,UAAU,YAAY,OAAO;AACrC;AAEA,eAAsB,gBAAgB,SAAmC;AACvE,MAAI;AACF,UAAM,OAAO,MAAM,GAAG,KAAK,OAAO;AAClC,WAAO,KAAK,YAAY;AAAA,EAC1B,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAsB,WAAW,UAAoC;AACnE,MAAI;AACF,UAAM,OAAO,MAAM,GAAG,KAAK,QAAQ;AACnC,WAAO,KAAK,OAAO;AAAA,EACrB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,kBAAkB,cAA8B;AAC9D,SAAO,aAAa,QAAQ,UAAU,EAAE;AAC1C;","names":[]}
@@ -1,24 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- copyFile,
4
- createDir,
5
- directoryExists,
6
- fileExists,
7
- getOutputFileName,
8
- getTemplatesDir,
9
- renderAndWrite,
10
- renderTemplate,
11
- writeFile
12
- } from "./chunk-2A65KFCS.js";
13
- export {
14
- copyFile,
15
- createDir,
16
- directoryExists,
17
- fileExists,
18
- getOutputFileName,
19
- getTemplatesDir,
20
- renderAndWrite,
21
- renderTemplate,
22
- writeFile
23
- };
24
- //# sourceMappingURL=file-5IKT7CEX.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}