@pranavraut033/ats-checker 0.1.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 +47 -0
- package/dist/index.d.mts +135 -0
- package/dist/index.d.ts +135 -0
- package/dist/index.js +757 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +753 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +44 -0
package/README.md
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# ats-checker
|
|
2
|
+
|
|
3
|
+
Deterministic, configurable ATS (Applicant Tracking System) compatibility checker with no external dependencies. Provides a single entry point `analyzeResume()` and extensible configuration for weights, skills, rules, and profiles.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install ats-checker
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick start
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { analyzeResume } from "ats-checker";
|
|
15
|
+
|
|
16
|
+
const { score, breakdown, suggestions } = analyzeResume({
|
|
17
|
+
resumeText: "...",
|
|
18
|
+
jobDescription: "..."
|
|
19
|
+
});
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Configuration
|
|
23
|
+
|
|
24
|
+
- **weights**: adjust scoring weight for skills, experience, keywords, and education.
|
|
25
|
+
- **skillAliases**: normalize synonyms to canonical skills.
|
|
26
|
+
- **profile**: specify mandatory/optional skills and minimum years of experience.
|
|
27
|
+
- **rules**: add custom penalties via functions that inspect parsed resume/job data.
|
|
28
|
+
|
|
29
|
+
See `src/types` for full type definitions.
|
|
30
|
+
|
|
31
|
+
## Development
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npm install
|
|
35
|
+
npm run build
|
|
36
|
+
npm test
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Features
|
|
40
|
+
|
|
41
|
+
- Zero runtime dependencies
|
|
42
|
+
- Deterministic, explainable scoring (0-100)
|
|
43
|
+
- Customizable weights, rules, and industry profiles
|
|
44
|
+
- Parses resumes and job descriptions
|
|
45
|
+
- Detects ATS-unfriendly patterns (tables, keyword stuffing)
|
|
46
|
+
- Generates actionable suggestions
|
|
47
|
+
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
type ResumeSection = "summary" | "experience" | "skills" | "education" | "projects" | "certifications";
|
|
2
|
+
interface ParsedDateRange {
|
|
3
|
+
raw?: string;
|
|
4
|
+
start?: string;
|
|
5
|
+
end?: string;
|
|
6
|
+
durationInMonths?: number;
|
|
7
|
+
}
|
|
8
|
+
interface ParsedExperienceEntry {
|
|
9
|
+
title?: string;
|
|
10
|
+
company?: string;
|
|
11
|
+
location?: string;
|
|
12
|
+
dates?: ParsedDateRange;
|
|
13
|
+
description?: string;
|
|
14
|
+
}
|
|
15
|
+
interface ParsedResume {
|
|
16
|
+
raw: string;
|
|
17
|
+
normalizedText: string;
|
|
18
|
+
detectedSections: ResumeSection[];
|
|
19
|
+
sectionContent: Partial<Record<ResumeSection, string>>;
|
|
20
|
+
skills: string[];
|
|
21
|
+
jobTitles: string[];
|
|
22
|
+
actionVerbs: string[];
|
|
23
|
+
educationEntries: string[];
|
|
24
|
+
experience: ParsedExperienceEntry[];
|
|
25
|
+
totalExperienceYears: number;
|
|
26
|
+
keywords: string[];
|
|
27
|
+
warnings: string[];
|
|
28
|
+
}
|
|
29
|
+
interface ParsedJobDescription {
|
|
30
|
+
raw: string;
|
|
31
|
+
normalizedText: string;
|
|
32
|
+
requiredSkills: string[];
|
|
33
|
+
preferredSkills: string[];
|
|
34
|
+
roleKeywords: string[];
|
|
35
|
+
keywords: string[];
|
|
36
|
+
minExperienceYears?: number;
|
|
37
|
+
educationRequirements: string[];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
interface ATSWeights {
|
|
41
|
+
skills: number;
|
|
42
|
+
experience: number;
|
|
43
|
+
keywords: number;
|
|
44
|
+
education: number;
|
|
45
|
+
}
|
|
46
|
+
type SkillAliases = Record<string, string[]>;
|
|
47
|
+
interface ATSProfile {
|
|
48
|
+
name: string;
|
|
49
|
+
mandatorySkills: string[];
|
|
50
|
+
optionalSkills: string[];
|
|
51
|
+
minExperience?: number;
|
|
52
|
+
}
|
|
53
|
+
interface KeywordDensityConfig {
|
|
54
|
+
/** Minimum density before a keyword is considered underused (informational only). */
|
|
55
|
+
min: number;
|
|
56
|
+
/** Maximum density before a keyword is considered stuffed. */
|
|
57
|
+
max: number;
|
|
58
|
+
/** Penalty applied when density exceeds max. */
|
|
59
|
+
overusePenalty: number;
|
|
60
|
+
}
|
|
61
|
+
interface SectionPenaltyConfig {
|
|
62
|
+
missingSummary?: number;
|
|
63
|
+
missingExperience?: number;
|
|
64
|
+
missingSkills?: number;
|
|
65
|
+
missingEducation?: number;
|
|
66
|
+
}
|
|
67
|
+
interface ATSRule {
|
|
68
|
+
id: string;
|
|
69
|
+
description?: string;
|
|
70
|
+
penalty: number;
|
|
71
|
+
warning?: string;
|
|
72
|
+
condition: (context: RuleContext) => boolean;
|
|
73
|
+
}
|
|
74
|
+
interface ATSConfig {
|
|
75
|
+
weights?: Partial<ATSWeights>;
|
|
76
|
+
skillAliases?: SkillAliases;
|
|
77
|
+
profile?: ATSProfile;
|
|
78
|
+
rules?: ATSRule[];
|
|
79
|
+
keywordDensity?: KeywordDensityConfig;
|
|
80
|
+
sectionPenalties?: SectionPenaltyConfig;
|
|
81
|
+
allowPartialMatches?: boolean;
|
|
82
|
+
}
|
|
83
|
+
interface NormalizedWeights extends ATSWeights {
|
|
84
|
+
/** Weights normalized so they sum to 1. */
|
|
85
|
+
normalizedTotal: number;
|
|
86
|
+
}
|
|
87
|
+
interface ResolvedATSConfig {
|
|
88
|
+
weights: NormalizedWeights;
|
|
89
|
+
skillAliases: SkillAliases;
|
|
90
|
+
profile?: ATSProfile;
|
|
91
|
+
rules: ATSRule[];
|
|
92
|
+
keywordDensity: KeywordDensityConfig;
|
|
93
|
+
sectionPenalties: Required<SectionPenaltyConfig>;
|
|
94
|
+
allowPartialMatches: boolean;
|
|
95
|
+
}
|
|
96
|
+
interface RuleContext {
|
|
97
|
+
resume: ParsedResume;
|
|
98
|
+
job: ParsedJobDescription;
|
|
99
|
+
weights: NormalizedWeights;
|
|
100
|
+
keywordDensity: KeywordDensityConfig;
|
|
101
|
+
breakdown?: ATSBreakdown;
|
|
102
|
+
matchedKeywords?: string[];
|
|
103
|
+
overusedKeywords?: string[];
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
interface ATSBreakdown {
|
|
107
|
+
skills: number;
|
|
108
|
+
experience: number;
|
|
109
|
+
keywords: number;
|
|
110
|
+
education: number;
|
|
111
|
+
}
|
|
112
|
+
interface AnalyzeResumeInput {
|
|
113
|
+
resumeText: string;
|
|
114
|
+
jobDescription: string;
|
|
115
|
+
config?: ATSConfig;
|
|
116
|
+
}
|
|
117
|
+
interface ATSAnalysisResult {
|
|
118
|
+
score: number;
|
|
119
|
+
breakdown: ATSBreakdown;
|
|
120
|
+
matchedKeywords: string[];
|
|
121
|
+
missingKeywords: string[];
|
|
122
|
+
overusedKeywords: string[];
|
|
123
|
+
suggestions: string[];
|
|
124
|
+
warnings: string[];
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
declare const defaultSkillAliases: SkillAliases;
|
|
128
|
+
declare const defaultProfiles: ATSProfile[];
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Analyze a resume against a job description using deterministic, explainable rules.
|
|
132
|
+
*/
|
|
133
|
+
declare function analyzeResume(input: AnalyzeResumeInput): ATSAnalysisResult;
|
|
134
|
+
|
|
135
|
+
export { type ATSAnalysisResult, type ATSBreakdown, type ATSConfig, type ATSProfile, type ATSRule, type ATSWeights, type AnalyzeResumeInput, type KeywordDensityConfig, type NormalizedWeights, type ParsedDateRange, type ParsedExperienceEntry, type ParsedJobDescription, type ParsedResume, type ResolvedATSConfig, type ResumeSection, type RuleContext, type SectionPenaltyConfig, type SkillAliases, analyzeResume, defaultProfiles, defaultSkillAliases };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
type ResumeSection = "summary" | "experience" | "skills" | "education" | "projects" | "certifications";
|
|
2
|
+
interface ParsedDateRange {
|
|
3
|
+
raw?: string;
|
|
4
|
+
start?: string;
|
|
5
|
+
end?: string;
|
|
6
|
+
durationInMonths?: number;
|
|
7
|
+
}
|
|
8
|
+
interface ParsedExperienceEntry {
|
|
9
|
+
title?: string;
|
|
10
|
+
company?: string;
|
|
11
|
+
location?: string;
|
|
12
|
+
dates?: ParsedDateRange;
|
|
13
|
+
description?: string;
|
|
14
|
+
}
|
|
15
|
+
interface ParsedResume {
|
|
16
|
+
raw: string;
|
|
17
|
+
normalizedText: string;
|
|
18
|
+
detectedSections: ResumeSection[];
|
|
19
|
+
sectionContent: Partial<Record<ResumeSection, string>>;
|
|
20
|
+
skills: string[];
|
|
21
|
+
jobTitles: string[];
|
|
22
|
+
actionVerbs: string[];
|
|
23
|
+
educationEntries: string[];
|
|
24
|
+
experience: ParsedExperienceEntry[];
|
|
25
|
+
totalExperienceYears: number;
|
|
26
|
+
keywords: string[];
|
|
27
|
+
warnings: string[];
|
|
28
|
+
}
|
|
29
|
+
interface ParsedJobDescription {
|
|
30
|
+
raw: string;
|
|
31
|
+
normalizedText: string;
|
|
32
|
+
requiredSkills: string[];
|
|
33
|
+
preferredSkills: string[];
|
|
34
|
+
roleKeywords: string[];
|
|
35
|
+
keywords: string[];
|
|
36
|
+
minExperienceYears?: number;
|
|
37
|
+
educationRequirements: string[];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
interface ATSWeights {
|
|
41
|
+
skills: number;
|
|
42
|
+
experience: number;
|
|
43
|
+
keywords: number;
|
|
44
|
+
education: number;
|
|
45
|
+
}
|
|
46
|
+
type SkillAliases = Record<string, string[]>;
|
|
47
|
+
interface ATSProfile {
|
|
48
|
+
name: string;
|
|
49
|
+
mandatorySkills: string[];
|
|
50
|
+
optionalSkills: string[];
|
|
51
|
+
minExperience?: number;
|
|
52
|
+
}
|
|
53
|
+
interface KeywordDensityConfig {
|
|
54
|
+
/** Minimum density before a keyword is considered underused (informational only). */
|
|
55
|
+
min: number;
|
|
56
|
+
/** Maximum density before a keyword is considered stuffed. */
|
|
57
|
+
max: number;
|
|
58
|
+
/** Penalty applied when density exceeds max. */
|
|
59
|
+
overusePenalty: number;
|
|
60
|
+
}
|
|
61
|
+
interface SectionPenaltyConfig {
|
|
62
|
+
missingSummary?: number;
|
|
63
|
+
missingExperience?: number;
|
|
64
|
+
missingSkills?: number;
|
|
65
|
+
missingEducation?: number;
|
|
66
|
+
}
|
|
67
|
+
interface ATSRule {
|
|
68
|
+
id: string;
|
|
69
|
+
description?: string;
|
|
70
|
+
penalty: number;
|
|
71
|
+
warning?: string;
|
|
72
|
+
condition: (context: RuleContext) => boolean;
|
|
73
|
+
}
|
|
74
|
+
interface ATSConfig {
|
|
75
|
+
weights?: Partial<ATSWeights>;
|
|
76
|
+
skillAliases?: SkillAliases;
|
|
77
|
+
profile?: ATSProfile;
|
|
78
|
+
rules?: ATSRule[];
|
|
79
|
+
keywordDensity?: KeywordDensityConfig;
|
|
80
|
+
sectionPenalties?: SectionPenaltyConfig;
|
|
81
|
+
allowPartialMatches?: boolean;
|
|
82
|
+
}
|
|
83
|
+
interface NormalizedWeights extends ATSWeights {
|
|
84
|
+
/** Weights normalized so they sum to 1. */
|
|
85
|
+
normalizedTotal: number;
|
|
86
|
+
}
|
|
87
|
+
interface ResolvedATSConfig {
|
|
88
|
+
weights: NormalizedWeights;
|
|
89
|
+
skillAliases: SkillAliases;
|
|
90
|
+
profile?: ATSProfile;
|
|
91
|
+
rules: ATSRule[];
|
|
92
|
+
keywordDensity: KeywordDensityConfig;
|
|
93
|
+
sectionPenalties: Required<SectionPenaltyConfig>;
|
|
94
|
+
allowPartialMatches: boolean;
|
|
95
|
+
}
|
|
96
|
+
interface RuleContext {
|
|
97
|
+
resume: ParsedResume;
|
|
98
|
+
job: ParsedJobDescription;
|
|
99
|
+
weights: NormalizedWeights;
|
|
100
|
+
keywordDensity: KeywordDensityConfig;
|
|
101
|
+
breakdown?: ATSBreakdown;
|
|
102
|
+
matchedKeywords?: string[];
|
|
103
|
+
overusedKeywords?: string[];
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
interface ATSBreakdown {
|
|
107
|
+
skills: number;
|
|
108
|
+
experience: number;
|
|
109
|
+
keywords: number;
|
|
110
|
+
education: number;
|
|
111
|
+
}
|
|
112
|
+
interface AnalyzeResumeInput {
|
|
113
|
+
resumeText: string;
|
|
114
|
+
jobDescription: string;
|
|
115
|
+
config?: ATSConfig;
|
|
116
|
+
}
|
|
117
|
+
interface ATSAnalysisResult {
|
|
118
|
+
score: number;
|
|
119
|
+
breakdown: ATSBreakdown;
|
|
120
|
+
matchedKeywords: string[];
|
|
121
|
+
missingKeywords: string[];
|
|
122
|
+
overusedKeywords: string[];
|
|
123
|
+
suggestions: string[];
|
|
124
|
+
warnings: string[];
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
declare const defaultSkillAliases: SkillAliases;
|
|
128
|
+
declare const defaultProfiles: ATSProfile[];
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Analyze a resume against a job description using deterministic, explainable rules.
|
|
132
|
+
*/
|
|
133
|
+
declare function analyzeResume(input: AnalyzeResumeInput): ATSAnalysisResult;
|
|
134
|
+
|
|
135
|
+
export { type ATSAnalysisResult, type ATSBreakdown, type ATSConfig, type ATSProfile, type ATSRule, type ATSWeights, type AnalyzeResumeInput, type KeywordDensityConfig, type NormalizedWeights, type ParsedDateRange, type ParsedExperienceEntry, type ParsedJobDescription, type ParsedResume, type ResolvedATSConfig, type ResumeSection, type RuleContext, type SectionPenaltyConfig, type SkillAliases, analyzeResume, defaultProfiles, defaultSkillAliases };
|