@pranavraut033/ats-checker 1.1.1 → 1.2.0

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/README.md CHANGED
@@ -19,6 +19,7 @@ Zero-dependency TypeScript library that scores a resume against a job descriptio
19
19
  - **Explainable** — breakdown by category (skills / experience / keywords / education) plus matched and missing skill/keyword lists
20
20
  - **Configurable** — adjust weights, add skill aliases, define custom penalty rules
21
21
  - **Zero dependencies** — core library has no runtime deps; ships ESM + CJS
22
+ - **PDF input** — optional `/pdf` subpath extracts resume text from a PDF buffer (requires `pdfjs-dist` peer dep)
22
23
  - **Built-in profiles** — software engineer, data scientist, product manager out of the box
23
24
 
24
25
  ---
@@ -184,6 +185,41 @@ const result = analyzeResume({
184
185
 
185
186
  ---
186
187
 
188
+ ## PDF Input
189
+
190
+ Extract text from a PDF resume before passing it to `analyzeResume`. This uses `pdfjs-dist` as an optional peer dependency — the core library stays zero-dep.
191
+
192
+ ```bash
193
+ npm install pdfjs-dist
194
+ ```
195
+
196
+ ```typescript
197
+ import { extractTextFromPDF } from "@pranavraut033/ats-checker/pdf";
198
+ import { analyzeResume } from "@pranavraut033/ats-checker";
199
+ import { readFileSync } from "fs";
200
+
201
+ const bytes = readFileSync("resume.pdf");
202
+ const resumeText = await extractTextFromPDF(bytes);
203
+
204
+ const result = analyzeResume({ resumeText, jobDescription: "..." });
205
+ ```
206
+
207
+ `extractTextFromPDF` accepts a `Uint8Array` or `ArrayBuffer` and returns a plain `string`. Works in Node.js and the browser (text-layer PDFs only).
208
+
209
+ **Multi-column layouts are handled automatically.** The extractor uses glyph x/y coordinates to detect column boundaries and process each column independently, so a two-column resume parses cleanly without interleaved text.
210
+
211
+ For PDFs that can't be recovered — scanned/image resumes or exports with no text layer — `analyzeResume` surfaces an actionable message in `result.warnings`. Always check it after PDF input:
212
+
213
+ ```typescript
214
+ const result = analyzeResume({ resumeText, jobDescription: "..." });
215
+ if (result.warnings.length) {
216
+ console.warn("Parsing issues:", result.warnings);
217
+ // e.g. "Almost no text was extracted — the resume may be a scanned/image PDF."
218
+ }
219
+ ```
220
+
221
+ ---
222
+
187
223
  ## LLM Integration (deprecated)
188
224
 
189
225
  `analyzeResumeAsync` accepts an optional `llm` config that rewrites suggestion text via a caller-supplied LLM client. **This path is deprecated** — scores and breakdowns are never touched by LLM. Prefer calling `analyzeResume` and running your own LLM pass on `result.suggestions` if you want AI-enhanced wording.
package/dist/index.js CHANGED
@@ -541,6 +541,16 @@ function parseResume(resumeText, config) {
541
541
  }
542
542
  const requiredSections = ["summary", "experience", "skills", "education"];
543
543
  const warnings = [];
544
+ const lineCount = splitLines(resumeText).length;
545
+ if (resumeText.trim().length < 100) {
546
+ warnings.push(
547
+ "Almost no text was extracted \u2014 the resume may be a scanned/image PDF. Upload a text-based PDF or paste the text directly."
548
+ );
549
+ } else if (lineCount <= 2) {
550
+ warnings.push(
551
+ "Resume text has no line breaks \u2014 the PDF layout likely didn't export cleanly (common with multi-column designs). Export as a single-column PDF or paste plain text for accurate parsing."
552
+ );
553
+ }
544
554
  for (const section of requiredSections) {
545
555
  if (!detected.includes(section)) {
546
556
  warnings.push(`${section} section not detected`);
@@ -920,6 +930,11 @@ var SuggestionEngine = class {
920
930
  "Strengthen bullet points with impact verbs (led, built, improved, delivered)."
921
931
  );
922
932
  }
933
+ if (input.resume.detectedSections.length < 2 && input.resume.raw.trim().length > 300) {
934
+ suggestions.push(
935
+ "Your resume may use a multi-column layout. Export as a single-column PDF or paste plain text \u2014 most ATS systems and this parser work best with a linear layout."
936
+ );
937
+ }
923
938
  return { suggestions, warnings };
924
939
  }
925
940
  };