@pranavraut033/ats-checker 1.0.5 → 1.1.1
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 +145 -108
- package/dist/index.d.mts +29 -9
- package/dist/index.d.ts +29 -9
- package/dist/index.js +261 -53
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +261 -53
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,12 +1,33 @@
|
|
|
1
|
-
# ats-checker
|
|
1
|
+
# @pranavraut033/ats-checker
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/@pranavraut033/ats-checker)
|
|
4
4
|
[](https://www.npmjs.com/package/@pranavraut033/ats-checker)
|
|
5
5
|
[](https://opensource.org/licenses/MIT)
|
|
6
|
-
[](https://github.com/Pranavraut033/ats-checker/actions/workflows/deploy.yml)
|
|
7
6
|
[](https://github.com/Pranavraut033/ats-checker/actions/workflows/ci.yml)
|
|
7
|
+
[](https://github.com/Pranavraut033/ats-checker/actions/workflows/deploy.yml)
|
|
8
|
+
|
|
9
|
+
Zero-dependency TypeScript library that scores a resume against a job description and explains why — skills coverage, keyword overlap, experience match, and education — with no randomness, no LLM, and no external calls.
|
|
10
|
+
|
|
11
|
+
**[Live Demo →](https://pranavraut033.github.io/ats-checker/)**
|
|
12
|
+
**[Docs →](https://pranavraut033.github.io/ats-checker/docs/)**
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Features
|
|
8
17
|
|
|
9
|
-
|
|
18
|
+
- **Deterministic** — same input always produces the same score; pin it with `referenceDate` to freeze "Present" date math
|
|
19
|
+
- **Explainable** — breakdown by category (skills / experience / keywords / education) plus matched and missing skill/keyword lists
|
|
20
|
+
- **Configurable** — adjust weights, add skill aliases, define custom penalty rules
|
|
21
|
+
- **Zero dependencies** — core library has no runtime deps; ships ESM + CJS
|
|
22
|
+
- **Built-in profiles** — software engineer, data scientist, product manager out of the box
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Requirements
|
|
27
|
+
|
|
28
|
+
- Node.js ≥ 18
|
|
29
|
+
|
|
30
|
+
---
|
|
10
31
|
|
|
11
32
|
## Installation
|
|
12
33
|
|
|
@@ -14,173 +35,189 @@ A zero-dependency TypeScript library for evaluating resume compatibility with Ap
|
|
|
14
35
|
npm install @pranavraut033/ats-checker
|
|
15
36
|
```
|
|
16
37
|
|
|
38
|
+
---
|
|
39
|
+
|
|
17
40
|
## Usage
|
|
18
41
|
|
|
19
42
|
```typescript
|
|
20
43
|
import { analyzeResume } from "@pranavraut033/ats-checker";
|
|
21
44
|
|
|
22
45
|
const result = analyzeResume({
|
|
23
|
-
resumeText: `
|
|
24
|
-
Software Engineer with 5 years of experience
|
|
25
|
-
|
|
46
|
+
resumeText: `
|
|
47
|
+
Software Engineer with 5 years of experience.
|
|
48
|
+
Skills: JavaScript, TypeScript, React, Node.js, SQL
|
|
49
|
+
Experience: Senior Engineer at ExampleCorp (Jan 2020 - Present)
|
|
50
|
+
Education: B.S. Computer Science
|
|
51
|
+
`,
|
|
52
|
+
jobDescription: `
|
|
53
|
+
Frontend engineer role. Must have React, TypeScript, accessibility best practices.
|
|
54
|
+
Preferred: GraphQL. 3+ years required. Bachelor's degree required.
|
|
55
|
+
`,
|
|
56
|
+
config: { referenceDate: "2026-01-01" }, // freeze clock for reproducible scores
|
|
26
57
|
});
|
|
27
58
|
|
|
28
|
-
console.log(result.score);
|
|
29
|
-
console.log(result.
|
|
30
|
-
console.log(result.
|
|
59
|
+
console.log(result.score); // e.g. 72.45
|
|
60
|
+
console.log(result.matchedSkills); // ["javascript", "node", "react", "typescript"]
|
|
61
|
+
console.log(result.missingSkills); // ["accessibility best practices", "graphql"]
|
|
62
|
+
console.log(result.experienceGap); // 0 (requirement met)
|
|
63
|
+
console.log(result.suggestions); // ["Add GraphQL to your skills section", ...]
|
|
31
64
|
```
|
|
32
65
|
|
|
33
|
-
|
|
66
|
+
---
|
|
34
67
|
|
|
35
|
-
|
|
68
|
+
## Output
|
|
36
69
|
|
|
70
|
+
`analyzeResume()` returns an `ATSAnalysisResult`:
|
|
37
71
|
|
|
72
|
+
| Field | Type | Description |
|
|
73
|
+
|---|---|---|
|
|
74
|
+
| `score` | `number` | Overall ATS score 0–100 after rule penalties |
|
|
75
|
+
| `breakdown` | `ATSBreakdown` | Sub-scores: `skills`, `experience`, `keywords`, `education` |
|
|
76
|
+
| `matchedSkills` | `string[]` | Required skills found in the resume |
|
|
77
|
+
| `missingSkills` | `string[]` | Required skills absent from the resume |
|
|
78
|
+
| `matchedKeywords` | `string[]` | JD keywords present in the resume (sorted) |
|
|
79
|
+
| `missingKeywords` | `string[]` | JD keywords absent from the resume (sorted) |
|
|
80
|
+
| `overusedKeywords` | `string[]` | Keywords exceeding density threshold (sorted) |
|
|
81
|
+
| `suggestions` | `string[]` | Deterministic improvement recommendations |
|
|
82
|
+
| `warnings` | `string[]` | Parse warnings and section alerts |
|
|
83
|
+
| `experienceGap` | `number` | Years below JD minimum; `0` when met |
|
|
84
|
+
| `detectedSections` | `string[]` | Resume sections the parser found |
|
|
85
|
+
| `parsedExperienceYears` | `number` | Total years from resume date ranges (overlap-deduplicated) |
|
|
86
|
+
| `experienceEntries` | `ParsedExperienceEntry[]` | Parsed job entries: `title`, `company`, `dates` (with `start`/`end`/`durationInMonths`) |
|
|
38
87
|
|
|
39
|
-
|
|
88
|
+
**Scoring formula:**
|
|
89
|
+
`score = skills×0.30 + experience×0.30 + keywords×0.25 + education×0.15` → clamped to 0–100 → rule penalties subtracted.
|
|
40
90
|
|
|
41
|
-
|
|
42
|
-
import { analyzeResumeAsync } from "@pranavraut033/ats-checker";
|
|
43
|
-
|
|
44
|
-
const myLLMClient = /* implement LLMClient (OpenAI/Anthropic/local) */;
|
|
45
|
-
|
|
46
|
-
const result = await analyzeResumeAsync({
|
|
47
|
-
resumeText: "...",
|
|
48
|
-
jobDescription: "...",
|
|
49
|
-
llm: {
|
|
50
|
-
client: myLLMClient,
|
|
51
|
-
models: { default: "gpt-4o-mini" },
|
|
52
|
-
limits: { maxCalls: 3, maxTokensPerCall: 1000, maxTotalTokens: 5000 },
|
|
53
|
-
enable: { suggestions: true }
|
|
54
|
-
}
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
console.log(result.score); // unchanged by LLM
|
|
58
|
-
console.log(result.suggestions); // enhanced wording/context
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
Note: Passing `llm` to `analyzeResume` (sync) will add a warning and skip enhancement. Prefer `analyzeResumeAsync` for LLM features.
|
|
91
|
+
---
|
|
62
92
|
|
|
63
93
|
## Configuration
|
|
64
94
|
|
|
65
|
-
|
|
95
|
+
All options are optional. Pass any subset; `resolveConfig()` fills in defaults.
|
|
66
96
|
|
|
67
97
|
```typescript
|
|
68
98
|
const result = analyzeResume({
|
|
69
99
|
resumeText: "...",
|
|
70
100
|
jobDescription: "...",
|
|
71
101
|
config: {
|
|
102
|
+
// Override scoring weights (auto-normalized to sum to 1)
|
|
72
103
|
weights: { skills: 0.4, experience: 0.3, keywords: 0.2, education: 0.1 },
|
|
73
|
-
|
|
104
|
+
|
|
105
|
+
// Additional skill synonyms merged over built-in defaults
|
|
106
|
+
skillAliases: { javascript: ["js", "ecmascript"] },
|
|
107
|
+
|
|
108
|
+
// Industry profile: sets mandatory/optional skills and minExperience
|
|
109
|
+
profile: {
|
|
110
|
+
mandatorySkills: ["javascript", "react"],
|
|
111
|
+
optionalSkills: ["graphql", "docker"],
|
|
112
|
+
minExperience: 3,
|
|
113
|
+
},
|
|
114
|
+
|
|
115
|
+
// Freeze "Present" end dates for reproducible experience scoring
|
|
116
|
+
referenceDate: "2026-01-01",
|
|
117
|
+
|
|
118
|
+
// Keyword density thresholds
|
|
119
|
+
keywordDensity: { min: 0.0025, max: 0.04, overusePenalty: 5 },
|
|
120
|
+
|
|
121
|
+
// Custom penalty rules
|
|
74
122
|
rules: [
|
|
75
123
|
{
|
|
76
|
-
id: "
|
|
77
|
-
penalty:
|
|
78
|
-
warning: "
|
|
79
|
-
condition: (ctx) =>
|
|
124
|
+
id: "no-tables",
|
|
125
|
+
penalty: 10,
|
|
126
|
+
warning: "Remove tables — ATS parsers often mangle them",
|
|
127
|
+
condition: (ctx) => ctx.resume.detectedSections.length < 2,
|
|
80
128
|
},
|
|
81
129
|
{
|
|
82
|
-
id: "
|
|
83
|
-
penalty:
|
|
84
|
-
warning: "
|
|
85
|
-
condition: (ctx) =>
|
|
86
|
-
}
|
|
87
|
-
]
|
|
88
|
-
}
|
|
130
|
+
id: "experience-gap",
|
|
131
|
+
penalty: 5,
|
|
132
|
+
warning: "Resume has less than 3 years experience",
|
|
133
|
+
condition: (ctx) => ctx.resume.totalExperienceYears < 3,
|
|
134
|
+
},
|
|
135
|
+
],
|
|
136
|
+
},
|
|
89
137
|
});
|
|
90
138
|
```
|
|
91
139
|
|
|
92
|
-
|
|
140
|
+
### Defaults
|
|
141
|
+
|
|
142
|
+
| Setting | Default |
|
|
143
|
+
|---|---|
|
|
144
|
+
| `weights.skills` | `0.30` |
|
|
145
|
+
| `weights.experience` | `0.30` |
|
|
146
|
+
| `weights.keywords` | `0.25` |
|
|
147
|
+
| `weights.education` | `0.15` |
|
|
148
|
+
| `keywordDensity.min` | `0.0025` |
|
|
149
|
+
| `keywordDensity.max` | `0.04` |
|
|
150
|
+
| `keywordDensity.overusePenalty` | `5` |
|
|
151
|
+
| `allowPartialMatches` | `true` |
|
|
152
|
+
| `referenceDate` | Current date (use explicit ISO string for determinism) |
|
|
153
|
+
|
|
154
|
+
See [Configuration docs](https://pranavraut033.github.io/ats-checker/docs/configuration/) for all options.
|
|
93
155
|
|
|
94
|
-
|
|
156
|
+
---
|
|
95
157
|
|
|
96
|
-
-
|
|
97
|
-
- Keyword density: min 0.0025, max 0.04, overusePenalty 5
|
|
98
|
-
- Section penalties: summary 4, experience 10, skills 8, education 6
|
|
99
|
-
- Partial matches: `allowPartialMatches: true`
|
|
158
|
+
## Built-in Skill Aliases
|
|
100
159
|
|
|
101
|
-
|
|
160
|
+
Common tech synonyms are pre-loaded so `js` matches `javascript`, `k8s` matches `kubernetes`, etc. Extend or override via `config.skillAliases`.
|
|
102
161
|
|
|
103
|
-
|
|
162
|
+
```typescript
|
|
163
|
+
import { defaultSkillAliases } from "@pranavraut033/ats-checker";
|
|
164
|
+
// { javascript: ["js"], node: ["node.js", "nodejs"], typescript: ["ts"], ... }
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
---
|
|
104
168
|
|
|
105
|
-
|
|
169
|
+
## Built-in Profiles
|
|
106
170
|
|
|
107
171
|
```typescript
|
|
172
|
+
import {
|
|
173
|
+
softwareEngineerProfile,
|
|
174
|
+
dataScientistProfile,
|
|
175
|
+
productManagerProfile,
|
|
176
|
+
} from "@pranavraut033/ats-checker";
|
|
177
|
+
|
|
108
178
|
const result = analyzeResume({
|
|
109
179
|
resumeText: "...",
|
|
110
180
|
jobDescription: "...",
|
|
111
|
-
config: {
|
|
112
|
-
rules: [
|
|
113
|
-
{
|
|
114
|
-
id: "min-years",
|
|
115
|
-
penalty: 5,
|
|
116
|
-
warning: "Less than 3 years experience",
|
|
117
|
-
condition: (ctx) => (ctx.resume.experienceYears ?? 0) < 3
|
|
118
|
-
},
|
|
119
|
-
{
|
|
120
|
-
id: "require-contact",
|
|
121
|
-
penalty: 2,
|
|
122
|
-
warning: "Add phone/email to contact info",
|
|
123
|
-
condition: (ctx) => !ctx.resume.contactInfo?.phone || !ctx.resume.contactInfo?.email
|
|
124
|
-
}
|
|
125
|
-
]
|
|
126
|
-
}
|
|
181
|
+
config: { profile: softwareEngineerProfile },
|
|
127
182
|
});
|
|
128
183
|
```
|
|
129
|
-
See [Rules Engine](docs/rules.md) for default rules and context fields.
|
|
130
|
-
|
|
131
|
-
## Features
|
|
132
184
|
|
|
133
|
-
|
|
134
|
-
- Detects common ATS issues like missing sections or keyword overuse
|
|
135
|
-
- Customizable scoring weights and validation rules
|
|
136
|
-
- Optional LLM integration for enhanced suggestions
|
|
137
|
-
- Includes a web interface for testing (`npm run dev`)
|
|
138
|
-
- [Live Demo](https://pranavraut033.github.io/ats-checker/)
|
|
185
|
+
---
|
|
139
186
|
|
|
140
|
-
##
|
|
187
|
+
## LLM Integration (deprecated)
|
|
141
188
|
|
|
142
|
-
|
|
189
|
+
`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.
|
|
143
190
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
**Input:**
|
|
147
|
-
- `resumeText: string` - The full text of the resume
|
|
148
|
-
- `jobDescription: string` - The job description text
|
|
149
|
-
- `config?: ATSConfig` - Optional configuration overrides
|
|
150
|
-
|
|
151
|
-
**Output:**
|
|
152
|
-
- `score: number` - Overall ATS score (0-100)
|
|
153
|
-
- `breakdown: ATSBreakdown` - Component scores
|
|
154
|
-
- `matchedKeywords: string[]` - Keywords found in both
|
|
155
|
-
- `missingKeywords: string[]` - Important keywords not in resume
|
|
156
|
-
- `suggestions: string[]` - Improvement recommendations
|
|
157
|
-
- `warnings: string[]` - Issues detected
|
|
191
|
+
---
|
|
158
192
|
|
|
159
193
|
## Development
|
|
160
194
|
|
|
161
195
|
```bash
|
|
162
196
|
npm install
|
|
163
|
-
npm run build
|
|
164
|
-
npm test
|
|
165
|
-
npm run
|
|
197
|
+
npm run build # tsup → ESM + CJS in dist/
|
|
198
|
+
npm test # vitest (single pass)
|
|
199
|
+
npm run type-check # tsc --noEmit
|
|
200
|
+
npm run dev # static demo UI at http://localhost:3005
|
|
166
201
|
```
|
|
167
202
|
|
|
203
|
+
---
|
|
204
|
+
|
|
168
205
|
## Documentation
|
|
169
206
|
|
|
170
|
-
|
|
171
|
-
- https://Pranavraut033.github.io/ats-checker/docs/
|
|
207
|
+
Full docs at **[pranavraut033.github.io/ats-checker/docs/](https://pranavraut033.github.io/ats-checker/docs/)**
|
|
172
208
|
|
|
173
|
-
**Local Docs** (in repository):
|
|
174
|
-
- [Configuration Guide](docs/configuration.md)
|
|
175
|
-
- [LLM Integration](docs/llm-integration.md)
|
|
176
|
-
- [Web Interface](docs/ui.md)
|
|
177
209
|
- [Architecture](docs/architecture.md)
|
|
210
|
+
- [Configuration](docs/configuration.md)
|
|
211
|
+
- [Rules Engine](docs/rules.md)
|
|
212
|
+
|
|
213
|
+
---
|
|
178
214
|
|
|
179
215
|
## Contributing
|
|
180
216
|
|
|
181
|
-
|
|
217
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md). PRs welcome.
|
|
182
218
|
|
|
183
|
-
|
|
219
|
+
---
|
|
184
220
|
|
|
185
|
-
|
|
221
|
+
## License
|
|
186
222
|
|
|
223
|
+
MIT © [Pranav Raut](https://github.com/Pranavraut033)
|
package/dist/index.d.mts
CHANGED
|
@@ -4,6 +4,11 @@ interface ParsedDateRange {
|
|
|
4
4
|
start?: string;
|
|
5
5
|
end?: string;
|
|
6
6
|
durationInMonths?: number;
|
|
7
|
+
/** Numeric year/month of the start and end, for overlap-aware summing. */
|
|
8
|
+
startYear?: number;
|
|
9
|
+
startMonth?: number;
|
|
10
|
+
endYear?: number;
|
|
11
|
+
endMonth?: number;
|
|
7
12
|
}
|
|
8
13
|
interface ParsedExperienceEntry {
|
|
9
14
|
title?: string;
|
|
@@ -79,6 +84,13 @@ interface ATSConfig {
|
|
|
79
84
|
keywordDensity?: KeywordDensityConfig;
|
|
80
85
|
sectionPenalties?: SectionPenaltyConfig;
|
|
81
86
|
allowPartialMatches?: boolean;
|
|
87
|
+
/**
|
|
88
|
+
* ISO date string (e.g. "2024-06-01") used as the "today" reference when
|
|
89
|
+
* computing duration for open-ended date ranges ("Present"/"Current"/"Now").
|
|
90
|
+
* Omit to use the actual current date (live/production behaviour).
|
|
91
|
+
* Set to a fixed value in tests or batch processing to guarantee determinism.
|
|
92
|
+
*/
|
|
93
|
+
referenceDate?: string;
|
|
82
94
|
}
|
|
83
95
|
interface NormalizedWeights extends ATSWeights {
|
|
84
96
|
/** Weights normalized so they sum to 1. */
|
|
@@ -92,6 +104,8 @@ interface ResolvedATSConfig {
|
|
|
92
104
|
keywordDensity: KeywordDensityConfig;
|
|
93
105
|
sectionPenalties: Required<SectionPenaltyConfig>;
|
|
94
106
|
allowPartialMatches: boolean;
|
|
107
|
+
/** Resolved reference date for "Present" duration calculations. */
|
|
108
|
+
referenceDate?: Date;
|
|
95
109
|
}
|
|
96
110
|
interface RuleContext {
|
|
97
111
|
resume: ParsedResume;
|
|
@@ -224,11 +238,23 @@ interface AnalyzeResumeInput {
|
|
|
224
238
|
interface ATSAnalysisResult {
|
|
225
239
|
score: number;
|
|
226
240
|
breakdown: ATSBreakdown;
|
|
241
|
+
/** Skills found in the resume that satisfy JD + profile requirements. */
|
|
242
|
+
matchedSkills: string[];
|
|
243
|
+
/** Required skills absent from the resume. */
|
|
244
|
+
missingSkills: string[];
|
|
227
245
|
matchedKeywords: string[];
|
|
228
246
|
missingKeywords: string[];
|
|
229
247
|
overusedKeywords: string[];
|
|
230
248
|
suggestions: string[];
|
|
231
249
|
warnings: string[];
|
|
250
|
+
/** Years below the JD's minimum experience requirement; 0 when the requirement is met. */
|
|
251
|
+
experienceGap: number;
|
|
252
|
+
/** Resume sections the parser successfully detected (e.g. "summary", "skills"). */
|
|
253
|
+
detectedSections: string[];
|
|
254
|
+
/** Total years of experience parsed from the resume's date ranges. */
|
|
255
|
+
parsedExperienceYears: number;
|
|
256
|
+
/** Parsed experience entries from the resume, with titles and date ranges. */
|
|
257
|
+
experienceEntries: ParsedExperienceEntry[];
|
|
232
258
|
}
|
|
233
259
|
|
|
234
260
|
declare const defaultSkillAliases: SkillAliases;
|
|
@@ -471,18 +497,12 @@ declare function safeExtractNumber(obj: unknown, key: string): number | undefine
|
|
|
471
497
|
*/
|
|
472
498
|
declare function analyzeResume(input: AnalyzeResumeInput): ATSAnalysisResult;
|
|
473
499
|
/**
|
|
474
|
-
*
|
|
475
|
-
*
|
|
500
|
+
* @deprecated The LLM layer only rewrites suggestion text and adds non-determinism.
|
|
501
|
+
* Prefer `analyzeResume` (sync, deterministic) and call your own LLM on the result if needed.
|
|
502
|
+
* This function will be removed in a future major version.
|
|
476
503
|
*
|
|
477
504
|
* @param input Resume, job description, and optional LLM config
|
|
478
505
|
* @returns Promise<ATSAnalysisResult>
|
|
479
|
-
*
|
|
480
|
-
* @example
|
|
481
|
-
* const result = await analyzeResumeAsync({
|
|
482
|
-
* resumeText,
|
|
483
|
-
* jobDescription,
|
|
484
|
-
* llm: { client, limits: {...}, enable: { suggestions: true } }
|
|
485
|
-
* });
|
|
486
506
|
*/
|
|
487
507
|
declare function analyzeResumeAsync(input: AnalyzeResumeInput): Promise<ATSAnalysisResult>;
|
|
488
508
|
|
package/dist/index.d.ts
CHANGED
|
@@ -4,6 +4,11 @@ interface ParsedDateRange {
|
|
|
4
4
|
start?: string;
|
|
5
5
|
end?: string;
|
|
6
6
|
durationInMonths?: number;
|
|
7
|
+
/** Numeric year/month of the start and end, for overlap-aware summing. */
|
|
8
|
+
startYear?: number;
|
|
9
|
+
startMonth?: number;
|
|
10
|
+
endYear?: number;
|
|
11
|
+
endMonth?: number;
|
|
7
12
|
}
|
|
8
13
|
interface ParsedExperienceEntry {
|
|
9
14
|
title?: string;
|
|
@@ -79,6 +84,13 @@ interface ATSConfig {
|
|
|
79
84
|
keywordDensity?: KeywordDensityConfig;
|
|
80
85
|
sectionPenalties?: SectionPenaltyConfig;
|
|
81
86
|
allowPartialMatches?: boolean;
|
|
87
|
+
/**
|
|
88
|
+
* ISO date string (e.g. "2024-06-01") used as the "today" reference when
|
|
89
|
+
* computing duration for open-ended date ranges ("Present"/"Current"/"Now").
|
|
90
|
+
* Omit to use the actual current date (live/production behaviour).
|
|
91
|
+
* Set to a fixed value in tests or batch processing to guarantee determinism.
|
|
92
|
+
*/
|
|
93
|
+
referenceDate?: string;
|
|
82
94
|
}
|
|
83
95
|
interface NormalizedWeights extends ATSWeights {
|
|
84
96
|
/** Weights normalized so they sum to 1. */
|
|
@@ -92,6 +104,8 @@ interface ResolvedATSConfig {
|
|
|
92
104
|
keywordDensity: KeywordDensityConfig;
|
|
93
105
|
sectionPenalties: Required<SectionPenaltyConfig>;
|
|
94
106
|
allowPartialMatches: boolean;
|
|
107
|
+
/** Resolved reference date for "Present" duration calculations. */
|
|
108
|
+
referenceDate?: Date;
|
|
95
109
|
}
|
|
96
110
|
interface RuleContext {
|
|
97
111
|
resume: ParsedResume;
|
|
@@ -224,11 +238,23 @@ interface AnalyzeResumeInput {
|
|
|
224
238
|
interface ATSAnalysisResult {
|
|
225
239
|
score: number;
|
|
226
240
|
breakdown: ATSBreakdown;
|
|
241
|
+
/** Skills found in the resume that satisfy JD + profile requirements. */
|
|
242
|
+
matchedSkills: string[];
|
|
243
|
+
/** Required skills absent from the resume. */
|
|
244
|
+
missingSkills: string[];
|
|
227
245
|
matchedKeywords: string[];
|
|
228
246
|
missingKeywords: string[];
|
|
229
247
|
overusedKeywords: string[];
|
|
230
248
|
suggestions: string[];
|
|
231
249
|
warnings: string[];
|
|
250
|
+
/** Years below the JD's minimum experience requirement; 0 when the requirement is met. */
|
|
251
|
+
experienceGap: number;
|
|
252
|
+
/** Resume sections the parser successfully detected (e.g. "summary", "skills"). */
|
|
253
|
+
detectedSections: string[];
|
|
254
|
+
/** Total years of experience parsed from the resume's date ranges. */
|
|
255
|
+
parsedExperienceYears: number;
|
|
256
|
+
/** Parsed experience entries from the resume, with titles and date ranges. */
|
|
257
|
+
experienceEntries: ParsedExperienceEntry[];
|
|
232
258
|
}
|
|
233
259
|
|
|
234
260
|
declare const defaultSkillAliases: SkillAliases;
|
|
@@ -471,18 +497,12 @@ declare function safeExtractNumber(obj: unknown, key: string): number | undefine
|
|
|
471
497
|
*/
|
|
472
498
|
declare function analyzeResume(input: AnalyzeResumeInput): ATSAnalysisResult;
|
|
473
499
|
/**
|
|
474
|
-
*
|
|
475
|
-
*
|
|
500
|
+
* @deprecated The LLM layer only rewrites suggestion text and adds non-determinism.
|
|
501
|
+
* Prefer `analyzeResume` (sync, deterministic) and call your own LLM on the result if needed.
|
|
502
|
+
* This function will be removed in a future major version.
|
|
476
503
|
*
|
|
477
504
|
* @param input Resume, job description, and optional LLM config
|
|
478
505
|
* @returns Promise<ATSAnalysisResult>
|
|
479
|
-
*
|
|
480
|
-
* @example
|
|
481
|
-
* const result = await analyzeResumeAsync({
|
|
482
|
-
* resumeText,
|
|
483
|
-
* jobDescription,
|
|
484
|
-
* llm: { client, limits: {...}, enable: { suggestions: true } }
|
|
485
|
-
* });
|
|
486
506
|
*/
|
|
487
507
|
declare function analyzeResumeAsync(input: AnalyzeResumeInput): Promise<ATSAnalysisResult>;
|
|
488
508
|
|