OverviewFilesCommitsIssuesDocsReleasesPeers

hyper-note / lib / cli / commands / note.js

165 lines · javascript ref:
/**
 * hn note — Note management commands
 */

import fs from 'bare-fs'
import { HnClient } from '../client.js'
import { table, log, error, jsonOut } from '../output.js'

export async function noteCommand (subcommand, cmdArgs, flags) {
  const client = new HnClient(flags)

  switch (subcommand) {
    case 'list':
      return await listNotes(client, cmdArgs, flags)
    case 'create':
      return await createNote(client, cmdArgs, flags)
    case 'show':
      return await showNote(client, cmdArgs, flags)
    case 'edit':
      return await editNote(client, cmdArgs, flags)
    case 'delete':
      return await deleteNote(client, cmdArgs, flags)
    default:
      error(`Unknown note subcommand: ${subcommand || '(none)'}\nUsage: hn note [list|create|show|edit|delete]`)
  }
}

async function listNotes (client, cmdArgs, flags) {
  const notebook = cmdArgs[0]
  if (!notebook) {
    error('Usage: hn note list <notebook>')
  }

  let path = `/api/notebooks/${encodeURIComponent(notebook)}/notes`
  const params = []
  if (flags.limit) params.push(`limit=${flags.limit}`)
  if (flags.offset) params.push(`offset=${flags.offset}`)
  if (params.length) path += '?' + params.join('&')

  const notes = await client.get(path)

  if (flags.json) {
    jsonOut(notes)
    return
  }

  if (notes.length === 0) {
    log(`No notes in '${notebook}'.`)
    return
  }

  table(notes, [
    { key: 'id', label: 'ID', width: 16 },
    { key: 'title', label: 'TITLE', width: 40 },
    { key: 'tags', label: 'TAGS', width: 20 },
    { key: 'updatedAt', label: 'UPDATED', width: 20 }
  ])
}

async function createNote (client, cmdArgs, flags) {
  const notebook = cmdArgs[0]
  if (!notebook) {
    error('Usage: hn note create <notebook> --title "..." [--content "..." | --file path] [--tags "a,b"]')
  }

  if (!flags.title) {
    error('--title is required')
  }

  const body = { title: flags.title }

  if (flags.file) {
    body.content = fs.readFileSync(flags.file, 'utf-8')
  } else if (flags.content) {
    body.content = flags.content
  }

  if (flags.tags) {
    body.tags = flags.tags.split(',').map(t => t.trim()).filter(Boolean)
  }

  const note = await client.post(`/api/notebooks/${encodeURIComponent(notebook)}/notes`, body)

  if (flags.json) {
    jsonOut(note)
    return
  }

  log(`Created note: ${note.id} — ${note.title}`)
}

async function showNote (client, cmdArgs, flags) {
  const notebook = cmdArgs[0]
  const noteId = cmdArgs[1]
  if (!notebook || !noteId) {
    error('Usage: hn note show <notebook> <id>')
  }

  const note = await client.get(`/api/notebooks/${encodeURIComponent(notebook)}/notes/${encodeURIComponent(noteId)}`)

  if (flags.json) {
    jsonOut(note)
    return
  }

  log(`# ${note.title}`)
  if (note.tags && note.tags.length) {
    log(`Tags: ${note.tags.join(', ')}`)
  }
  log(`ID: ${note.id}  |  Updated: ${new Date(note.updatedAt).toLocaleString()}`)
  log('')
  log(note.content || '(empty)')
}

async function editNote (client, cmdArgs, flags) {
  const notebook = cmdArgs[0]
  const noteId = cmdArgs[1]
  if (!notebook || !noteId) {
    error('Usage: hn note edit <notebook> <id> [--title "..." | --content "..." | --file path | --tags "a,b"]')
  }

  const body = {}
  if (flags.title) body.title = flags.title
  if (flags.file) {
    body.content = fs.readFileSync(flags.file, 'utf-8')
  } else if (flags.content !== undefined) {
    body.content = flags.content
  }
  if (flags.tags !== undefined) {
    body.tags = flags.tags.split(',').map(t => t.trim()).filter(Boolean)
  }

  if (Object.keys(body).length === 0) {
    error('No updates specified. Use --title, --content, --file, or --tags.')
  }

  const note = await client.patch(`/api/notebooks/${encodeURIComponent(notebook)}/notes/${encodeURIComponent(noteId)}`, body)

  if (flags.json) {
    jsonOut(note)
    return
  }

  log(`Updated note: ${note.id} — ${note.title}`)
}

async function deleteNote (client, cmdArgs, flags) {
  const notebook = cmdArgs[0]
  const noteId = cmdArgs[1]
  if (!notebook || !noteId) {
    error('Usage: hn note delete <notebook> <id>')
  }

  const result = await client.del(`/api/notebooks/${encodeURIComponent(notebook)}/notes/${encodeURIComponent(noteId)}`)

  if (flags.json) {
    jsonOut(result)
    return
  }

  log(`Deleted note: ${noteId}`)
}

export default noteCommand