@codefast/cli 0.3.1-canary.10 → 0.3.1-canary.12

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/CHANGELOG.md CHANGED
@@ -1,5 +1,27 @@
1
1
  # @codefast/cli
2
2
 
3
+ ## 0.3.1-canary.12
4
+
5
+ ### Patch Changes
6
+
7
+ - [`0841266`](https://github.com/codefastlabs/codefast/commit/0841266536570b017099fd32b6f0b732cc562932) Thanks [@thevuong](https://github.com/thevuong)! - fix(cli): remove redundant default action from CLI
8
+
9
+ - [`5d33972`](https://github.com/codefastlabs/codefast/commit/5d339720048479b37ce3ded253d5182364df6762) Thanks [@thevuong](https://github.com/thevuong)! - refactor(cli): update styles and constants for project creation
10
+
11
+ - [`109a2a5`](https://github.com/codefastlabs/codefast/commit/109a2a5cf4a205d4c5ceb5c3ac7afa95ca69a51d) Thanks [@thevuong](https://github.com/thevuong)! - feat(cli): improve ReactNode handling and RootLayout typings
12
+
13
+ - [`e873ddc`](https://github.com/codefastlabs/codefast/commit/e873ddcdabb110655e39aa7a69a0850c9050186e) Thanks [@thevuong](https://github.com/thevuong)! - refactor(cli): centralize file operations and error handling
14
+
15
+ ## 0.3.1-canary.11
16
+
17
+ ### Patch Changes
18
+
19
+ - [`6b32857`](https://github.com/codefastlabs/codefast/commit/6b32857abb5960c780a46a642b114a2f459cbb4c) Thanks [@thevuong](https://github.com/thevuong)! - feat(cli): add support for optimizePackageImports in Next.js config
20
+
21
+ - [`b33cd3c`](https://github.com/codefastlabs/codefast/commit/b33cd3c893c16861d70e25476973a2b6973a3736) Thanks [@thevuong](https://github.com/thevuong)! - feat(cli): enhance project setup with Prettier ignore support
22
+
23
+ - [`6acb04b`](https://github.com/codefastlabs/codefast/commit/6acb04b3d8efaeb17a0a4944652f76b21b59ffcb) Thanks [@thevuong](https://github.com/thevuong)! - refactor(cli): adjust comment formatting in config-files.ts
24
+
3
25
  ## 0.3.1-canary.10
4
26
 
5
27
  ### Patch Changes
package/dist/index.cjs CHANGED
@@ -49,9 +49,38 @@ function runCommand(command) {
49
49
  stdio: "inherit"
50
50
  });
51
51
  }
52
- function writeConfigFile(filePath, content) {
53
- external_node_fs_default().writeFileSync(filePath, content);
54
- console.log(`šŸ“ Created ${filePath}`);
52
+ const FileUtils = {
53
+ exists (filePath) {
54
+ return external_node_fs_default().existsSync(filePath);
55
+ },
56
+ readFile (filePath) {
57
+ try {
58
+ return external_node_fs_default().readFileSync(filePath, "utf8");
59
+ } catch (error) {
60
+ throw new Error(`Failed to read file ${filePath}: ${getErrorMessage(error)}`);
61
+ }
62
+ },
63
+ writeFile (filePath, content) {
64
+ try {
65
+ external_node_fs_default().writeFileSync(filePath, content);
66
+ } catch (error) {
67
+ throw new Error(`Failed to write to file ${filePath}: ${getErrorMessage(error)}`);
68
+ }
69
+ },
70
+ writeConfigFile (filePath, content) {
71
+ external_node_fs_default().writeFileSync(filePath, content);
72
+ console.log(`šŸ“ Created ${filePath}`);
73
+ },
74
+ validatePath (filePath, filename) {
75
+ if (!this.exists(filePath)) {
76
+ console.warn(`āš ļø ${filename} not found, skipping update.`);
77
+ return false;
78
+ }
79
+ return true;
80
+ }
81
+ };
82
+ function getErrorMessage(error) {
83
+ return error instanceof Error ? error.message : "Unknown error occurred";
55
84
  }
56
85
  function validateProjectName(name) {
57
86
  if (!name || /^\s*$/.test(name)) return {
@@ -274,6 +303,24 @@ indent_style = tab
274
303
  indent_size = 4
275
304
  `,
276
305
  description: "Editor configuration for source code formatting"
306
+ },
307
+ {
308
+ path: ".prettierignore",
309
+ content: `# changesets
310
+ .changeset
311
+
312
+ # debug
313
+ npm-debug.log*
314
+ yarn-debug.log*
315
+ yarn-error.log*
316
+ .pnpm-debug.log*
317
+
318
+ # lock files
319
+ package-lock.json
320
+ yarn.lock
321
+ pnpm-lock.yaml
322
+ `,
323
+ description: ""
277
324
  }
278
325
  ],
279
326
  linting: [
@@ -297,6 +344,7 @@ export default config;
297
344
  {
298
345
  path: "eslint.config.mjs",
299
346
  content: `import { config } from "@codefast/eslint-config/next";
347
+
300
348
  /**
301
349
  * @see https://eslint.org/docs/latest/use/configure/configuration-files
302
350
  * @type {import('eslint').Linter.Config[]}
@@ -371,6 +419,7 @@ export const fontVariables = cn(fontGeistSans.variable, fontGeistMono.variable);
371
419
  :root {
372
420
  --font-sans: var(--font-geist-sans);
373
421
  --font-mono: var(--font-geist-mono);
422
+
374
423
  --input: var(--color-neutral-200);
375
424
  --border: var(--color-neutral-200);
376
425
  --ring: var(--color-neutral-400);
@@ -404,6 +453,7 @@ export const fontVariables = cn(fontGeistSans.variable, fontGeistMono.variable);
404
453
  --chart-4: var(--color-amber-600);
405
454
  --chart-5: var(--color-amber-500);
406
455
  }
456
+
407
457
  .dark {
408
458
  --input: var(--color-neutral-700);
409
459
  --border: --alpha(var(--color-neutral-700) / 50%);
@@ -444,68 +494,86 @@ export const fontVariables = cn(fontGeistSans.variable, fontGeistMono.variable);
444
494
  }
445
495
  ]
446
496
  };
497
+ function updateFileIfNeeded(filePath, filename, checkFn, updateFn, successMessage, alreadyUpdatedMessage) {
498
+ if (!FileUtils.validatePath(filePath, filename)) return;
499
+ const content = FileUtils.readFile(filePath);
500
+ if (checkFn(content)) return void console.log(`šŸ“ ${alreadyUpdatedMessage}`);
501
+ try {
502
+ const updatedContent = updateFn(content);
503
+ FileUtils.writeFile(filePath, updatedContent);
504
+ console.log(`šŸ“ ${successMessage}`);
505
+ } catch (error) {
506
+ console.warn(`āš ļø Failed to update ${filename}: ${getErrorMessage(error)}`);
507
+ }
508
+ }
447
509
  function updatePostcssConfig(projectDir) {
448
510
  const postcssConfigPath = external_node_path_default().join(projectDir, "postcss.config.mjs");
449
- if (!external_node_fs_default().existsSync(postcssConfigPath)) return void console.warn(`āš ļø postcss.config.mjs not found, skipping update.`);
450
- let content = external_node_fs_default().readFileSync(postcssConfigPath, "utf8");
451
511
  const typeComment = `/** @type {import('postcss-load-config').Config} */\n`;
452
- if (content.includes(typeComment)) console.log(`šŸ“ postcss.config.mjs already contains type comment, no changes made.`);
453
- else {
454
- content = content.replace("const config = {", `${typeComment}const config = {`);
455
- external_node_fs_default().writeFileSync(postcssConfigPath, content);
456
- console.log(`šŸ“ Updated postcss.config.mjs with type comment.`);
457
- }
512
+ updateFileIfNeeded(postcssConfigPath, "postcss.config.mjs", (content)=>content.includes(typeComment), (content)=>content.replace("const config = {", `${typeComment}const config = {`), "Updated postcss.config.mjs with type comment.", "postcss.config.mjs already contains type comment, no changes made.");
458
513
  }
459
514
  function updateLayoutFile(projectDir) {
460
515
  const layoutPath = external_node_path_default().join(projectDir, "src/app/layout.tsx");
461
- if (!external_node_fs_default().existsSync(layoutPath)) return void console.warn(`āš ļø src/app/layout.tsx not found, skipping update.`);
462
- let content = external_node_fs_default().readFileSync(layoutPath, "utf8");
463
- if (content.includes('<html className={cn(fontVariables, "antialiased")} lang="en">')) return void console.log(`šŸ“ src/app/layout.tsx already uses fontVariables in html tag, no changes made.`);
464
- const newImports = `import type { Metadata } from "next";
465
-
516
+ const htmlTarget = '<html className={cn(fontVariables, "antialiased")} lang="en">';
517
+ updateFileIfNeeded(layoutPath, "src/app/layout.tsx", (content)=>content.includes(htmlTarget), (content)=>{
518
+ const newImports = `import type { Metadata } from "next";
519
+ import type { JSX, ReactNode } from "react";
466
520
  import { cn } from "@codefast/ui";
467
-
468
521
  import { fontVariables } from "@/lib/fonts";
469
522
  import "@/app/globals.css";`;
470
- content = content.replaceAll(/import\s+{[^}]+}\s+from\s+["']next\/font\/google["'];\s*/g, "");
471
- content = content.replace(/const\s+geistSans\s*=[^;]+;\s*const\s+geistMono\s*=[^;]+;\s*/, "");
472
- content = content.replace(/import\s+type\s+{[^}]+}\s+from\s+["']next["'];\s*import\s+["']\.\/globals\.css["'];\s*/, newImports);
473
- const htmlRegex = /<html\s+lang="en"\s*>/;
474
- const newHtml = '<html className={cn(fontVariables, "antialiased")} lang="en">';
475
- content = content.replace(htmlRegex, newHtml);
476
- const bodyRegex = /<body\s+className={`[^`]*`}\s*>/;
477
- const newBody = "<body>";
478
- content = content.replace(bodyRegex, newBody);
523
+ let result = content;
524
+ result = result.replaceAll(/import\s+{[^}]+}\s+from\s+["']next\/font\/google["'];\s*/g, "");
525
+ result = result.replace(/const\s+geistSans\s*=[^;]+;\s*const\s+geistMono\s*=[^;]+;\s*/, "");
526
+ result = result.replace(/import\s+type\s+{[^}]+}\s+from\s+["']next["'];\s*import\s+["']\.\/globals\.css["'];\s*/, newImports);
527
+ result = result.replace(/export default function RootLayout\({\s*children,\s*}\s*:\s*Readonly<{\s*children:\s*React\.ReactNode;\s*}>\)\s*{/, "export default function RootLayout({ children }: Readonly<{ children: ReactNode }>): JSX.Element {");
528
+ result = result.replace(/<html\s+lang="en"\s*>/, htmlTarget);
529
+ result = result.replace(/<body\s+className={`[^`]*`}\s*>/, "<body>");
530
+ return result;
531
+ }, "Updated src/app/layout.tsx to use fontVariables in html tag, removed className from body, modified ReactNode import, and added return type to RootLayout", "src/app/layout.tsx already uses fontVariables in html tag, no changes made.");
532
+ }
533
+ function updatePackageJson(projectDir) {
534
+ const packageJsonPath = external_node_path_default().join(projectDir, "package.json");
535
+ if (!FileUtils.validatePath(packageJsonPath, "package.json")) return;
479
536
  try {
480
- external_node_fs_default().writeFileSync(layoutPath, content);
481
- console.log(`šŸ“ Updated src/app/layout.tsx to use fontVariables in html tag and removed className from body`);
537
+ const packageJson = JSON.parse(FileUtils.readFile(packageJsonPath));
538
+ packageJson.scripts = {
539
+ ...packageJson.scripts,
540
+ "deploy:preview": "vercel deploy --archive=tgz",
541
+ "deploy:prod": "vercel deploy --archive=tgz --prod",
542
+ format: "prettier --write --ignore-unknown .",
543
+ "format:check": "prettier --check --ignore-unknown .",
544
+ lint: "next lint --fix --max-warnings 0",
545
+ "lint:check": "next lint --max-warnings 0",
546
+ "package:install": "pnpm install",
547
+ "package:outdated": "pnpm outdated",
548
+ "package:upgrade": "pnpm update --latest",
549
+ preview: "pnpm build && pnpm start"
550
+ };
551
+ packageJson["simple-git-hooks"] = {
552
+ "pre-commit": "pnpm lint-staged",
553
+ "commit-msg": "pnpm commitlint --edit"
554
+ };
555
+ FileUtils.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));
556
+ console.log(`šŸ“ Updated package.json`);
482
557
  } catch (error) {
483
- const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
484
- console.warn(`āš ļø Failed to update src/app/layout.tsx: ${errorMessage}`);
558
+ console.warn(`āš ļø Failed to update package.json: ${getErrorMessage(error)}`);
485
559
  }
486
560
  }
487
- function updatePackageJson(projectDir) {
488
- const packageJsonPath = external_node_path_default().join(projectDir, "package.json");
489
- const packageJson = JSON.parse(external_node_fs_default().readFileSync(packageJsonPath, "utf8"));
490
- packageJson.scripts = {
491
- ...packageJson.scripts,
492
- "deploy:preview": "vercel deploy --archive=tgz",
493
- "deploy:prod": "vercel deploy --archive=tgz --prod",
494
- format: "prettier --write --ignore-unknown",
495
- "format:check": "prettier --check --ignore-unknown",
496
- lint: "next lint --fix --max-warnings 0",
497
- "lint:check": "next lint --max-warnings 0",
498
- "package:install": "pnpm install",
499
- "package:outdated": "pnpm outdated",
500
- "package:upgrade": "pnpm update --latest",
501
- preview: "pnpm build && pnpm start"
502
- };
503
- packageJson["simple-git-hooks"] = {
504
- "pre-commit": "pnpm lint-staged",
505
- "commit-msg": "pnpm commitlint --edit"
506
- };
507
- external_node_fs_default().writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
508
- console.log(`šŸ“ Updated package.json`);
561
+ function updateNextConfig(projectDir) {
562
+ const nextConfigPath = external_node_path_default().join(projectDir, "next.config.ts");
563
+ const optimizePackagesConfig = 'optimizePackageImports: ["@codefast/ui"]';
564
+ updateFileIfNeeded(nextConfigPath, "next.config.ts", (content)=>content.includes(optimizePackagesConfig), (content)=>content.replace(/const nextConfig: NextConfig = \{/, `const nextConfig: NextConfig = {
565
+ experimental: {
566
+ optimizePackageImports: ["@codefast/ui"],
567
+ },`), "Updated next.config.ts with optimizePackageImports configuration.", "next.config.ts already contains optimizePackageImports configuration, no changes made.");
568
+ }
569
+ function updatePageFile(projectDir) {
570
+ const pagePath = external_node_path_default().join(projectDir, "src/app/page.tsx");
571
+ updateFileIfNeeded(pagePath, "src/app/page.tsx", (content)=>content.includes("): JSX.Element"), (content)=>{
572
+ let result = content;
573
+ if (!result.includes("import type { JSX }")) result = result.includes("import type {") ? result.replace(/import type {(?<types>[^}]+)} from "react";/, 'import type {$1, JSX } from "react";') : result.includes("import {") ? result.replace(/import {/, 'import type { JSX } from "react";\n\nimport {') : `import type { JSX } from "react";\n\n${result}`;
574
+ result = result.replace(/export default function Home\(\) {/, "export default function Home(): JSX.Element {");
575
+ return result;
576
+ }, "Updated src/app/page.tsx to add JSX.Element return type to Home component", "src/app/page.tsx already has JSX.Element return type, no changes made.");
509
577
  }
510
578
  function createConfigFiles(projectDir) {
511
579
  console.log(`\nšŸ“ Creating configuration files...`);
@@ -514,10 +582,10 @@ function createConfigFiles(projectDir) {
514
582
  for (const { path: filePath, content, description } of configs){
515
583
  const fullPath = external_node_path_default().join(projectDir, filePath);
516
584
  const dir = external_node_path_default().dirname(fullPath);
517
- if (!external_node_fs_default().existsSync(dir)) external_node_fs_default().mkdirSync(dir, {
585
+ if (!FileUtils.exists(dir)) external_node_fs_default().mkdirSync(dir, {
518
586
  recursive: true
519
587
  });
520
- writeConfigFile(fullPath, content);
588
+ FileUtils.writeConfigFile(fullPath, content);
521
589
  if (description) console.log(` ā„¹ļø ${filePath}: ${description}`);
522
590
  }
523
591
  }
@@ -536,8 +604,7 @@ function cleanupPackages() {
536
604
  try {
537
605
  packageJson = JSON.parse(external_node_fs_namespaceObject.readFileSync(packageJsonPath, "utf8"));
538
606
  } catch (error) {
539
- const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
540
- console.warn(`āš ļø Error reading package.json: ${errorMessage}, skipping cleanup.`);
607
+ console.warn(`āš ļø Error reading package.json: ${getErrorMessage(error)}, skipping cleanup.`);
541
608
  return;
542
609
  }
543
610
  const dependencies = packageJson.dependencies ?? {};
@@ -573,15 +640,19 @@ function createProjectCommand(program) {
573
640
  console.log(`šŸ“‚ Moved to ${projectName}`);
574
641
  }
575
642
  updateLayoutFile(process.cwd());
643
+ updatePageFile(process.cwd());
576
644
  updatePostcssConfig(process.cwd());
577
645
  installDependencies();
578
646
  cleanupPackages();
579
647
  createConfigFiles(process.cwd());
648
+ updateNextConfig(process.cwd());
580
649
  updatePackageJson(process.cwd());
581
650
  console.log(`\nšŸ”„ Activating git hooks...`);
582
651
  runCommand("pnpm simple-git-hooks");
583
652
  console.log(`\nšŸ“ Formatting files with Prettier...`);
584
653
  runCommand("pnpm format");
654
+ console.log(`\nšŸ” Running ESLint to check code style...`);
655
+ runCommand("pnpm lint");
585
656
  console.log(`\nāœ… Project ${packageJsonExists ? "configured" : "created"} successfully!`);
586
657
  console.log(`- Project: ${projectName}`);
587
658
  console.log("- Next.js with TypeScript");
@@ -592,8 +663,7 @@ function createProjectCommand(program) {
592
663
  console.log(`\nšŸš€ To start development:`);
593
664
  console.log(`cd ${projectName} && pnpm dev`);
594
665
  } catch (error) {
595
- const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
596
- console.error(`\nāŒ An error occurred: ${errorMessage}`);
666
+ console.error(`\nāŒ An error occurred: ${getErrorMessage(error)}`);
597
667
  process.exit(1);
598
668
  } finally{
599
669
  rl.close();
@@ -732,7 +802,7 @@ const EXPORTS_PREVIEW_FILE = "exports-preview.json";
732
802
  const EXPORTS_ANALYSIS_FILE = "exports-analysis.json";
733
803
  const ENCODING = "utf8";
734
804
  const JSON_INDENT = 2;
735
- const FileUtils = {
805
+ const file_utils_FileUtils = {
736
806
  exists (filePath) {
737
807
  return external_node_fs_default().existsSync(filePath);
738
808
  },
@@ -770,19 +840,19 @@ const FileUtils = {
770
840
  }
771
841
  };
772
842
  function fileExists(filePath) {
773
- return FileUtils.exists(filePath);
843
+ return file_utils_FileUtils.exists(filePath);
774
844
  }
775
845
  function readPackageJson(filePath) {
776
- return FileUtils.readJsonFile(filePath);
846
+ return file_utils_FileUtils.readJsonFile(filePath);
777
847
  }
778
848
  function backupPackageJson(filePath) {
779
849
  try {
780
850
  const content = external_node_fs_default().readFileSync(filePath, ENCODING);
781
851
  const dir = external_node_path_default().dirname(filePath);
782
852
  const backupDir = external_node_path_default().join(dir, EXPORTS_ANALYSIS_DIR);
783
- FileUtils.ensureDirectoryExists(backupDir);
853
+ file_utils_FileUtils.ensureDirectoryExists(backupDir);
784
854
  const baseName = external_node_path_default().basename(filePath);
785
- const backupPath = external_node_path_default().join(backupDir, FileUtils.createBackupFilename(baseName));
855
+ const backupPath = external_node_path_default().join(backupDir, file_utils_FileUtils.createBackupFilename(baseName));
786
856
  external_node_fs_default().writeFileSync(backupPath, content, ENCODING);
787
857
  return true;
788
858
  } catch (error) {
@@ -791,11 +861,11 @@ function backupPackageJson(filePath) {
791
861
  }
792
862
  }
793
863
  function savePackageJson(filePath, content) {
794
- return FileUtils.writeJsonFile(filePath, content);
864
+ return file_utils_FileUtils.writeJsonFile(filePath, content);
795
865
  }
796
866
  function saveJsonToFile(packageDir, fileName, content) {
797
- const outputDir = FileUtils.getAnalysisDir(packageDir);
798
- FileUtils.writeJsonFile(external_node_path_default().join(outputDir, fileName), content);
867
+ const outputDir = file_utils_FileUtils.getAnalysisDir(packageDir);
868
+ file_utils_FileUtils.writeJsonFile(external_node_path_default().join(outputDir, fileName), content);
799
869
  }
800
870
  function saveExportsAnalysis(packageDir, analysis) {
801
871
  saveJsonToFile(packageDir, EXPORTS_ANALYSIS_FILE, analysis);
@@ -955,12 +1025,6 @@ function main() {
955
1025
  program.name("codefast").description("CodeFast CLI - A development toolkit for CodeFast.").version(getPackageVersion(), "-v, --version", "display CLI version");
956
1026
  createUpdateExportsCommand(program);
957
1027
  createProjectCommand(program);
958
- program.action(()=>{
959
- console.log('Use "codefast create-project" to create a new Next.js project.');
960
- console.log('Use "codefast update-exports" to update exports.');
961
- console.log('Run "codefast --help" to see all available commands.');
962
- program.help();
963
- });
964
1028
  program.parse(process.argv);
965
1029
  }
966
1030
  main();