mirror of
https://github.com/MadsLorentzen/ai-job-search.git
synced 2026-09-17 16:46:24 +00:00
fix(jobbank): parse JobPosting entries nested in JSON-LD @graph (#190)
Extracts the JSON-LD JobPosting lookup into a recursive parseJobPostingJsonLd helper that handles top-level objects, arrays, and @graph wrappers (including nested combinations), keeps skipping malformed scripts, and covers all four cases with network-free Bun tests. By @luochen211. Closes #189.
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
import { defineCommand, option } from "@bunli/core"
|
||||
import { z } from "zod"
|
||||
import { fetchWithUA, writeError, BASE_URL } from "../helpers.js"
|
||||
import { parse as parseHtml } from "node-html-parser"
|
||||
import { fetchWithUA, parseJobPostingJsonLd, writeError, BASE_URL } from "../helpers.js"
|
||||
|
||||
export const detail = defineCommand({
|
||||
name: "detail",
|
||||
@@ -39,31 +38,7 @@ export const detail = defineCommand({
|
||||
|
||||
if (signal.aborted) return
|
||||
|
||||
const root = parseHtml(html)
|
||||
|
||||
// Find all <script type="application/ld+json"> tags
|
||||
const scripts = root.querySelectorAll('script[type="application/ld+json"]')
|
||||
let jobPosting: Record<string, unknown> | null = null
|
||||
|
||||
for (const script of scripts) {
|
||||
try {
|
||||
const json = JSON.parse(script.text)
|
||||
if (json["@type"] === "JobPosting") {
|
||||
jobPosting = json
|
||||
break
|
||||
}
|
||||
// Could be an array
|
||||
if (Array.isArray(json)) {
|
||||
const found = json.find((item) => item["@type"] === "JobPosting")
|
||||
if (found) {
|
||||
jobPosting = found
|
||||
break
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// not valid JSON — skip
|
||||
}
|
||||
}
|
||||
const jobPosting = parseJobPostingJsonLd(html)
|
||||
|
||||
if (!jobPosting) {
|
||||
writeError("No JSON-LD found on job page", "PARSE_ERROR")
|
||||
|
||||
Reference in New Issue
Block a user