mirror of
				https://github.com/jackyzha0/quartz.git
				synced 2025-10-30 03:27:41 +01:00 
			
		
		
		
	feat: support CLI arguments for npx quartz create (#421)
				
					
				
			* feat(cli): add new args for content + link resolve
* feat(cli): validate cmd args
* feat(cli): add chalk + error code to errors
* feat(cli): support for setup/link via args
* refactor(cli): use yargs choices instead of manual
Scrap manual check if arguments are valid, use yargs "choices" field instead.
* feat(cli): add in-dir argument+ handle errors
add new "in-directory" argument, used if "setup" is "copy" or "symlink" to determine source. add error handling for invalid permutations of arguments or non existent path
* feat(cli): dynamically use cli or provided args
use "in-directory" arg as `originalFolder` if available, otherwise get it from manual cli process
* run format
* fix: use process.exit instead of return
* refactor: split CommonArgv and CreateArgv
* refactor(cli): rename create args, use ${} syntax
* fix(cli): fix link resolution strategy arg
* format
* feat(consistency): allow partial cmd args
			
			
This commit is contained in:
		
							parent
							
								
									74c3ebb7bd
								
							
						
					
					
						commit
						ad4145fb10
					
				| @ -43,6 +43,27 @@ const CommonArgv = { | ||||
|   }, | ||||
| } | ||||
| 
 | ||||
| const CreateArgv = { | ||||
|   ...CommonArgv, | ||||
|   source: { | ||||
|     string: true, | ||||
|     alias: ["s"], | ||||
|     describe: "source directory to copy/create symlink from", | ||||
|   }, | ||||
|   strategy: { | ||||
|     string: true, | ||||
|     alias: ["X"], | ||||
|     choices: ["new", "copy", "symlink"], | ||||
|     describe: "strategy for content folder setup", | ||||
|   }, | ||||
|   links: { | ||||
|     string: true, | ||||
|     alias: ["l"], | ||||
|     choices: ["absolute", "shortest", "relative"], | ||||
|     describe: "strategy to resolve links", | ||||
|   }, | ||||
| } | ||||
| 
 | ||||
| const SyncArgv = { | ||||
|   ...CommonArgv, | ||||
|   commit: { | ||||
| @ -147,24 +168,73 @@ yargs(hideBin(process.argv)) | ||||
|   .scriptName("quartz") | ||||
|   .version(version) | ||||
|   .usage("$0 <cmd> [args]") | ||||
|   .command("create", "Initialize Quartz", CommonArgv, async (argv) => { | ||||
|   .command("create", "Initialize Quartz", CreateArgv, async (argv) => { | ||||
|     console.log() | ||||
|     intro(chalk.bgGreen.black(` Quartz v${version} `)) | ||||
|     const contentFolder = path.join(cwd, argv.directory) | ||||
|     const setupStrategy = exitIfCancel( | ||||
|       await select({ | ||||
|         message: `Choose how to initialize the content in \`${contentFolder}\``, | ||||
|         options: [ | ||||
|           { value: "new", label: "Empty Quartz" }, | ||||
|           { value: "copy", label: "Copy an existing folder", hint: "overwrites `content`" }, | ||||
|           { | ||||
|             value: "symlink", | ||||
|             label: "Symlink an existing folder", | ||||
|             hint: "don't select this unless you know what you are doing!", | ||||
|           }, | ||||
|         ], | ||||
|       }), | ||||
|     ) | ||||
|     let setupStrategy = argv.strategy?.toLowerCase() | ||||
|     let linkResolutionStrategy = argv.links?.toLowerCase() | ||||
|     const sourceDirectory = argv.source | ||||
| 
 | ||||
|     // If all cmd arguments were provided, check if theyre valid
 | ||||
|     if (setupStrategy && linkResolutionStrategy) { | ||||
|       // If setup isn't, "new", source argument is required
 | ||||
|       if (setupStrategy !== "new") { | ||||
|         // Error handling
 | ||||
|         if (!sourceDirectory) { | ||||
|           outro( | ||||
|             chalk.red( | ||||
|               `Setup strategies (arg '${chalk.yellow( | ||||
|                 `-${CreateArgv.strategy.alias[0]}`, | ||||
|               )}') other than '${chalk.yellow( | ||||
|                 "new", | ||||
|               )}' require content folder argument ('${chalk.yellow( | ||||
|                 `-${CreateArgv.source.alias[0]}`, | ||||
|               )}') to be set`,
 | ||||
|             ), | ||||
|           ) | ||||
|           process.exit(1) | ||||
|         } else { | ||||
|           if (!fs.existsSync(sourceDirectory)) { | ||||
|             outro( | ||||
|               chalk.red( | ||||
|                 `Input directory to copy/symlink 'content' from not found ('${chalk.yellow( | ||||
|                   sourceDirectory, | ||||
|                 )}', invalid argument "${chalk.yellow(`-${CreateArgv.source.alias[0]}`)})`,
 | ||||
|               ), | ||||
|             ) | ||||
|             process.exit(1) | ||||
|           } else if (!fs.lstatSync(sourceDirectory).isDirectory()) { | ||||
|             outro( | ||||
|               chalk.red( | ||||
|                 `Source directory to copy/symlink 'content' from is not a directory (found file at '${chalk.yellow( | ||||
|                   sourceDirectory, | ||||
|                 )}', invalid argument ${chalk.yellow(`-${CreateArgv.source.alias[0]}`)}")`,
 | ||||
|               ), | ||||
|             ) | ||||
|             process.exit(1) | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     // Use cli process if cmd args werent provided
 | ||||
|     if (!setupStrategy) { | ||||
|       setupStrategy = exitIfCancel( | ||||
|         await select({ | ||||
|           message: `Choose how to initialize the content in \`${contentFolder}\``, | ||||
|           options: [ | ||||
|             { value: "new", label: "Empty Quartz" }, | ||||
|             { value: "copy", label: "Copy an existing folder", hint: "overwrites `content`" }, | ||||
|             { | ||||
|               value: "symlink", | ||||
|               label: "Symlink an existing folder", | ||||
|               hint: "don't select this unless you know what you are doing!", | ||||
|             }, | ||||
|           ], | ||||
|         }), | ||||
|       ) | ||||
|     } | ||||
| 
 | ||||
|     async function rmContentFolder() { | ||||
|       const contentStat = await fs.promises.lstat(contentFolder) | ||||
| @ -177,23 +247,28 @@ yargs(hideBin(process.argv)) | ||||
| 
 | ||||
|     await fs.promises.unlink(path.join(contentFolder, ".gitkeep")) | ||||
|     if (setupStrategy === "copy" || setupStrategy === "symlink") { | ||||
|       const originalFolder = escapePath( | ||||
|         exitIfCancel( | ||||
|           await text({ | ||||
|             message: "Enter the full path to existing content folder", | ||||
|             placeholder: | ||||
|               "On most terminal emulators, you can drag and drop a folder into the window and it will paste the full path", | ||||
|             validate(fp) { | ||||
|               const fullPath = escapePath(fp) | ||||
|               if (!fs.existsSync(fullPath)) { | ||||
|                 return "The given path doesn't exist" | ||||
|               } else if (!fs.lstatSync(fullPath).isDirectory()) { | ||||
|                 return "The given path is not a folder" | ||||
|               } | ||||
|             }, | ||||
|           }), | ||||
|         ), | ||||
|       ) | ||||
|       let originalFolder = sourceDirectory | ||||
| 
 | ||||
|       // If input directory was not passed, use cli
 | ||||
|       if (!sourceDirectory) { | ||||
|         originalFolder = escapePath( | ||||
|           exitIfCancel( | ||||
|             await text({ | ||||
|               message: "Enter the full path to existing content folder", | ||||
|               placeholder: | ||||
|                 "On most terminal emulators, you can drag and drop a folder into the window and it will paste the full path", | ||||
|               validate(fp) { | ||||
|                 const fullPath = escapePath(fp) | ||||
|                 if (!fs.existsSync(fullPath)) { | ||||
|                   return "The given path doesn't exist" | ||||
|                 } else if (!fs.lstatSync(fullPath).isDirectory()) { | ||||
|                   return "The given path is not a folder" | ||||
|                 } | ||||
|               }, | ||||
|             }), | ||||
|           ), | ||||
|         ) | ||||
|       } | ||||
| 
 | ||||
|       await rmContentFolder() | ||||
|       if (setupStrategy === "copy") { | ||||
| @ -217,29 +292,32 @@ See the [documentation](https://quartz.jzhao.xyz) for how to get started. | ||||
|       ) | ||||
|     } | ||||
| 
 | ||||
|     // get a preferred link resolution strategy
 | ||||
|     const linkResolutionStrategy = exitIfCancel( | ||||
|       await select({ | ||||
|         message: `Choose how Quartz should resolve links in your content. You can change this later in \`quartz.config.ts\`.`, | ||||
|         options: [ | ||||
|           { | ||||
|             value: "absolute", | ||||
|             label: "Treat links as absolute path", | ||||
|             hint: "for content made for Quartz 3 and Hugo", | ||||
|           }, | ||||
|           { | ||||
|             value: "shortest", | ||||
|             label: "Treat links as shortest path", | ||||
|             hint: "for most Obsidian vaults", | ||||
|           }, | ||||
|           { | ||||
|             value: "relative", | ||||
|             label: "Treat links as relative paths", | ||||
|             hint: "for just normal Markdown files", | ||||
|           }, | ||||
|         ], | ||||
|       }), | ||||
|     ) | ||||
|     // Use cli process if cmd args werent provided
 | ||||
|     if (!linkResolutionStrategy) { | ||||
|       // get a preferred link resolution strategy
 | ||||
|       linkResolutionStrategy = exitIfCancel( | ||||
|         await select({ | ||||
|           message: `Choose how Quartz should resolve links in your content. You can change this later in \`quartz.config.ts\`.`, | ||||
|           options: [ | ||||
|             { | ||||
|               value: "absolute", | ||||
|               label: "Treat links as absolute path", | ||||
|               hint: "for content made for Quartz 3 and Hugo", | ||||
|             }, | ||||
|             { | ||||
|               value: "shortest", | ||||
|               label: "Treat links as shortest path", | ||||
|               hint: "for most Obsidian vaults", | ||||
|             }, | ||||
|             { | ||||
|               value: "relative", | ||||
|               label: "Treat links as relative paths", | ||||
|               hint: "for just normal Markdown files", | ||||
|             }, | ||||
|           ], | ||||
|         }), | ||||
|       ) | ||||
|     } | ||||
| 
 | ||||
|     // now, do config changes
 | ||||
|     const configFilePath = path.join(cwd, "quartz.config.ts") | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Ben Schlegel
						Ben Schlegel