mirror of
https://github.com/prdlk/jobyssey.git
synced 2026-11-08 07:57:39 +00:00
feat: add skills
This commit is contained in:
1 parent
6984212b17
commit
c50aa92862
150 files changed
+12702
No files matched your search
+103
@@ -0,0 +1,103 @@
|
||||
import { defineCommand, option } from "@bunli/core"
|
||||
import { z } from "zod"
|
||||
import { BASE_URL, htmlFetch, parseSearchPage, writeError, type JobCard } from "../helpers.js"
|
||||
|
||||
export const search = defineCommand({
|
||||
name: "search",
|
||||
description: "Search for job listings on Jobindex.dk",
|
||||
options: {
|
||||
query: option(z.string().optional(), {
|
||||
short: "q",
|
||||
description: "Keyword search query (e.g. python, grafisk designer)",
|
||||
}),
|
||||
page: option(z.coerce.number().int().min(1).default(1), {
|
||||
description: "Page number (1-indexed)",
|
||||
}),
|
||||
jobage: option(z.coerce.number().int().min(1).default(9999), {
|
||||
description: "Max age of posting in days: 1, 7, 14, 30, or 9999 (all)",
|
||||
}),
|
||||
sort: option(z.string().default("score"), {
|
||||
description: "Sort order: score (relevance) or date (newest first)",
|
||||
}),
|
||||
limit: option(z.coerce.number().int().min(1).optional(), {
|
||||
description: "Cap total results returned by the CLI (client-side)",
|
||||
}),
|
||||
format: option(z.enum(["json", "table", "plain"]).default("json"), {
|
||||
description: "Output format: json, table, plain",
|
||||
}),
|
||||
},
|
||||
handler: async ({ flags, signal }) => {
|
||||
if (!flags.query) {
|
||||
writeError("--query is required", "MISSING_REQUIRED")
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
if (signal.aborted) return
|
||||
|
||||
const params = new URLSearchParams({
|
||||
q: flags.query,
|
||||
page: String(flags.page),
|
||||
jobage: String(flags.jobage),
|
||||
sort: flags.sort,
|
||||
})
|
||||
|
||||
try {
|
||||
const html = await htmlFetch(`${BASE_URL}/jobsoegning?${params.toString()}`)
|
||||
|
||||
if (signal.aborted) return
|
||||
|
||||
const parsed = parseSearchPage(html)
|
||||
const total = parsed.total
|
||||
let results = parsed.results
|
||||
|
||||
if (flags.limit !== undefined) {
|
||||
results = results.slice(0, flags.limit)
|
||||
}
|
||||
|
||||
const output = {
|
||||
meta: {
|
||||
total,
|
||||
page: flags.page,
|
||||
perPage: 20,
|
||||
},
|
||||
results,
|
||||
}
|
||||
|
||||
if (flags.format === "json") {
|
||||
console.log(JSON.stringify(output, null, 2))
|
||||
} else if (flags.format === "table") {
|
||||
outputTable(results)
|
||||
} else {
|
||||
outputPlain(results)
|
||||
}
|
||||
} catch (err) {
|
||||
writeError(err instanceof Error ? err.message : String(err), "API_ERROR")
|
||||
process.exit(1)
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
function outputTable(results: JobCard[]): void {
|
||||
console.log("id title company location")
|
||||
for (const r of results) {
|
||||
const id = r.id.padEnd(11)
|
||||
const title = r.title.substring(0, 40).padEnd(40)
|
||||
const company = (r.company ?? "-").substring(0, 20).padEnd(20)
|
||||
const location = r.location ?? "-"
|
||||
console.log(`${id} ${title} ${company} ${location}`)
|
||||
}
|
||||
}
|
||||
|
||||
function outputPlain(results: JobCard[]): void {
|
||||
for (const r of results) {
|
||||
console.log(`id: ${r.id}`)
|
||||
console.log(`title: ${r.title}`)
|
||||
console.log(`company: ${r.company ?? "-"}`)
|
||||
console.log(`location: ${r.location ?? "-"}`)
|
||||
console.log(`date: ${r.date ?? "-"}`)
|
||||
console.log(`deadline: ${r.deadline ?? "-"}`)
|
||||
console.log(`url: ${r.url}`)
|
||||
if (r.description) console.log(`description: ${r.description}`)
|
||||
console.log("")
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user