Ben Schlegel
2023-08-26 ad4145fb10dbf32d8f99e1de555339dba0979f72
quartz/bootstrap-cli.mjs
@@ -43,6 +43,27 @@
  },
}
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 @@
  .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 @@
    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 @@
      )
    }
    // 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")