feat: add support for indicating workplaceTypes (#296)

This commit is contained in:
Ryan Foote
2026-03-21 20:43:43 +00:00
committed by GitHub
parent 8274ec4e14
commit 0b22c08d7d
25 changed files with 497 additions and 5 deletions
+3
View File
@@ -68,6 +68,9 @@ export const manifest: ExtractorManifest = {
single:
context.settings.searchCities ?? context.settings.jobspyLocation,
}),
workplaceTypes: context.settings.workplaceTypes
? JSON.parse(context.settings.workplaceTypes)
: undefined,
maxJobsPerTerm,
onProgress: (event) => {
if (context.shouldCancel?.()) return;
@@ -35,10 +35,11 @@ export function createDefaultSearchState(args: {
searchQuery: string;
location: HiringCafeCountryLocation | null;
dateFetchedPastNDays: number;
workplaceTypes?: Array<"Remote" | "Hybrid" | "Onsite">;
}): HiringCafeSearchState {
return {
locations: args.location ? [args.location] : [],
workplaceTypes: ["Remote", "Hybrid", "Onsite"],
workplaceTypes: args.workplaceTypes ?? ["Remote", "Hybrid", "Onsite"],
defaultToUserLocation: false,
userLocation: null,
commitmentTypes: [
+39 -1
View File
@@ -68,6 +68,8 @@ interface NominatimResult {
address?: Record<string, unknown>;
}
type HiringCafeWorkplaceType = "Remote" | "Hybrid" | "Onsite";
function emitProgress(payload: Record<string, unknown>): void {
if (process.env.JOBOPS_EMIT_PROGRESS !== "1") return;
console.log(`${JOBOPS_PROGRESS_PREFIX}${JSON.stringify(payload)}`);
@@ -79,6 +81,36 @@ function parsePositiveInt(input: string | undefined, fallback: number): number {
return parsed;
}
function parseWorkplaceTypes(
raw: string | undefined,
): HiringCafeWorkplaceType[] {
if (!raw) return ["Remote", "Hybrid", "Onsite"];
try {
const parsed = JSON.parse(raw) as unknown;
if (!Array.isArray(parsed)) return ["Remote", "Hybrid", "Onsite"];
const out: HiringCafeWorkplaceType[] = [];
const seen = new Set<HiringCafeWorkplaceType>();
for (const value of parsed) {
const mapped =
value === "remote"
? "Remote"
: value === "hybrid"
? "Hybrid"
: value === "onsite"
? "Onsite"
: null;
if (!mapped || seen.has(mapped)) continue;
seen.add(mapped);
out.push(mapped);
}
return out.length > 0 ? out : ["Remote", "Hybrid", "Onsite"];
} catch {
return ["Remote", "Hybrid", "Onsite"];
}
}
function encodeSearchState(searchState: unknown): string {
const json = JSON.stringify(searchState);
const urlEncodedJson = encodeURIComponent(json);
@@ -301,6 +333,7 @@ function createCitySearchState(args: {
searchQuery: string;
dateFetchedPastNDays: number;
context: CityLocationContext;
workplaceTypes: HiringCafeWorkplaceType[];
}): Record<string, unknown> {
return {
locations: [
@@ -340,7 +373,7 @@ function createCitySearchState(args: {
},
},
],
workplaceTypes: ["Remote", "Hybrid", "Onsite"],
workplaceTypes: args.workplaceTypes,
defaultToUserLocation: true,
userLocation: null,
physicalEnvironments: [
@@ -553,6 +586,9 @@ async function run(): Promise<void> {
process.env.HIRING_CAFE_OUTPUT_JSON ||
join(__dirname, "../storage/datasets/default/jobs.json");
const headless = process.env.HIRING_CAFE_HEADLESS !== "false";
const workplaceTypes = parseWorkplaceTypes(
process.env.HIRING_CAFE_WORKPLACE_TYPES,
);
let browser = await firefox.launch(
await launchOptions({
@@ -620,11 +656,13 @@ async function run(): Promise<void> {
searchQuery: searchTerm,
dateFetchedPastNDays,
context: cityLocationContext,
workplaceTypes,
})
: createDefaultSearchState({
searchQuery: searchTerm,
location: countryLocation,
dateFetchedPastNDays,
workplaceTypes,
});
const encodedSearchState = encodeSearchState(searchState);
+4
View File
@@ -54,6 +54,7 @@ export interface RunHiringCafeOptions {
country?: string;
countryKey?: string;
locations?: string[];
workplaceTypes?: Array<"remote" | "hybrid" | "onsite">;
locationRadiusMiles?: number;
maxJobsPerTerm?: number;
onProgress?: (event: HiringCafeProgressEvent) => void;
@@ -216,6 +217,9 @@ export async function runHiringCafe(
JOBOPS_EMIT_PROGRESS: "1",
HIRING_CAFE_SEARCH_TERMS: JSON.stringify(searchTerms),
HIRING_CAFE_COUNTRY: country,
HIRING_CAFE_WORKPLACE_TYPES: JSON.stringify(
options.workplaceTypes ?? ["remote", "hybrid", "onsite"],
),
HIRING_CAFE_MAX_JOBS_PER_TERM: String(maxJobsPerTerm),
HIRING_CAFE_OUTPUT_JSON: DATASET_PATH,
HIRING_CAFE_LOCATION_QUERY: strictLocationFilter ? location : "",