lazy-apply 0.1.2 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +1 -1
- package/dist/runner.js +30 -2
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -6,7 +6,7 @@ import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node
|
|
|
6
6
|
import { homedir, hostname, platform, tmpdir, userInfo } from "node:os";
|
|
7
7
|
import { dirname, join } from "node:path";
|
|
8
8
|
import { createInterface } from "node:readline/promises";
|
|
9
|
-
var VERSION = true ? "0.1.
|
|
9
|
+
var VERSION = true ? "0.1.3" : "dev";
|
|
10
10
|
var DEFAULT_APP = "https://lazyapply.online";
|
|
11
11
|
var HOME = join(homedir(), ".lazy-apply");
|
|
12
12
|
var CONFIG = join(HOME, "config.json");
|
package/dist/runner.js
CHANGED
|
@@ -144,7 +144,33 @@ var pick = (opts, ...prefer) => {
|
|
|
144
144
|
};
|
|
145
145
|
var or = (v, fallback) => v && v.trim() || fallback;
|
|
146
146
|
var links = (s) => [s.website, s.linkedin, s.github].filter(Boolean).join(" | ");
|
|
147
|
+
var yesNo = (o, yes) => o?.length ? pick(o, yes ? /^yes\b/i : /^no\b/i) : yes ? "Yes" : "No";
|
|
148
|
+
var countriesIn = (text) => {
|
|
149
|
+
const out = /* @__PURE__ */ new Set();
|
|
150
|
+
for (const part of text.split(/,|\bor\b|\band\b|\//i)) {
|
|
151
|
+
const c = countryOf(part) ?? (/\bpoland\b/i.test(part) ? "Poland" : void 0);
|
|
152
|
+
if (c) out.add(c);
|
|
153
|
+
}
|
|
154
|
+
return out;
|
|
155
|
+
};
|
|
147
156
|
var RULES = [
|
|
157
|
+
// Screening questions that sound like other rules but are not: answered before the broad rules below see them.
|
|
158
|
+
{ test: /employment agreements?|post[- ]employment restrictions?|non[- ]?compete|non[- ]?solicit|restrictive covenants?/i, answer: (_s, o) => yesNo(o, false) },
|
|
159
|
+
{ test: /(previously|ever|before) (worked|been employed|consulted|interned)( at| for| with)|former (employee|contractor) (of|at)/i, answer: (_s, o) => yesNo(o, false) },
|
|
160
|
+
// "...sponsorship to remain in your current location": about where the person lives, not where the job is.
|
|
161
|
+
{ test: /sponsor[^?]*(current(ly)? (location|country)|where you (currently )?(live|reside|are based))/i, answer: (s, o) => {
|
|
162
|
+
const home = countryOf(s.location);
|
|
163
|
+
if (!home) return void 0;
|
|
164
|
+
const ok = s.workAuthorizedCountries.split(",").some((c) => c.trim().toLowerCase() === home.toLowerCase());
|
|
165
|
+
return yesNo(o, !ok);
|
|
166
|
+
} },
|
|
167
|
+
// "Are you currently located in either Canada, UK or Poland?"
|
|
168
|
+
{ test: /(currently |presently )?(locat(ed|ion)|living|based|residing|reside) in (either )?[A-Z][^?]*\b(or|and)\b/i, answer: (s, o, _c, label) => {
|
|
169
|
+
const home = countryOf(s.location);
|
|
170
|
+
if (!home || !label) return void 0;
|
|
171
|
+
const listed = countriesIn(label.replace(/^.*?\b(?:in|either)\b/i, ""));
|
|
172
|
+
return listed.size ? yesNo(o, listed.has(home)) : void 0;
|
|
173
|
+
} },
|
|
148
174
|
{ test: /^first\s*name/i, answer: (s) => or(s.firstName) },
|
|
149
175
|
{ test: /^last\s*name|surname|family name/i, answer: (s) => or(s.lastName) },
|
|
150
176
|
{ test: /^(full |legal )?name$/i, answer: (s) => or(`${s.firstName} ${s.lastName}`.trim()) },
|
|
@@ -397,14 +423,16 @@ function findEmptyRequired() {
|
|
|
397
423
|
if (!box) continue;
|
|
398
424
|
const required = /\*|✱/.test(raw) || /required/i.test(lab.className) || !!(ctl && (ctl.hasAttribute("required") || ctl.getAttribute("aria-required") === "true")) || !!box.querySelector("[required], [aria-required=true]");
|
|
399
425
|
if (!required) continue;
|
|
400
|
-
const
|
|
426
|
+
const combo = !!ctl && (ctl.getAttribute("role") === "combobox" || !!ctl.closest("[class*=select__], [class*=-container]"));
|
|
427
|
+
const scope = ctl && !combo && !/radio|checkbox/.test(ctl.type || "") ? ctl.parentElement || box : box;
|
|
401
428
|
const texts = Array.from(scope.querySelectorAll("input:not([type=hidden]):not([type=radio]):not([type=checkbox]):not([type=file]):not([type=submit]), textarea, select"));
|
|
402
429
|
const files = Array.from(scope.querySelectorAll("input[type=file]"));
|
|
403
430
|
const checks = Array.from(scope.querySelectorAll("input[type=radio], input[type=checkbox]"));
|
|
404
431
|
const buttons = Array.from(scope.querySelectorAll("button, [role=radio], [role=checkbox]")).filter((b) => b.type !== "submit");
|
|
405
432
|
if (!texts.length && !files.length && !checks.length && !buttons.length) continue;
|
|
406
433
|
const scopeText = scope.textContent || "";
|
|
407
|
-
const
|
|
434
|
+
const chosen = !!Array.from(scope.querySelectorAll("[class*=single-value], [class*=multi-value], [class*=singleValue], [class*=multiValue]")).some((e) => (e.textContent || "").trim()) || !!scope.querySelector("[class*=value-container--has-value]") || Array.from(scope.querySelectorAll("input[type=hidden]")).some((h) => h.value.trim() && /question|answer|select|value/i.test(h.name || h.id || ""));
|
|
435
|
+
const filled = chosen || texts.some((t) => t.value?.trim()) || files.some((f) => (f.files?.length || 0) > 0) || files.length > 0 && /\.(pdf|docx?|rtf|txt)\b/i.test(scopeText) || checks.some((c) => c.checked) || buttons.some((b) => b.getAttribute("aria-pressed") === "true" || b.getAttribute("aria-checked") === "true" || /selected|active|checked/i.test(b.className) && !/unselected/i.test(b.className));
|
|
408
436
|
const label = clean(raw).replace(/(ATTACH RESUME|No location found|Couldn't auto-read|Analyzing resume|Loading).*$/i, "").trim();
|
|
409
437
|
if (!filled && label && !seen.has(label)) {
|
|
410
438
|
seen.add(label);
|
package/package.json
CHANGED