Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/vin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export interface VINDecoded {
region: string;
country: string;
modelYear: string;
possibleModelYears: number[];
manufacturer: string;
};
}
Expand Down Expand Up @@ -79,7 +80,7 @@ export const decodeVIN = (vin: string): VINDecoded => {
const split = splitVIN(vin);
const region = getRegion(split.wmi);
const country = getCountry(split.wmi);
const modelYear = getModelYear(vin);
const { modelYear, possibleModelYears } = getModelYear(vin);
const manufacturer = getManufacturer(split.wmi);

return {
Expand All @@ -89,6 +90,7 @@ export const decodeVIN = (vin: string): VINDecoded => {
region,
country,
modelYear,
possibleModelYears,
manufacturer,
},
};
Expand Down
13 changes: 8 additions & 5 deletions src/year.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,20 @@ import { years } from './constants/year.constant';

// If the manufacturer chooses to designate year, it is recommended that the year be indicated by the first character of the VIS. (10th character)
// The recommended code to be used when designating year is indicated in year.constant file.
export const getModelYear = (vin: string): string => {
export const getModelYear = (vin: string): {
modelYear: string;
possibleModelYears: number[]
} => {
vin = vin.toUpperCase();
const candidateModelYear = vin.substring(9, 10);
const candidateYears = years[candidateModelYear as keyof typeof years];
const possibleModelYears = years[candidateModelYear as keyof typeof years];

const validationCharacter = vin.substring(6, 7);

// Check if the validationCharacter is a Number
const modelYear: string = /^\d+$/.test(validationCharacter)
? candidateYears?.find((year) => year < 2010)?.toString() || '-'
: candidateYears?.find((year) => year >= 2010)?.toString() || '-';
? possibleModelYears?.find((year) => year < 2010)?.toString() || '-'
: possibleModelYears?.find((year) => year >= 2010)?.toString() || '-';

return modelYear;
return { modelYear, possibleModelYears }
};
74 changes: 72 additions & 2 deletions tests/universal-vin-decoder.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,16 @@ describe('Universal VIN Decoder', () => {

describe('#Model Year', () => {
test('Model Year is computed correctly.', () => {
expect(getModelYear('W1N2476871W240290')).toEqual('2001');
expect(getModelYear('W1N2476871W240290')).toEqual({
modelYear: '2001',
possibleModelYears: [
2001,
2031
]
});
});
test('Model Year is not defined by the manufacturer.', () => {
expect(getModelYear('WBA11CM0X08C97826')).toEqual('-');
expect(getModelYear('WBA11CM0X08C97826')).toEqual({ modelYear: '-' });
});
});

Expand Down Expand Up @@ -95,6 +101,10 @@ describe('Universal VIN Decoder', () => {
country: 'Germany',
modelYear: '2023',
manufacturer: 'Mercedes-Benz car',
possibleModelYears: [
1993,
2023
],
},
});
expect(decodeVIN('W1N2476871W240290')).toEqual({
Expand All @@ -105,6 +115,10 @@ describe('Universal VIN Decoder', () => {
country: 'Germany',
modelYear: '2001',
manufacturer: 'Mercedes-Benz SUV',
possibleModelYears: [
2001,
2031
],
},
});
expect(decodeVIN('W1K3F8CB3PN299204')).toEqual({
Expand All @@ -115,6 +129,10 @@ describe('Universal VIN Decoder', () => {
country: 'Germany',
modelYear: '2023',
manufacturer: 'Mercedes-Benz car',
possibleModelYears: [
1993,
2023
],
},
});
});
Expand Down Expand Up @@ -193,6 +211,10 @@ describe('Universal VIN Decoder', () => {
country: 'France',
modelYear: '2007',
manufacturer: 'Renault & Eagle Medallion made by Renault',
possibleModelYears: [
2007,
2037
],
},
});
expect(decodeVIN('VF1RJK00870326167')).toEqual({
Expand All @@ -203,6 +225,10 @@ describe('Universal VIN Decoder', () => {
country: 'France',
modelYear: '2007',
manufacturer: 'Renault & Eagle Medallion made by Renault',
possibleModelYears: [
2007,
2037
],
},
});
expect(decodeVIN('VF1RJK00870326167')).toEqual({
Expand All @@ -213,6 +239,10 @@ describe('Universal VIN Decoder', () => {
country: 'France',
modelYear: '2007',
manufacturer: 'Renault & Eagle Medallion made by Renault',
possibleModelYears: [
2007,
2037
],
},
});
});
Expand All @@ -225,6 +255,10 @@ describe('Universal VIN Decoder', () => {
country: 'France',
modelYear: '2021',
manufacturer: 'Citroën',
possibleModelYears: [
1991,
2021,
],
},
});
expect(decodeVIN('VR7EFYHT2PN547380')).toEqual({
Expand All @@ -235,6 +269,10 @@ describe('Universal VIN Decoder', () => {
country: 'France',
modelYear: '2023',
manufacturer: 'Citroën',
possibleModelYears: [
1993,
2023,
],
},
});
expect(decodeVIN('VR7EFYHT2PJ708414')).toEqual({
Expand All @@ -245,6 +283,10 @@ describe('Universal VIN Decoder', () => {
country: 'France',
modelYear: '2023',
manufacturer: 'Citroën',
possibleModelYears: [
1993,
2023,
],
},
});
});
Expand All @@ -257,6 +299,10 @@ describe('Universal VIN Decoder', () => {
country: 'South Korea',
modelYear: '1993',
manufacturer: 'Kia car',
possibleModelYears: [
1993,
2023,
],
},
});
expect(decodeVIN('KNADA818AP6838826')).toEqual({
Expand All @@ -267,6 +313,10 @@ describe('Universal VIN Decoder', () => {
country: 'South Korea',
modelYear: '1993',
manufacturer: 'Kia car',
possibleModelYears: [
1993,
2023,
],
},
});
expect(decodeVIN('KNADA818ART907403')).toEqual({
Expand All @@ -277,8 +327,28 @@ describe('Universal VIN Decoder', () => {
country: 'South Korea',
modelYear: '1994',
manufacturer: 'Kia car',
possibleModelYears: [
1994,
2024,
],
},
});
});
test('Honda VUNs are decoded correctly', () => {
expect(decodeVIN('JHMGK3770HX000000')).toEqual({
info: {
country: "Japan",
manufacturer: "Honda car",
modelYear: "1987",
possibleModelYears: [
1987,
2017,
],
region: "Asia",
},
isValid: true,
vin: "JHMGK3770HX000000",
});
})
});
});