From 39a01e97fd021b2323629e92de0e3764952d4eec Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Sat, 29 May 2021 19:49:29 +0200 Subject: [PATCH 01/22] Add support for 2-character manufacturer codes in the WMI Some manufacturers use the first 2 characters of the WMI as the manufacturer ID, with the 3rd denoting the specific class of vehicle specific to that manufacturer. Fixes #7. --- CHANGELOG.md | 4 ++++ lib/src/vin_decoder_base.dart | 10 +++++++++- test/vin_decoder_test.dart | 22 ++++++++++++++++++++++ 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a17f02f..9d00737 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.1.4 + +- Support VINs with 2-character manufacturer IDs in their WMI (reported by @huangkaichang, issue #7) + ## 0.1.3 - Update dependencies diff --git a/lib/src/vin_decoder_base.dart b/lib/src/vin_decoder_base.dart index d0655c3..e95caff 100644 --- a/lib/src/vin_decoder_base.dart +++ b/lib/src/vin_decoder_base.dart @@ -65,10 +65,18 @@ class VIN { /// Get the full name of the vehicle manufacturer as defined by the [wmi]. String? getManufacturer() { + // Check for the standard case - a 3 character WMI if (manufacturers.containsKey(this.wmi)) { return manufacturers[this.wmi]; } else { - return "Unknown (WMI: ${this.wmi.toUpperCase()})"; + // Some manufacturers only use the first 2 characters for manufacturer + // identification, and the third for the class of vehicle. + var id = this.wmi.substring(0, 2); + if (manufacturers.containsKey(id)) { + return manufacturers[id]; + } else { + return "Unknown (WMI: ${this.wmi.toUpperCase()})"; + } } } diff --git a/test/vin_decoder_test.dart b/test/vin_decoder_test.dart index 3089f96..9448418 100644 --- a/test/vin_decoder_test.dart +++ b/test/vin_decoder_test.dart @@ -37,4 +37,26 @@ void main() { expect(vin.getRegion(), 'AS'); }); }); + + group('2-character WMI Manufacturer Test', () { + late VIN vin; + + setUp(() { + // Here the first 2 characters refer to the manufacturer, with the 3rd + // representing the class of vehicle specific to that manufacturer. + vin = VIN(number: '5TENL42N94Z436445'); + }); + + test('Validity Test', () { + expect(vin.valid(), isTrue); + }); + + test('Region Test', () { + expect(vin.getRegion(), 'NA'); + }); + + test('Manufacturer Test', () { + expect(vin.getManufacturer(), 'Toyota - trucks'); + }); + }); } From 1010c47645e8701eeffae3cb3f9f545a6ecad3a4 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Sat, 29 May 2021 20:18:40 +0200 Subject: [PATCH 02/22] Update stable release to 0.1.4 --- CHANGELOG.md | 1 + pubspec.yaml | 10 +++++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d00737..c9c42b9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ ## 0.1.4 - Support VINs with 2-character manufacturer IDs in their WMI (reported by @huangkaichang, issue #7) +- Fix Uri parsing for NHTSA DB REST API ## 0.1.3 diff --git a/pubspec.yaml b/pubspec.yaml index c59c682..a8d3ba5 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -3,7 +3,7 @@ description: Dart library for working with Vehicle Identification Numbers (VINs) based on ISO 3779:2009 and World Manufacturer Identifiers (WMIs) based on ISO 3780:2009, enriched by NHTSA data. -version: 0.1.3 +version: 0.1.4 repository: https://github.com/adaptant-labs/vin-decoder-dart issue_tracker: https://github.com/adaptant-labs/vin-decoder-dart/issues @@ -11,9 +11,9 @@ environment: sdk: '>=2.12.0 <3.0.0' dependencies: - basic_utils: ^3.0.0-nullsafety.0 - http: ^0.13.0 - random_string: ^2.2.0-nullsafety + basic_utils: ^3.1.0 + http: ^0.13.3 + random_string: ^2.1.0 dev_dependencies: - test: ^1.16.5 + test: ^1.17.5 From 235f9cba4a04a64a8aa8f5fc558ca61e2665c067 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Sat, 29 May 2021 20:21:38 +0200 Subject: [PATCH 03/22] Reduce dart SDK constraints for unsound null safety For sound null safety, use the -nullsafety pre-releases until such a time that all of the package dependencies have migrated. --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index a8d3ba5..bdf1dd8 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -8,7 +8,7 @@ repository: https://github.com/adaptant-labs/vin-decoder-dart issue_tracker: https://github.com/adaptant-labs/vin-decoder-dart/issues environment: - sdk: '>=2.12.0 <3.0.0' + sdk: '>=2.1.0 <3.0.0' dependencies: basic_utils: ^3.1.0 From 3740e6a39be8f608632588834ed88103cdff7fd3 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Sat, 29 May 2021 20:38:21 +0200 Subject: [PATCH 04/22] Revert "null safety migration" for stable release This reverts commit e739c20c491cf4b1176a8545503dba6be9594960. --- CHANGELOG.md | 4 ++++ example/vin_decoder_example.dart | 2 +- lib/src/nhtsa_model.dart | 38 ++++++++++++++++---------------- lib/src/vin_decoder_base.dart | 20 +++++++++-------- lib/vin_decoder.dart | 1 + pubspec.yaml | 9 ++++---- test/vin_decoder_test.dart | 22 +++++------------- test/vin_generator_test.dart | 2 +- 8 files changed, 47 insertions(+), 51 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c9c42b9..d59941e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.1.4+1 + +- Revert null-safety changes from stable release to satisfy SDK constraints + ## 0.1.4 - Support VINs with 2-character manufacturer IDs in their WMI (reported by @huangkaichang, issue #7) diff --git a/example/vin_decoder_example.dart b/example/vin_decoder_example.dart index 7da9a33..4bc2f02 100644 --- a/example/vin_decoder_example.dart +++ b/example/vin_decoder_example.dart @@ -10,7 +10,7 @@ void main() async { print("Model year is " + vin.modelYear()); print("Serial number is " + vin.serialNumber()); print("Assembly plant is " + vin.assemblyPlant()); - print("Manufacturer is " + vin.getManufacturer()!); + print("Manufacturer is " + vin.getManufacturer()); print("Year is " + vin.getYear().toString()); print("Region is " + vin.getRegion()); print("VIN string is " + vin.toString()); diff --git a/lib/src/nhtsa_model.dart b/lib/src/nhtsa_model.dart index c9ffa27..feb48ab 100644 --- a/lib/src/nhtsa_model.dart +++ b/lib/src/nhtsa_model.dart @@ -3,10 +3,10 @@ import 'package:http/http.dart' as http; import 'dart:convert'; class NHTSAResult { - String? value; - String? valueId; - String? variable; - int? variableId; + String value; + String valueId; + String variable; + int variableId; NHTSAResult({this.value, this.valueId, this.variable, this.variableId}); @@ -24,10 +24,10 @@ class NHTSAResult { } class NHTSAVehicleInfo { - int? count; - String? message; - String? searchCriteria; - List? results; + int count; + String message; + String searchCriteria; + List results; NHTSAVehicleInfo( {this.count, this.message, this.searchCriteria, this.results}); @@ -37,10 +37,10 @@ class NHTSAVehicleInfo { message = json['Message']; searchCriteria = json['SearchCriteria']; if (json['Results'] != null) { - results = []; + results = List(); json['Results'].forEach((v) { if (v['Value'] != null) { - results!.add(NHTSAResult.fromJson(v)); + results.add(NHTSAResult.fromJson(v)); } }); } @@ -54,16 +54,16 @@ class NHTSAVehicleInfo { ExtendedVehicleInfo toExtendedVehicleInfo() { final ExtendedVehicleInfo info = ExtendedVehicleInfo(); - results!.forEach((f) { + results.forEach((f) { switch (f.variable) { case "Vehicle Type": - info.vehicleType = normalizeStringValue(f.value!); + info.vehicleType = normalizeStringValue(f.value); break; case "Make": - info.make = normalizeStringValue(f.value!); + info.make = normalizeStringValue(f.value); break; case "Model": - info.model = normalizeStringValue(f.value!); + info.model = normalizeStringValue(f.value); break; } }); @@ -78,12 +78,12 @@ class NHTSAVehicleInfo { } class ExtendedVehicleInfo { - String? make; - String? model; - String? vehicleType; + String make; + String model; + String vehicleType; - static Future getExtendedVehicleInfo(String vin) async { - var path = 'https://vpic.nhtsa.dot.gov/api/vehicles/DecodeVin/' + + static Future getExtendedVehicleInfo(String vin) async { + var path = 'https://vpic.nhtsa.dot.gov/api//vehicles/DecodeVin/' + vin + '?format=json'; final response = await http.get(Uri.parse(path)); diff --git a/lib/src/vin_decoder_base.dart b/lib/src/vin_decoder_base.dart index e95caff..1c2da85 100644 --- a/lib/src/vin_decoder_base.dart +++ b/lib/src/vin_decoder_base.dart @@ -2,6 +2,8 @@ import 'manufacturers.dart'; import 'nhtsa_model.dart'; import 'year_map.dart'; +import 'package:meta/meta.dart'; + class VIN { /// The VIN that the class was instantiated with. final String number; @@ -17,16 +19,16 @@ class VIN { /// Try to obtain extended information for the VIN from the NHTSA database. final bool extended; - ExtendedVehicleInfo? _info; + ExtendedVehicleInfo _info; - VIN({required this.number, this.extended = false}) + VIN({@required this.number, this.extended = false}) : wmi = normalize(number).substring(0, 3), vds = normalize(number).substring(3, 9), vis = normalize(number).substring(9, 17); /// Carry out VIN validation. A valid [number] must be 17 characters long /// and contain only valid alphanumeric characters. - bool valid([String? number]) { + bool valid([String number]) { String value = normalize(number != null ? number : this.number); return RegExp(r"^[a-zA-Z0-9]+$").hasMatch(value) && value.length == 17; } @@ -36,7 +38,7 @@ class VIN { number.toUpperCase().replaceAll('-', ''); /// Obtain the encoded manufacturing year in YYYY format. - int? getYear() { + int getYear() { return yearMap[modelYear()]; } @@ -64,7 +66,7 @@ class VIN { } /// Get the full name of the vehicle manufacturer as defined by the [wmi]. - String? getManufacturer() { + String getManufacturer() { // Check for the standard case - a 3 character WMI if (manufacturers.containsKey(this.wmi)) { return manufacturers[this.wmi]; @@ -83,7 +85,7 @@ class VIN { /// Returns the checksum for the VIN. Note that in the case of the EU region /// checksums are not implemented, so this becomes a no-op. More information /// is provided in ISO 3779:2009. - String? getChecksum() { + String getChecksum() { return (getRegion() != "EU") ? normalize(this.number)[8] : null; } @@ -105,21 +107,21 @@ class VIN { /// Get the Make of the vehicle from the NHTSA database if [extended] mode /// is enabled. - Future getMakeAsync() async { + Future getMakeAsync() async { await _fetchExtendedVehicleInfo(); return this._info?.make; } /// Get the Model of the vehicle from the NHTSA database if [extended] mode /// is enabled. - Future getModelAsync() async { + Future getModelAsync() async { await _fetchExtendedVehicleInfo(); return this._info?.model; } /// Get the Vehicle Type from the NHTSA database if [extended] mode is /// enabled. - Future getVehicleTypeAsync() async { + Future getVehicleTypeAsync() async { await _fetchExtendedVehicleInfo(); return this._info?.vehicleType; } diff --git a/lib/vin_decoder.dart b/lib/vin_decoder.dart index 84467c7..08f0c05 100644 --- a/lib/vin_decoder.dart +++ b/lib/vin_decoder.dart @@ -1,4 +1,5 @@ /// Support for VIN parsing, validation, and generation. +// @dart=2.9 library vin_decoder; diff --git a/pubspec.yaml b/pubspec.yaml index bdf1dd8..32604bf 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -3,7 +3,7 @@ description: Dart library for working with Vehicle Identification Numbers (VINs) based on ISO 3779:2009 and World Manufacturer Identifiers (WMIs) based on ISO 3780:2009, enriched by NHTSA data. -version: 0.1.4 +version: 0.1.4+1 repository: https://github.com/adaptant-labs/vin-decoder-dart issue_tracker: https://github.com/adaptant-labs/vin-decoder-dart/issues @@ -11,9 +11,10 @@ environment: sdk: '>=2.1.0 <3.0.0' dependencies: - basic_utils: ^3.1.0 - http: ^0.13.3 + meta: ^1.4.0 + basic_utils: ^2.7.1 + http: ^0.12.2 random_string: ^2.1.0 dev_dependencies: - test: ^1.17.5 + test: ^1.15.7 diff --git a/test/vin_decoder_test.dart b/test/vin_decoder_test.dart index 9448418..1527ae2 100644 --- a/test/vin_decoder_test.dart +++ b/test/vin_decoder_test.dart @@ -3,11 +3,7 @@ import 'package:test/test.dart'; void main() { group('EU VIN Test', () { - late VIN vin; - - setUp(() { - vin = VIN(number: 'WP0ZZZ99ZTS392124'); - }); + final vin = VIN(number: 'WP0ZZZ99ZTS392124'); test('Validity Test', () { expect(vin.valid(), isTrue); @@ -23,11 +19,7 @@ void main() { }); group('AS VIN Test', () { - late VIN vin; - - setUp(() { - vin = VIN(number: 'JS1VX51L7X2175460'); - }); + final vin = VIN(number: 'JS1VX51L7X2175460'); test('Validity Test', () { expect(vin.valid(), isTrue); @@ -39,13 +31,9 @@ void main() { }); group('2-character WMI Manufacturer Test', () { - late VIN vin; - - setUp(() { - // Here the first 2 characters refer to the manufacturer, with the 3rd - // representing the class of vehicle specific to that manufacturer. - vin = VIN(number: '5TENL42N94Z436445'); - }); + // Here the first 2 characters refer to the manufacturer, with the 3rd + // representing the class of vehicle specific to that manufacturer. + final vin = VIN(number: '5TENL42N94Z436445'); test('Validity Test', () { expect(vin.valid(), isTrue); diff --git a/test/vin_generator_test.dart b/test/vin_generator_test.dart index 0bd7695..9e4b067 100644 --- a/test/vin_generator_test.dart +++ b/test/vin_generator_test.dart @@ -4,7 +4,7 @@ import 'package:test/test.dart'; void main() { group('VIN Generator Test', () { VINGenerator generator; - late VIN vin; + VIN vin; setUp(() { generator = VINGenerator(); From 7635210c03914c639f61eda358f88210003c1a2c Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Sat, 29 May 2021 20:41:24 +0200 Subject: [PATCH 05/22] Match min dart SDK constraint for stable release --- lib/vin_decoder.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/vin_decoder.dart b/lib/vin_decoder.dart index 08f0c05..a596681 100644 --- a/lib/vin_decoder.dart +++ b/lib/vin_decoder.dart @@ -1,5 +1,5 @@ /// Support for VIN parsing, validation, and generation. -// @dart=2.9 +// @dart=2.1 library vin_decoder; From 2ce1cedd17fc2d1e8e86228142114a1ff2547f37 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Thu, 26 Aug 2021 01:50:38 +0200 Subject: [PATCH 06/22] Add .vscode to .gitignore --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 9591aae..2662521 100644 --- a/.gitignore +++ b/.gitignore @@ -5,9 +5,10 @@ # Remove the following pattern if you wish to check in your lock file pubspec.lock -# IntelliJ +# IntelliJ / IDEs *.iml .idea/ +.vscode/ # Conventional directory for build outputs build/ From dc082f1e0ec3aea79ea34d70ffc05e61e1c84e3f Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Thu, 26 Aug 2021 10:56:40 +0200 Subject: [PATCH 07/22] Expose NHTSA API accessors Presently the NHTSA DB results are trapped and filtered for the specific data points required by the VIN decoder, but this can be generalized in order to permit other variables exposed by the NHTSA API to be directly queried. Resolves #8 --- CHANGELOG.md | 4 ++ example/vin_decoder_example.dart | 7 ++ lib/nhtsa.dart | 5 ++ lib/src/nhtsa_model.dart | 113 ++++++++++++++++++------------- lib/src/vin_decoder_base.dart | 15 ++-- 5 files changed, 90 insertions(+), 54 deletions(-) create mode 100644 lib/nhtsa.dart diff --git a/CHANGELOG.md b/CHANGELOG.md index d59941e..544bafd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.2.0 + +- Expose helpers for querying NHTSA DB and accessing extended vehicle information (requested by @ride4sun, issue #8) + ## 0.1.4+1 - Revert null-safety changes from stable release to satisfy SDK constraints diff --git a/example/vin_decoder_example.dart b/example/vin_decoder_example.dart index 4bc2f02..96fe069 100644 --- a/example/vin_decoder_example.dart +++ b/example/vin_decoder_example.dart @@ -1,3 +1,4 @@ +import 'package:vin_decoder/nhtsa.dart'; import 'package:vin_decoder/vin_decoder.dart'; void main() async { @@ -25,6 +26,12 @@ void main() async { var type = await vin.getVehicleTypeAsync(); print("Type is ${type}"); + var info = await NHTSA.decodeVin(vin.number); + print('Plant Country is ' + info.value('Plant Country')); + + var values = await NHTSA.decodeVinValues(vin.number); + print('Manufacturer from NHTSA DB is ' + values['Manufacturer']); + var generated = VINGenerator().generate(); print('Randomly Generated VIN is ${generated}'); } diff --git a/lib/nhtsa.dart b/lib/nhtsa.dart new file mode 100644 index 0000000..0bddffa --- /dev/null +++ b/lib/nhtsa.dart @@ -0,0 +1,5 @@ +/// Support for querying NHTSA database by VIN. +// @dart=2.1 +library nhtsa; + +export 'src/nhtsa_model.dart'; diff --git a/lib/src/nhtsa_model.dart b/lib/src/nhtsa_model.dart index feb48ab..af28dfc 100644 --- a/lib/src/nhtsa_model.dart +++ b/lib/src/nhtsa_model.dart @@ -2,14 +2,63 @@ import 'package:basic_utils/basic_utils.dart'; import 'package:http/http.dart' as http; import 'dart:convert'; +// NHTSA Results not relevant for a specific vehicle can be either null or N/A +const String _RESULT_NOT_APPLICABLE = 'Not Applicable'; + +/// A wrapper for the NHTSA REST API +class NHTSA { + static const String _uriBase = 'https://vpic.nhtsa.dot.gov/api/vehicles'; + + /// Obtain information about a given [vin] from the NHTSA DB. + static Future decodeVin(String vin) async { + var path = _uriBase + '/DecodeVin/' + vin + '?format=json'; + final response = await http.get(Uri.parse(path)); + + if (response.statusCode == 200) { + return NHTSAVehicleInfo.fromJson(jsonDecode(response.body)); + } + + return null; + } + + /// Obtain a map of key/value pairs containing known values for a given [vin] + static Future> decodeVinValues(String vin) async { + var path = _uriBase + '/DecodeVinValues/' + vin + '?format=json'; + final response = await http.get(Uri.parse(path)); + + // The DecodeVinValues endpoint returns a single Results object with all + // variables and values as an array of encapsulated key/value pairs. + // Manually unpack this in order to provide the caller a populated Dart map. + if (response.statusCode == 200) { + Map data = jsonDecode(response.body); + Map map = data['Results'][0]; + // Discard empty and not applicable entries from map + map.removeWhere((key, value) => + value == null || value == _RESULT_NOT_APPLICABLE || value == ''); + return map; + } + + return null; + } +} + +/// The result of a single data point from the NHTSA DB for a specific variable. class NHTSAResult { + /// The value associated with a given [variable] or [variableId] String value; + + /// The ID number associated with a given [value] String valueId; + + /// The variable name String variable; + + /// The ID number of a given [variable] int variableId; NHTSAResult({this.value, this.valueId, this.variable, this.variableId}); + /// Create a new [NHTSAResult] instance from a fixed JSON payload NHTSAResult.fromJson(Map json) { value = json['Value']; valueId = json['ValueId']; @@ -23,81 +72,53 @@ class NHTSAResult { } } +/// Extended vehicle information for a specific VIN obtained from the NHTSA DB. class NHTSAVehicleInfo { int count; String message; String searchCriteria; - List results; + List results = []; NHTSAVehicleInfo( {this.count, this.message, this.searchCriteria, this.results}); + /// Create a new [NHTSAVehicleInfo] instance from a fixed JSON payload NHTSAVehicleInfo.fromJson(Map json) { count = json['Count']; message = json['Message']; searchCriteria = json['SearchCriteria']; if (json['Results'] != null) { - results = List(); json['Results'].forEach((v) { - if (v['Value'] != null) { + if (v['Value'] != null && + v['Value'] != _RESULT_NOT_APPLICABLE && + v['Value'] != '') { results.add(NHTSAResult.fromJson(v)); } }); } } - static String normalizeStringValue(String s) { + static String _normalizeStringValue(String s) { return s.splitMapJoin(' ', onNonMatch: (m) => StringUtils.capitalize(m.toLowerCase())); } - ExtendedVehicleInfo toExtendedVehicleInfo() { - final ExtendedVehicleInfo info = ExtendedVehicleInfo(); - - results.forEach((f) { - switch (f.variable) { - case "Vehicle Type": - info.vehicleType = normalizeStringValue(f.value); - break; - case "Make": - info.make = normalizeStringValue(f.value); - break; - case "Model": - info.model = normalizeStringValue(f.value); - break; - } - }); - - return info; - } - - @override - String toString() { - return 'NHTSAVehicleInfo[count=$count, message=$message, searchCriteria=$searchCriteria, results=$results]'; + /// Lookup the value of a variable by its [variableId] in the NHTSA DB results + String valueFromId(int variableId) { + var result = results.singleWhere((e) => e.variableId == variableId, + orElse: () => null); + return result != null ? _normalizeStringValue(result.value) : null; } -} - -class ExtendedVehicleInfo { - String make; - String model; - String vehicleType; - static Future getExtendedVehicleInfo(String vin) async { - var path = 'https://vpic.nhtsa.dot.gov/api//vehicles/DecodeVin/' + - vin + - '?format=json'; - final response = await http.get(Uri.parse(path)); - - if (response.statusCode == 200) { - var vehicleInfo = NHTSAVehicleInfo.fromJson(jsonDecode(response.body)); - return vehicleInfo.toExtendedVehicleInfo(); - } - - return null; + /// Lookup the value of a named [variable] in the NHTSA DB results + String value(String variable) { + var result = + results.singleWhere((e) => e.variable == variable, orElse: () => null); + return result != null ? _normalizeStringValue(result.value) : null; } @override String toString() { - return 'ExtendedVehicleInfo[make=$make, model=$model, vehicleType=$vehicleType]'; + return 'NHTSAVehicleInfo[count=$count, message=$message, searchCriteria=$searchCriteria, results=$results]'; } } diff --git a/lib/src/vin_decoder_base.dart b/lib/src/vin_decoder_base.dart index 1c2da85..21d84d1 100644 --- a/lib/src/vin_decoder_base.dart +++ b/lib/src/vin_decoder_base.dart @@ -19,7 +19,7 @@ class VIN { /// Try to obtain extended information for the VIN from the NHTSA database. final bool extended; - ExtendedVehicleInfo _info; + Map _vehicleInfo = {}; VIN({@required this.number, this.extended = false}) : wmi = normalize(number).substring(0, 3), @@ -98,10 +98,9 @@ class VIN { /// Extract the serial number from the [number]. String serialNumber() => normalize(this.number).substring(12, 17); - Future _fetchExtendedVehicleInfo() async { - if (this._info == null && extended == true) { - this._info = - await ExtendedVehicleInfo.getExtendedVehicleInfo(this.number); + Future _fetchExtendedVehicleInfo() async { + if (this._vehicleInfo.isEmpty && extended == true) { + this._vehicleInfo = await NHTSA.decodeVinValues(this.number); } } @@ -109,21 +108,21 @@ class VIN { /// is enabled. Future getMakeAsync() async { await _fetchExtendedVehicleInfo(); - return this._info?.make; + return this._vehicleInfo['Make']; } /// Get the Model of the vehicle from the NHTSA database if [extended] mode /// is enabled. Future getModelAsync() async { await _fetchExtendedVehicleInfo(); - return this._info?.model; + return this._vehicleInfo['Model']; } /// Get the Vehicle Type from the NHTSA database if [extended] mode is /// enabled. Future getVehicleTypeAsync() async { await _fetchExtendedVehicleInfo(); - return this._info?.vehicleType; + return this._vehicleInfo['VehicleType']; } @override From 00bb611c972a64054a605986ee9fcd9ac10ef69b Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Thu, 26 Aug 2021 11:17:10 +0200 Subject: [PATCH 08/22] Update Travis CI badge link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 28972bf..345871b 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ vin-decoder-dart ================ -[![Build Status](https://travis-ci.com/adaptant-labs/vin-decoder-dart.svg?branch=master)](https://travis-ci.com/adaptant-labs/vin-decoder-dart#) +[![Build Status](https://travis-ci.com/adaptant-labs/vin-decoder-dart.svg?branch=master)](https://app.travis-ci.com/github/adaptant-labs/vin-decoder-dart) [![Pub](https://img.shields.io/pub/v/vin_decoder.svg)](https://pub.dartlang.org/packages/vin_decoder) A VIN decoding, validation, and generation library for Dart. From 717aaf674bd9200b4a93e10e52dcea4fb565da19 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Thu, 26 Aug 2021 11:17:46 +0200 Subject: [PATCH 09/22] Bump up dependency versions --- pubspec.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pubspec.yaml b/pubspec.yaml index 32604bf..858c2d8 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -12,8 +12,8 @@ environment: dependencies: meta: ^1.4.0 - basic_utils: ^2.7.1 - http: ^0.12.2 + basic_utils: ^3.4.0 + http: ^0.13.3 random_string: ^2.1.0 dev_dependencies: From 6ea3d4268338632c9c8c1eb4cce5a0c73e9c3de3 Mon Sep 17 00:00:00 2001 From: Bailie Livingston Date: Fri, 2 Dec 2022 13:25:52 -0600 Subject: [PATCH 10/22] Nullsafety compliant --- AUTHORS | 3 +- CHANGELOG.md | 3 ++ example/vin_decoder_example.dart | 10 ++--- lib/nhtsa.dart | 1 - lib/src/nhtsa_model.dart | 64 ++++++++++++++++++-------------- lib/src/vin_decoder_base.dart | 13 +++---- lib/vin_decoder.dart | 1 - pubspec.yaml | 9 ++--- test/vin_decoder_test.dart | 2 +- test/vin_generator_test.dart | 4 +- 10 files changed, 60 insertions(+), 50 deletions(-) diff --git a/AUTHORS b/AUTHORS index 7d248e8..580b1f6 100644 --- a/AUTHORS +++ b/AUTHORS @@ -3,4 +3,5 @@ # # Name/Organization -Adaptant Labs \ No newline at end of file +Adaptant Labs +Stemco \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e725cc..d33e625 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## 0.2.1 +- Migrated completely to nullsafety + ## 0.2.0 - Expose helpers for querying NHTSA DB and accessing extended vehicle information (requested by @ride4sun, issue #8) diff --git a/example/vin_decoder_example.dart b/example/vin_decoder_example.dart index 96fe069..7471dc3 100644 --- a/example/vin_decoder_example.dart +++ b/example/vin_decoder_example.dart @@ -1,5 +1,5 @@ -import 'package:vin_decoder/nhtsa.dart'; -import 'package:vin_decoder/vin_decoder.dart'; +import 'package:custom_vin_decoder/nhtsa.dart'; +import 'package:custom_vin_decoder/vin_decoder.dart'; void main() async { var vin = VIN(number: 'WP0ZZZ99ZTS392124', extended: true); @@ -11,7 +11,7 @@ void main() async { print("Model year is " + vin.modelYear()); print("Serial number is " + vin.serialNumber()); print("Assembly plant is " + vin.assemblyPlant()); - print("Manufacturer is " + vin.getManufacturer()); + print("Manufacturer is " + (vin.getManufacturer() ?? "")); print("Year is " + vin.getYear().toString()); print("Region is " + vin.getRegion()); print("VIN string is " + vin.toString()); @@ -27,10 +27,10 @@ void main() async { print("Type is ${type}"); var info = await NHTSA.decodeVin(vin.number); - print('Plant Country is ' + info.value('Plant Country')); + print('Plant Country is ' + (info?.value('Plant Country') ?? "")); var values = await NHTSA.decodeVinValues(vin.number); - print('Manufacturer from NHTSA DB is ' + values['Manufacturer']); + print('Manufacturer from NHTSA DB is ' + values?['Manufacturer']); var generated = VINGenerator().generate(); print('Randomly Generated VIN is ${generated}'); diff --git a/lib/nhtsa.dart b/lib/nhtsa.dart index 0bddffa..44fd877 100644 --- a/lib/nhtsa.dart +++ b/lib/nhtsa.dart @@ -1,5 +1,4 @@ /// Support for querying NHTSA database by VIN. -// @dart=2.1 library nhtsa; export 'src/nhtsa_model.dart'; diff --git a/lib/src/nhtsa_model.dart b/lib/src/nhtsa_model.dart index af28dfc..74c626d 100644 --- a/lib/src/nhtsa_model.dart +++ b/lib/src/nhtsa_model.dart @@ -5,24 +5,25 @@ import 'dart:convert'; // NHTSA Results not relevant for a specific vehicle can be either null or N/A const String _RESULT_NOT_APPLICABLE = 'Not Applicable'; +// ignore: avoid_classes_with_only_static_members /// A wrapper for the NHTSA REST API class NHTSA { static const String _uriBase = 'https://vpic.nhtsa.dot.gov/api/vehicles'; /// Obtain information about a given [vin] from the NHTSA DB. - static Future decodeVin(String vin) async { + static Future decodeVin(String vin) async { var path = _uriBase + '/DecodeVin/' + vin + '?format=json'; final response = await http.get(Uri.parse(path)); if (response.statusCode == 200) { - return NHTSAVehicleInfo.fromJson(jsonDecode(response.body)); + return NHTSAVehicleInfo.fromJson(jsonDecode(response.body) as Map); } return null; } /// Obtain a map of key/value pairs containing known values for a given [vin] - static Future> decodeVinValues(String vin) async { + static Future?> decodeVinValues(String vin) async { var path = _uriBase + '/DecodeVinValues/' + vin + '?format=json'; final response = await http.get(Uri.parse(path)); @@ -30,8 +31,8 @@ class NHTSA { // variables and values as an array of encapsulated key/value pairs. // Manually unpack this in order to provide the caller a populated Dart map. if (response.statusCode == 200) { - Map data = jsonDecode(response.body); - Map map = data['Results'][0]; + final Map data = jsonDecode(response.body) as Map; + final Map map = data['Results'][0] as Map; // Discard empty and not applicable entries from map map.removeWhere((key, value) => value == null || value == _RESULT_NOT_APPLICABLE || value == ''); @@ -45,25 +46,27 @@ class NHTSA { /// The result of a single data point from the NHTSA DB for a specific variable. class NHTSAResult { /// The value associated with a given [variable] or [variableId] - String value; + String? value; /// The ID number associated with a given [value] - String valueId; + String? valueId; /// The variable name - String variable; + String? variable; /// The ID number of a given [variable] - int variableId; + int? variableId; - NHTSAResult({this.value, this.valueId, this.variable, this.variableId}); + NHTSAResult({required this.value, required this.valueId, required this.variable, required this.variableId}); /// Create a new [NHTSAResult] instance from a fixed JSON payload - NHTSAResult.fromJson(Map json) { - value = json['Value']; - valueId = json['ValueId']; - variable = json['Variable']; - variableId = json['VariableId']; + factory NHTSAResult.fromJson(Map json) { + return NHTSAResult( + value: json['Value'] as String?, + valueId: json['ValueId'] as String?, + variable: json['Variable'] as String?, + variableId: json['VariableId'] as int? + ); } @override @@ -80,13 +83,11 @@ class NHTSAVehicleInfo { List results = []; NHTSAVehicleInfo( - {this.count, this.message, this.searchCriteria, this.results}); + {required this.count, required this.message, required this.searchCriteria, required this.results}); /// Create a new [NHTSAVehicleInfo] instance from a fixed JSON payload - NHTSAVehicleInfo.fromJson(Map json) { - count = json['Count']; - message = json['Message']; - searchCriteria = json['SearchCriteria']; + factory NHTSAVehicleInfo.fromJson(Map json) { + List results = []; if (json['Results'] != null) { json['Results'].forEach((v) { if (v['Value'] != null && @@ -96,25 +97,34 @@ class NHTSAVehicleInfo { } }); } + return NHTSAVehicleInfo( + count: (json['Count'] as int?) ?? 0, + message: json['Message'] as String? ?? "", + searchCriteria: json['SearchCriteria'], + results: results + ); } - static String _normalizeStringValue(String s) { + static String? _normalizeStringValue(String? s) { + if (s == null){ + return null; + } return s.splitMapJoin(' ', onNonMatch: (m) => StringUtils.capitalize(m.toLowerCase())); } /// Lookup the value of a variable by its [variableId] in the NHTSA DB results - String valueFromId(int variableId) { + String? valueFromId(int? variableId) { var result = results.singleWhere((e) => e.variableId == variableId, - orElse: () => null); - return result != null ? _normalizeStringValue(result.value) : null; + orElse: () => NHTSAResult(value: null, valueId: null, variable: null, variableId: null)); + return _normalizeStringValue(result.value); } /// Lookup the value of a named [variable] in the NHTSA DB results - String value(String variable) { + String? value(String variable) { var result = - results.singleWhere((e) => e.variable == variable, orElse: () => null); - return result != null ? _normalizeStringValue(result.value) : null; + results.singleWhere((e) => e.variable == variable, orElse: () => NHTSAResult(value: null, valueId: null, variable: null, variableId: null)); + return _normalizeStringValue(result.value); } @override diff --git a/lib/src/vin_decoder_base.dart b/lib/src/vin_decoder_base.dart index e832b96..6e4ed98 100644 --- a/lib/src/vin_decoder_base.dart +++ b/lib/src/vin_decoder_base.dart @@ -2,8 +2,6 @@ import 'manufacturers.dart'; import 'nhtsa_model.dart'; import 'year_map.dart'; -import 'package:meta/meta.dart'; - class VIN { /// The VIN that the class was instantiated with. final String number; @@ -21,14 +19,14 @@ class VIN { final bool extended; Map _vehicleInfo = {}; - VIN({@required this.number, this.extended = false}) + VIN({required this.number, this.extended = false}) : wmi = normalize(number).substring(0, 3), vds = normalize(number).substring(3, 9), vis = normalize(number).substring(9, 17); /// Carry out VIN validation. A valid [number] must be 17 characters long /// and contain only valid alphanumeric characters. - bool valid([String number]) { + bool valid([String? number]) { String value = normalize(number != null ? number : this.number); return RegExp(r"^[a-zA-Z0-9]+$").hasMatch(value) && value.length == 17; } @@ -39,7 +37,7 @@ class VIN { /// Obtain the encoded manufacturing year in YYYY format. int getYear() { - return yearMap[modelYear()]; + return yearMap[modelYear()] ?? 2001; } /// Obtain the 2-character region code for the manufacturing region. @@ -85,7 +83,7 @@ class VIN { /// Returns the checksum for the VIN. Note that in the case of the EU region /// checksums are not implemented, so this becomes a no-op. More information /// is provided in ISO 3779:2009. - String getChecksum() { + String? getChecksum() { return (getRegion() != "EU") ? normalize(this.number)[8] : null; } @@ -98,9 +96,10 @@ class VIN { /// Extract the serial number from the [number]. String serialNumber() => normalize(this.number).substring(12, 17); + /// Assigns the Future _fetchExtendedVehicleInfo() async { if (this._vehicleInfo.isEmpty && extended == true) { - this._vehicleInfo = await NHTSA.decodeVinValues(this.number); + this._vehicleInfo = await NHTSA.decodeVinValues(this.number) ?? {}; } } diff --git a/lib/vin_decoder.dart b/lib/vin_decoder.dart index a596681..84467c7 100644 --- a/lib/vin_decoder.dart +++ b/lib/vin_decoder.dart @@ -1,5 +1,4 @@ /// Support for VIN parsing, validation, and generation. -// @dart=2.1 library vin_decoder; diff --git a/pubspec.yaml b/pubspec.yaml index 1163387..dbdedb9 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,19 +1,18 @@ -name: vin_decoder +name: custom_vin_decoder description: Dart library for working with Vehicle Identification Numbers (VINs) based on ISO 3779:2009 and World Manufacturer Identifiers (WMIs) based on ISO 3780:2009, enriched by NHTSA data. -version: 0.2.1-nullsafety +version: 0.2.1 repository: https://github.com/adaptant-labs/vin-decoder-dart issue_tracker: https://github.com/adaptant-labs/vin-decoder-dart/issues environment: - sdk: '>=2.1.0 <3.0.0' + sdk: '>=2.12.0 < 3.0.0' dependencies: - meta: ^1.4.0 + meta: ^1.8.0 basic_utils: ^3.4.0 - basic_utils: ^3.1.0 http: ^0.13.3 random_string: ^2.2.0-nullsafety diff --git a/test/vin_decoder_test.dart b/test/vin_decoder_test.dart index c913d7e..532f82f 100644 --- a/test/vin_decoder_test.dart +++ b/test/vin_decoder_test.dart @@ -1,4 +1,4 @@ -import 'package:vin_decoder/vin_decoder.dart'; +import 'package:custom_vin_decoder/vin_decoder.dart'; import 'package:test/test.dart'; void main() { diff --git a/test/vin_generator_test.dart b/test/vin_generator_test.dart index 9e4b067..e3a1cf5 100644 --- a/test/vin_generator_test.dart +++ b/test/vin_generator_test.dart @@ -1,10 +1,10 @@ -import 'package:vin_decoder/vin_decoder.dart'; +import 'package:custom_vin_decoder/vin_decoder.dart'; import 'package:test/test.dart'; void main() { group('VIN Generator Test', () { VINGenerator generator; - VIN vin; + late VIN vin; setUp(() { generator = VINGenerator(); From 2357c09d253e7dc4132251f571eca468175eb933 Mon Sep 17 00:00:00 2001 From: Bailie Livingston Date: Wed, 7 Dec 2022 13:16:46 -0600 Subject: [PATCH 11/22] Added as submodule --- example/vin_decoder_example.dart | 2 +- lib/src/nhtsa_model.dart | 2 +- lib/src/vin_decoder_base.dart | 51 ++++++++++++++++++++------- lib/src/year_map.dart | 60 ++++++++++++++++---------------- test/vin_decoder_test.dart | 6 ++-- test/vin_generator_test.dart | 2 +- 6 files changed, 74 insertions(+), 49 deletions(-) diff --git a/example/vin_decoder_example.dart b/example/vin_decoder_example.dart index 7471dc3..6b0de2a 100644 --- a/example/vin_decoder_example.dart +++ b/example/vin_decoder_example.dart @@ -2,7 +2,7 @@ import 'package:custom_vin_decoder/nhtsa.dart'; import 'package:custom_vin_decoder/vin_decoder.dart'; void main() async { - var vin = VIN(number: 'WP0ZZZ99ZTS392124', extended: true); + var vin = VIN(vin: 'WP0ZZZ99ZTS392124', extended: true); print('WMI: ${vin.wmi}'); print('VDS: ${vin.vds}'); diff --git a/lib/src/nhtsa_model.dart b/lib/src/nhtsa_model.dart index 74c626d..7244959 100644 --- a/lib/src/nhtsa_model.dart +++ b/lib/src/nhtsa_model.dart @@ -85,7 +85,7 @@ class NHTSAVehicleInfo { NHTSAVehicleInfo( {required this.count, required this.message, required this.searchCriteria, required this.results}); - /// Create a new [NHTSAVehicleInfo] instance from a fixed JSON payload + /// Create a new [NHTSAVehicleInfo] instance from a fixed JSON payload. factory NHTSAVehicleInfo.fromJson(Map json) { List results = []; if (json['Results'] != null) { diff --git a/lib/src/vin_decoder_base.dart b/lib/src/vin_decoder_base.dart index 6e4ed98..5cd5cec 100644 --- a/lib/src/vin_decoder_base.dart +++ b/lib/src/vin_decoder_base.dart @@ -19,13 +19,25 @@ class VIN { final bool extended; Map _vehicleInfo = {}; - VIN({required this.number, this.extended = false}) - : wmi = normalize(number).substring(0, 3), - vds = normalize(number).substring(3, 9), - vis = normalize(number).substring(9, 17); + /// Private named constructor. Creates a new VIN. + /// + /// [wmi], [vds], and [vis] are populated based on [number]. + VIN._({required this.number, required this.extended}) : + wmi = number.substring(0, 3), + vds = number.substring(3, 9), + vis = number.substring(9, 17); + + /// Creates a new VIN. + /// + /// This factory constructor makes sure the string is normallyed + factory VIN({required String vin, bool extended = false}){ + return VIN._(number: normalize(vin), extended: extended); + } /// Carry out VIN validation. A valid [number] must be 17 characters long /// and contain only valid alphanumeric characters. + /// + /// If a number is provided, validates that number. Otherwise, it validates the number this object was initialized with. bool valid([String? number]) { String value = normalize(number != null ? number : this.number); return RegExp(r"^[a-zA-Z0-9]+$").hasMatch(value) && value.length == 17; @@ -64,6 +76,8 @@ class VIN { } /// Get the full name of the vehicle manufacturer as defined by the [wmi]. + /// + /// If the full name cannot be found, returns null. String? getManufacturer() { // Check for the standard case - a 3 character WMI if (manufacturers.containsKey(this.wmi)) { @@ -75,7 +89,7 @@ class VIN { if (manufacturers.containsKey(id)) { return manufacturers[id]; } else { - return "Unknown (WMI: ${this.wmi.toUpperCase()})"; + return null; } } } @@ -83,18 +97,20 @@ class VIN { /// Returns the checksum for the VIN. Note that in the case of the EU region /// checksums are not implemented, so this becomes a no-op. More information /// is provided in ISO 3779:2009. + /// + /// If the region is EU, returns null String? getChecksum() { - return (getRegion() != "EU") ? normalize(this.number)[8] : null; + return (getRegion() != "EU") ? this.number[8] : null; } /// Extract the single-character model year from the [number]. - String modelYear() => normalize(this.number)[9]; + String modelYear() => this.number[9]; /// Extract the single-character assembly plant designator from the [number]. - String assemblyPlant() => normalize(this.number)[10]; + String assemblyPlant() => this.number[10]; /// Extract the serial number from the [number]. - String serialNumber() => normalize(this.number).substring(12, 17); + String serialNumber() => this.number.substring(12, 17); /// Assigns the Future _fetchExtendedVehicleInfo() async { @@ -110,15 +126,24 @@ class VIN { return this._vehicleInfo['Make']; } - /// Get the Model of the vehicle from the NHTSA database if [extended] mode - /// is enabled. + /// Get the Make ID of a vehicle from the NHTSA database if the [extended] mode is enabled + Future getMakeIdAsync() async { + await _fetchExtendedVehicleInfo(); + return this._vehicleInfo["MakeID"]; + } + + /// Get the Model of the vehicle from the NHTSA database if [extended] mode is enabled. Future getModelAsync() async { await _fetchExtendedVehicleInfo(); return this._vehicleInfo['Model']; } - /// Get the Vehicle Type from the NHTSA database if [extended] mode is - /// enabled. + Future getModelIdAsync() async { + await _fetchExtendedVehicleInfo(); + return this._vehicleInfo['ModelID']; + } + + /// Get the Vehicle Type from the NHTSA database if [extended] mode is enabled. Future getVehicleTypeAsync() async { await _fetchExtendedVehicleInfo(); return this._vehicleInfo['VehicleType']; diff --git a/lib/src/year_map.dart b/lib/src/year_map.dart index 075277a..3bbbebb 100644 --- a/lib/src/year_map.dart +++ b/lib/src/year_map.dart @@ -1,32 +1,32 @@ const yearMap = { - 'N': 1992, - 'P': 1993, - 'R': 1994, - 'S': 1995, - 'T': 1996, - 'V': 1997, - 'W': 1998, - 'X': 1999, - 'Y': 2000, - '1': 2001, - '2': 2002, - '3': 2003, - '4': 2004, - '5': 2005, - '6': 2006, - '7': 2007, - '8': 2008, - '9': 2009, - 'A': 2010, - 'B': 2011, - 'C': 2012, - 'D': 2013, - 'E': 2014, - 'F': 2015, - 'G': 2016, - 'H': 2017, - 'J': 2018, - 'K': 2019, - 'L': 2020, - 'M': 2021, + "S": 1995, + "T": 1996, + "V": 1997, + "W": 1998, + "X": 1999, + "Y": 2000, + "1": 2001, + "2": 2002, + "3": 2003, + "4": 2004, + "5": 2005, + "6": 2006, + "7": 2007, + "8": 2008, + "9": 2009, + "A": 2010, + "B": 2011, + "C": 2012, + "D": 2013, + "E": 2014, + "F": 2015, + "G": 2016, + "H": 2017, + "J": 2018, + "K": 2019, + "L": 2020, + "M": 2021, + "N": 2022, + "P": 2023, + "R": 2024, }; diff --git a/test/vin_decoder_test.dart b/test/vin_decoder_test.dart index 532f82f..e8a190e 100644 --- a/test/vin_decoder_test.dart +++ b/test/vin_decoder_test.dart @@ -3,7 +3,7 @@ import 'package:test/test.dart'; void main() { group('EU VIN Test', () { - final vin = VIN(number: 'WP0ZZZ99ZTS392124'); + final vin = VIN(vin: 'WP0ZZZ99ZTS392124'); test('Validity Test', () { expect(vin.valid(), isTrue); @@ -19,7 +19,7 @@ void main() { }); group('AS VIN Test', () { - final vin = VIN(number: 'JS1VX51L7X2175460'); + final vin = VIN(vin: 'JS1VX51L7X2175460'); test('Validity Test', () { expect(vin.valid(), isTrue); @@ -37,7 +37,7 @@ void main() { setUp(() { // Here the first 2 characters refer to the manufacturer, with the 3rd // representing the class of vehicle specific to that manufacturer. - vin = VIN(number: '5TENL42N94Z436445'); + vin = VIN(vin: '5TENL42N94Z436445'); }); test('Validity Test', () { diff --git a/test/vin_generator_test.dart b/test/vin_generator_test.dart index e3a1cf5..420f3ac 100644 --- a/test/vin_generator_test.dart +++ b/test/vin_generator_test.dart @@ -8,7 +8,7 @@ void main() { setUp(() { generator = VINGenerator(); - vin = VIN(number: generator.generate()); + vin = VIN(vin: generator.generate()); }); test('Validity Test', () { From 58d8593076f555b786488fe9510389cc7e499ba1 Mon Sep 17 00:00:00 2001 From: Bailie Livingston Date: Wed, 7 Dec 2022 13:49:30 -0600 Subject: [PATCH 12/22] Added typecasting --- lib/src/nhtsa_model.dart | 6 +++--- lib/src/vin_decoder_base.dart | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/src/nhtsa_model.dart b/lib/src/nhtsa_model.dart index 7244959..28fa3fb 100644 --- a/lib/src/nhtsa_model.dart +++ b/lib/src/nhtsa_model.dart @@ -93,14 +93,14 @@ class NHTSAVehicleInfo { if (v['Value'] != null && v['Value'] != _RESULT_NOT_APPLICABLE && v['Value'] != '') { - results.add(NHTSAResult.fromJson(v)); + results.add(NHTSAResult.fromJson(v as Map)); } }); } return NHTSAVehicleInfo( count: (json['Count'] as int?) ?? 0, - message: json['Message'] as String? ?? "", - searchCriteria: json['SearchCriteria'], + message: (json['Message'] as String?) ?? "", + searchCriteria:( json['SearchCriteria'] as String?) ?? "", results: results ); } diff --git a/lib/src/vin_decoder_base.dart b/lib/src/vin_decoder_base.dart index 5cd5cec..7893b0f 100644 --- a/lib/src/vin_decoder_base.dart +++ b/lib/src/vin_decoder_base.dart @@ -123,30 +123,30 @@ class VIN { /// is enabled. Future getMakeAsync() async { await _fetchExtendedVehicleInfo(); - return this._vehicleInfo['Make']; + return this._vehicleInfo['Make'] as String? ?? ""; } /// Get the Make ID of a vehicle from the NHTSA database if the [extended] mode is enabled Future getMakeIdAsync() async { await _fetchExtendedVehicleInfo(); - return this._vehicleInfo["MakeID"]; + return this._vehicleInfo["MakeID"] as int? ?? 0; } /// Get the Model of the vehicle from the NHTSA database if [extended] mode is enabled. Future getModelAsync() async { await _fetchExtendedVehicleInfo(); - return this._vehicleInfo['Model']; + return this._vehicleInfo['Model'] as String? ?? ""; } Future getModelIdAsync() async { await _fetchExtendedVehicleInfo(); - return this._vehicleInfo['ModelID']; + return this._vehicleInfo['ModelID'] as String? ?? ""; } /// Get the Vehicle Type from the NHTSA database if [extended] mode is enabled. Future getVehicleTypeAsync() async { await _fetchExtendedVehicleInfo(); - return this._vehicleInfo['VehicleType']; + return this._vehicleInfo['VehicleType'] as String? ?? ""; } @override From 6a4d02a39a1a846b984820f77a756e1b9be8ee56 Mon Sep 17 00:00:00 2001 From: Bailie Livingston Date: Wed, 21 Dec 2022 15:29:00 -0600 Subject: [PATCH 13/22] Fixed VIN decoder to never return empty string --- lib/src/vin_decoder_base.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/src/vin_decoder_base.dart b/lib/src/vin_decoder_base.dart index 7893b0f..f3a5f20 100644 --- a/lib/src/vin_decoder_base.dart +++ b/lib/src/vin_decoder_base.dart @@ -135,18 +135,18 @@ class VIN { /// Get the Model of the vehicle from the NHTSA database if [extended] mode is enabled. Future getModelAsync() async { await _fetchExtendedVehicleInfo(); - return this._vehicleInfo['Model'] as String? ?? ""; + return this._vehicleInfo['Model'] as String? ?? "Unknown"; } Future getModelIdAsync() async { await _fetchExtendedVehicleInfo(); - return this._vehicleInfo['ModelID'] as String? ?? ""; + return this._vehicleInfo['ModelID'] as String? ?? "Unknown"; } /// Get the Vehicle Type from the NHTSA database if [extended] mode is enabled. Future getVehicleTypeAsync() async { await _fetchExtendedVehicleInfo(); - return this._vehicleInfo['VehicleType'] as String? ?? ""; + return this._vehicleInfo['VehicleType'] as String? ?? "0"; } @override From 9705d723d01fa788aa2925e5ebd700b98a95f2a1 Mon Sep 17 00:00:00 2001 From: Dan Harding <82483951+Daniel-Harding@users.noreply.github.com> Date: Thu, 23 Mar 2023 22:12:49 -0500 Subject: [PATCH 14/22] Updated pubspec.yaml Removed space between < and 3 to eliminate 27 errors in VS code --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index dbdedb9..e6cbbe0 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -8,7 +8,7 @@ repository: https://github.com/adaptant-labs/vin-decoder-dart issue_tracker: https://github.com/adaptant-labs/vin-decoder-dart/issues environment: - sdk: '>=2.12.0 < 3.0.0' + sdk: '>=2.12.0 <3.0.0' # Important no space allowed between math operator and the numeric digit so < 3 is not the same as <3 dependencies: meta: ^1.8.0 From 3d20f6e41daebf96875ed54cbce581d722aa55c4 Mon Sep 17 00:00:00 2001 From: Bailie Livingston Date: Thu, 30 Mar 2023 17:28:14 -0500 Subject: [PATCH 15/22] Linter fixes --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index dbdedb9..5eccaad 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -8,7 +8,7 @@ repository: https://github.com/adaptant-labs/vin-decoder-dart issue_tracker: https://github.com/adaptant-labs/vin-decoder-dart/issues environment: - sdk: '>=2.12.0 < 3.0.0' + sdk: ">=2.12.0 <3.0.0" dependencies: meta: ^1.8.0 From 12a80f59cfb469d4212d4eee0b34ca27989fe77c Mon Sep 17 00:00:00 2001 From: Stemco2021 <82483951+Daniel-Harding@users.noreply.github.com> Date: Fri, 28 Jul 2023 18:15:54 -0500 Subject: [PATCH 16/22] Updated year models to 2000 to 2029 --- lib/src/year_map.dart | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/src/year_map.dart b/lib/src/year_map.dart index 3bbbebb..bc988b8 100644 --- a/lib/src/year_map.dart +++ b/lib/src/year_map.dart @@ -1,9 +1,4 @@ const yearMap = { - "S": 1995, - "T": 1996, - "V": 1997, - "W": 1998, - "X": 1999, "Y": 2000, "1": 2001, "2": 2002, @@ -29,4 +24,9 @@ const yearMap = { "N": 2022, "P": 2023, "R": 2024, + "S": 2025, + "T": 2026, + "V": 2027, + "W": 2028, + "X": 2029, }; From 6e4c419e14e9e38c237361a7e2bfe5d0a657298f Mon Sep 17 00:00:00 2001 From: ghananand-shukla-cgi <122914297+ghananand-shukla-cgi@users.noreply.github.com> Date: Mon, 25 Sep 2023 20:00:54 +0530 Subject: [PATCH 17/22] Added check for properties --- lib/src/vin_decoder_base.dart | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/src/vin_decoder_base.dart b/lib/src/vin_decoder_base.dart index f3a5f20..a158908 100644 --- a/lib/src/vin_decoder_base.dart +++ b/lib/src/vin_decoder_base.dart @@ -129,24 +129,24 @@ class VIN { /// Get the Make ID of a vehicle from the NHTSA database if the [extended] mode is enabled Future getMakeIdAsync() async { await _fetchExtendedVehicleInfo(); - return this._vehicleInfo["MakeID"] as int? ?? 0; + return this._vehicleInfo.keys.contains("MakeID") ? this._vehicleInfo["MakeID"] as int? ?? 0 : 0; } /// Get the Model of the vehicle from the NHTSA database if [extended] mode is enabled. Future getModelAsync() async { await _fetchExtendedVehicleInfo(); - return this._vehicleInfo['Model'] as String? ?? "Unknown"; + return (this._vehicleInfo.keys.contains("Model") ? this._vehicleInfo['Model'] as String? ?? "Unknown": "Unknown"); } Future getModelIdAsync() async { await _fetchExtendedVehicleInfo(); - return this._vehicleInfo['ModelID'] as String? ?? "Unknown"; + return (this._vehicleInfo.keys.contains("ModelID") ? this._vehicleInfo['ModelID'] as String? ?? "Unknown": "Unknown"); } /// Get the Vehicle Type from the NHTSA database if [extended] mode is enabled. Future getVehicleTypeAsync() async { await _fetchExtendedVehicleInfo(); - return this._vehicleInfo['VehicleType'] as String? ?? "0"; + return (this._vehicleInfo.keys.contains("VehicleType") ? this._vehicleInfo['VehicleType'] as String? ?? "0": "0"); } @override From 36a8d4233c8069fada6bcd69e2bc9fb3c66dbd0d Mon Sep 17 00:00:00 2001 From: ghananand-shukla-cgi <122914297+ghananand-shukla-cgi@users.noreply.github.com> Date: Wed, 27 Sep 2023 12:08:04 +0530 Subject: [PATCH 18/22] fix issue of int conversion --- lib/src/vin_decoder_base.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/vin_decoder_base.dart b/lib/src/vin_decoder_base.dart index a158908..4994323 100644 --- a/lib/src/vin_decoder_base.dart +++ b/lib/src/vin_decoder_base.dart @@ -129,7 +129,7 @@ class VIN { /// Get the Make ID of a vehicle from the NHTSA database if the [extended] mode is enabled Future getMakeIdAsync() async { await _fetchExtendedVehicleInfo(); - return this._vehicleInfo.keys.contains("MakeID") ? this._vehicleInfo["MakeID"] as int? ?? 0 : 0; + return this._vehicleInfo.keys.contains("MakeID") ? int.parse(this._vehicleInfo["MakeID"]): 0; } /// Get the Model of the vehicle from the NHTSA database if [extended] mode is enabled. From 19657908f7d65dce04df95b27ad45c9b1aa961f6 Mon Sep 17 00:00:00 2001 From: Josue Jovel Date: Wed, 20 Dec 2023 16:31:40 -0600 Subject: [PATCH 19/22] Added fuel type search (issue #670) --- lib/src/vin_decoder_base.dart | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/lib/src/vin_decoder_base.dart b/lib/src/vin_decoder_base.dart index 4994323..96de1d6 100644 --- a/lib/src/vin_decoder_base.dart +++ b/lib/src/vin_decoder_base.dart @@ -1,3 +1,5 @@ +import 'dart:collection'; + import 'manufacturers.dart'; import 'nhtsa_model.dart'; import 'year_map.dart'; @@ -119,6 +121,28 @@ class VIN { } } + /// Get the fuel type of the vehicle from the NHTSA database if [extended] mode + /// is enabled. + Future getFuelTypeAsync() async { + await _fetchExtendedVehicleInfo(); + String fuelType = this._vehicleInfo['FuelTypePrimary'] as String? ?? ""; + Map fuels = HashMap(); //Hashmap containing fuel names and their respective # + fuels["Diesel"] = 1; + fuels["CNG"] = 6; + fuels["Gasoline"] = 4; + fuels["Battery"] = 2; + fuels["LNG"] = 7; + fuels["Hydrogen"] = 8; + fuels["LPG"] = 9; + fuels["E85"] = 10; + fuels["E100"] = 11; + fuels["M85"] = 13; + fuels["M100"] = 14; + fuels["FFV"] = 15; + int fuelTypeNumber = fuels[fuelType] ?? 0; + return fuelTypeNumber; + } + /// Get the Make of the vehicle from the NHTSA database if [extended] mode /// is enabled. Future getMakeAsync() async { From bfea38d74922da02de5ea31a06ffe312b9ffec87 Mon Sep 17 00:00:00 2001 From: Nathan-Bianco Date: Tue, 19 Mar 2024 14:42:57 -0500 Subject: [PATCH 20/22] Issue #670: refactor fuelMap as a const and handle mismatching cases/incomplete fuel names. --- lib/src/vin_decoder_base.dart | 44 +++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/lib/src/vin_decoder_base.dart b/lib/src/vin_decoder_base.dart index 96de1d6..ed40ada 100644 --- a/lib/src/vin_decoder_base.dart +++ b/lib/src/vin_decoder_base.dart @@ -1,10 +1,24 @@ -import 'dart:collection'; - import 'manufacturers.dart'; import 'nhtsa_model.dart'; import 'year_map.dart'; class VIN { + /// Hashmap containing fuel names and their respective # + static const Map fuelMap = { + "Diesel": 1, + "CNG": 6, + "Gasoline": 4, + "Battery": 2, + "LNG": 7, + "Hydrogen": 8, + "LPG": 9, + "E85": 10, + "E100": 11, + "M85": 13, + "M100": 14, + "FFV": 15 + }; + /// The VIN that the class was instantiated with. final String number; @@ -125,22 +139,16 @@ class VIN { /// is enabled. Future getFuelTypeAsync() async { await _fetchExtendedVehicleInfo(); - String fuelType = this._vehicleInfo['FuelTypePrimary'] as String? ?? ""; - Map fuels = HashMap(); //Hashmap containing fuel names and their respective # - fuels["Diesel"] = 1; - fuels["CNG"] = 6; - fuels["Gasoline"] = 4; - fuels["Battery"] = 2; - fuels["LNG"] = 7; - fuels["Hydrogen"] = 8; - fuels["LPG"] = 9; - fuels["E85"] = 10; - fuels["E100"] = 11; - fuels["M85"] = 13; - fuels["M100"] = 14; - fuels["FFV"] = 15; - int fuelTypeNumber = fuels[fuelType] ?? 0; - return fuelTypeNumber; + final String? fuelType = this._vehicleInfo['FuelTypePrimary'] as String?; + if (fuelType == null) return 0; + + final String fuelLower = fuelType.toLowerCase(); + for (final String fuelKey in fuelMap.keys) { + if (fuelLower.contains(fuelKey.toLowerCase())) { + return fuelMap[fuelKey]!; + } + } + return 0; } /// Get the Make of the vehicle from the NHTSA database if [extended] mode From 009fde5cdef1be498e9a04d55d89e021956ff063 Mon Sep 17 00:00:00 2001 From: Stemco2021 <82483951+Daniel-Harding@users.noreply.github.com> Date: Wed, 27 Mar 2024 11:05:47 -0500 Subject: [PATCH 21/22] Added more Fuel types --- lib/src/vin_decoder_base.dart | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/src/vin_decoder_base.dart b/lib/src/vin_decoder_base.dart index ed40ada..47c718b 100644 --- a/lib/src/vin_decoder_base.dart +++ b/lib/src/vin_decoder_base.dart @@ -9,6 +9,7 @@ class VIN { "CNG": 6, "Gasoline": 4, "Battery": 2, + "BEV":2, "LNG": 7, "Hydrogen": 8, "LPG": 9, @@ -16,7 +17,9 @@ class VIN { "E100": 11, "M85": 13, "M100": 14, - "FFV": 15 + "FFV": 15, + "FCEV":18, + "Fuel Cell": 18 }; /// The VIN that the class was instantiated with. From 999e2fa3fa90d531de37593a12010fa3b80f064b Mon Sep 17 00:00:00 2001 From: Stemco2021 <82483951+Daniel-Harding@users.noreply.github.com> Date: Thu, 16 May 2024 15:13:23 -0500 Subject: [PATCH 22/22] Added the keyword "Electric" for fuel type 2 --- lib/src/vin_decoder_base.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/src/vin_decoder_base.dart b/lib/src/vin_decoder_base.dart index 47c718b..8fabf04 100644 --- a/lib/src/vin_decoder_base.dart +++ b/lib/src/vin_decoder_base.dart @@ -9,6 +9,7 @@ class VIN { "CNG": 6, "Gasoline": 4, "Battery": 2, + "Electric":2, "BEV":2, "LNG": 7, "Hydrogen": 8,