Initial import of hire-me.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
delikesance
2026-09-04 20:08:12 +00:00
co-authored by Cursor
commit 9c734470b3
23 changed files with 2463 additions and 0 deletions
+161
View File
@@ -0,0 +1,161 @@
import type { Match, NormalizedJob } from "./types.ts";
const EU_COUNTRIES = [
"france",
"germany",
"spain",
"italy",
"portugal",
"netherlands",
"belgium",
"luxembourg",
"austria",
"switzerland",
"ireland",
"united kingdom",
"sweden",
"norway",
"denmark",
"finland",
"poland",
"czech",
"czechia",
"romania",
"hungary",
"greece",
"croatia",
"slovenia",
"slovakia",
"estonia",
"latvia",
"lithuania",
"bulgaria",
"europe",
"european",
"emea",
];
const AGENCY_DENY = [
"lemon.io",
"g2i",
"distantjob",
"talent sam",
"kdci",
"2am.tech",
"photon",
"turing",
"toptal",
"andela",
"telus digital",
"a.team",
"white cloak",
"creative chaos",
"dacodes",
"coalition technologies",
"jobs for humanity",
"jobsforlebanon",
"consulting1x1",
];
const JUNIOR = /\b(intern|internship|trainee|stage\b|apprentice|junior|entry-level|entry level|software engineer i\b)\b/i;
const WRONG_ROLE =
/\b(qa engineer|quality assurance|copywriter|marketing|sales|account executive|customer support|support engineer|devops|data engineer|scraping engineer|documentation engineer|ux designer|head of engineering|game developer)\b/i;
const WRONG_STACK =
/\b(reactjs|react\.js|\breact\b|next\.js|angular|ruby|rails|django|\.net|asp\.net|spring ?boot|\bjava\b|\bphp\b|laravel|symfony|kotlin|golang|flutter)\b/i;
const VUE = /\bvue(?:\.?js)?\b/i;
const NUXT = /\bnuxt(?:\.?js)?\b/i;
function tokens(location: string): string[] {
const parts = location
.toLowerCase()
.split(/[,/;|]+/)
.map((part) => part.trim())
.filter(Boolean);
if (parts.length === 0 && location.trim()) return [location.toLowerCase().trim()];
return parts;
}
function isEuToken(token: string): boolean {
if (token === "uk" || token === "gb" || token === "eu") return true;
return EU_COUNTRIES.some((country) => token === country || token.startsWith(`${country} `));
}
function geoEligible(job: NormalizedJob): { ok: boolean; reason?: string; bonus: number } {
const loc = job.location.toLowerCase().trim();
if (!loc || loc === "worldwide" || loc === "anywhere" || loc === "remote") {
return { ok: true, bonus: 1, reason: "remote worldwide" };
}
const parts = tokens(job.location);
const euParts = parts.filter(isEuToken);
if (euParts.length === 0) return { ok: false, bonus: 0 };
const france = parts.some((part) => part === "france" || part.includes("france"));
return {
ok: true,
bonus: france ? 6 : 3,
reason: france ? "France" : "Europe",
};
}
function timezoneOk(job: NormalizedJob): boolean {
if (job.timezones.length === 0) return true;
return job.timezones.some((tz) => tz >= 0 && tz <= 3);
}
export function matchJob(job: NormalizedJob): Match | null {
const company = job.company.toLowerCase();
if (AGENCY_DENY.some((name) => company.includes(name))) return null;
const title = job.title;
if (JUNIOR.test(title) || WRONG_ROLE.test(title)) return null;
if (/\b(hybrid|présentiel|on-?site|short term|fluent ukrainian)\b/i.test(title)) return null;
if (!job.remote) return null;
if (!timezoneOk(job)) return null;
const geo = geoEligible(job);
if (!geo.ok) return null;
const vueTitle = VUE.test(title);
const nuxtTitle = NUXT.test(title) || /\bsidebase\b/i.test(title);
const conflictingTitle = WRONG_STACK.test(title) && !vueTitle && !nuxtTitle;
if (conflictingTitle) return null;
if (!vueTitle && !nuxtTitle) return null;
const body = `${job.excerpt} ${job.description}`.toLowerCase().slice(0, 4000);
const reasons: string[] = [];
let score = geo.bonus;
if (geo.reason) reasons.push(geo.reason);
if (nuxtTitle) {
score += 8;
reasons.push("Nuxt");
}
if (vueTitle) {
score += 7;
reasons.push("Vue");
}
if (/\btypescript\b/i.test(`${title} ${job.tags.join(" ")} ${body}`)) {
score += 2;
reasons.push("TypeScript");
}
if (/\bnode(?:\.?js)?\b/i.test(`${title} ${job.tags.join(" ")} ${body}`)) {
score += 2;
reasons.push("Node.js");
}
if (/\bfull[\s-]?stack\b/i.test(title)) {
score += 2;
reasons.push("Fullstack");
} else if (/\bfront[\s-]?end\b/i.test(title)) {
score += 1;
reasons.push("Frontend");
}
if (/\b(travel|booking|ndc|gds|fintech|b2b)\b/i.test(`${title} ${body}`)) {
score += 2;
reasons.push("domaine proche");
}
if (score < 8) return null;
return { job, score, reasons };
}