mirror of
https://github.com/MadsLorentzen/ai-job-search.git
synced 2026-09-17 16:46:24 +00:00
58 lines
1.7 KiB
TypeScript
58 lines
1.7 KiB
TypeScript
import { DETAIL_URL, htmlFetch, parseJobDetail, writeError } from "../helpers.js"
|
|||
|
|
|
||
|
|
export interface DetailOpts {
|
||
|
|
id: string
|
||
|
|
format: "json" | "plain"
|
||
|
|
}
|
||
|
|
|
||
|
|
/** Accept a raw job ID, a job-view URL, or a job URN. */
|
||
|
|
function normalizeId(input: string): string | null {
|
||
|
|
const urn = input.match(/urn:li:jobPosting:(\d+)/)
|
||
|
|
if (urn) return urn[1]
|
||
|
|
const url = input.match(/-(\d{6,})(?:\?|$)/) || input.match(/\/(\d{6,})(?:\?|$)/)
|
||
|
|
if (url) return url[1]
|
||
|
|
const bare = input.match(/^\d{6,}$/)
|
||
|
|
if (bare) return input
|
||
|
|
return null
|
||
|
|
}
|
||
|
|
|
||
|
|
export async function runDetail(opts: DetailOpts): Promise<number> {
|
||
|
|
const id = normalizeId(opts.id)
|
||
|
|
if (!id) {
|
||
|
|
writeError(`Could not parse a job ID from "${opts.id}"`, "BAD_ID")
|
||
|
|
return 1
|
||
|
|
}
|
||
|
|
try {
|
||
|
|
const html = await htmlFetch(`${DETAIL_URL}/${id}`)
|
||
|
|
if (!html) {
|
||
|
|
writeError("Job not found", "NOT_FOUND")
|
||
|
|
return 1
|
||
|
|
}
|
||
|
|
const job = parseJobDetail(html, id)
|
||
|
|
|
||
|
|
if (opts.format === "plain") {
|
||
|
|
const lines = [
|
||
|
|
job.title,
|
||
|
|
`${job.company || "—"} · ${job.location || "—"}`,
|
||
|
|
"",
|
||
|
|
job.seniority ? `Seniority: ${job.seniority}` : "",
|
||
|
|
job.employmentType ? `Employment: ${job.employmentType}` : "",
|
||
|
|
job.jobFunction ? `Function: ${job.jobFunction}` : "",
|
||
|
|
job.industries ? `Industries: ${job.industries}` : "",
|
||
|
|
"",
|
||
|
|
job.description || "(no description)",
|
||
|
|
"",
|
||
|
|
`URL: ${job.url}`,
|
||
|
|
job.applyUrl ? `Apply: ${job.applyUrl}` : "",
|
||
|
|
].filter((l) => l !== "")
|
||
|
|
process.stdout.write(lines.join("\n") + "\n")
|
||
|
|
} else {
|
||
|
|
process.stdout.write(JSON.stringify(job, null, 2) + "\n")
|
||
|
|
}
|
||
|
|
return 0
|
||
|
|
} catch (e) {
|
||
|
|
writeError(e instanceof Error ? e.message : String(e), "DETAIL_FAILED")
|
||
|
|
return 1
|
||
|
|
}
|
||
|
|
}
|