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:
		@@ -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,11 +168,59 @@ 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(
 | 
			
		||||
    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: [
 | 
			
		||||
@@ -165,6 +234,7 @@ yargs(hideBin(process.argv))
 | 
			
		||||
          ],
 | 
			
		||||
        }),
 | 
			
		||||
      )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async function rmContentFolder() {
 | 
			
		||||
      const contentStat = await fs.promises.lstat(contentFolder)
 | 
			
		||||
@@ -177,7 +247,11 @@ yargs(hideBin(process.argv))
 | 
			
		||||
 | 
			
		||||
    await fs.promises.unlink(path.join(contentFolder, ".gitkeep"))
 | 
			
		||||
    if (setupStrategy === "copy" || setupStrategy === "symlink") {
 | 
			
		||||
      const originalFolder = escapePath(
 | 
			
		||||
      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",
 | 
			
		||||
@@ -194,6 +268,7 @@ yargs(hideBin(process.argv))
 | 
			
		||||
            }),
 | 
			
		||||
          ),
 | 
			
		||||
        )
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      await rmContentFolder()
 | 
			
		||||
      if (setupStrategy === "copy") {
 | 
			
		||||
@@ -217,8 +292,10 @@ See the [documentation](https://quartz.jzhao.xyz) for how to get started.
 | 
			
		||||
      )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Use cli process if cmd args werent provided
 | 
			
		||||
    if (!linkResolutionStrategy) {
 | 
			
		||||
      // get a preferred link resolution strategy
 | 
			
		||||
    const linkResolutionStrategy = exitIfCancel(
 | 
			
		||||
      linkResolutionStrategy = exitIfCancel(
 | 
			
		||||
        await select({
 | 
			
		||||
          message: `Choose how Quartz should resolve links in your content. You can change this later in \`quartz.config.ts\`.`,
 | 
			
		||||
          options: [
 | 
			
		||||
@@ -240,6 +317,7 @@ See the [documentation](https://quartz.jzhao.xyz) for how to get started.
 | 
			
		||||
          ],
 | 
			
		||||
        }),
 | 
			
		||||
      )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // now, do config changes
 | 
			
		||||
    const configFilePath = path.join(cwd, "quartz.config.ts")
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user