diff --git a/src/address_validation/suggest_validation_action.ts b/src/address_validation/suggest_validation_action.ts index a26fca3..259b246 100644 --- a/src/address_validation/suggest_validation_action.ts +++ b/src/address_validation/suggest_validation_action.ts @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import {Address, AddressValidationResponse, Granularity, ValidationResult} from '../utils/googlemaps_types.js'; +import {Address, AddressValidation, Granularity} from '../utils/googlemaps_types.js'; /** Suggested action to take for this validation result. */ @@ -32,8 +32,8 @@ function isUSA(address: Address): boolean { return address.postalAddress?.regionCode === 'US'; } -function isMissingNonSubpremiseComponent(result: ValidationResult): boolean { - const missingComponents = result.address.missingComponentTypes || []; +function isMissingNonSubpremiseComponent(result: AddressValidation): boolean { + const missingComponents = result.address?.missingComponentTypes || []; return (missingComponents.length > 1) || ((missingComponents.length === 1) && (missingComponents[0] !== SUBPREMISE)); @@ -44,34 +44,37 @@ function isMissingNonSubpremiseComponent(result: ValidationResult): boolean { * `ROUTE` level. `PREMISE`, `SUBPREMISE`, and `PREMISE_PROXIMITY` are all * considered as good as `ROUTE` or better. */ -function hasValidationGranularityOther(result: ValidationResult): boolean { +function hasValidationGranularityOther(result: AddressValidation): boolean { return !result.verdict?.validationGranularity || result.verdict.validationGranularity === Granularity.OTHER; } -function hasSuspiciousComponent(result: ValidationResult): boolean { - return result.address.addressComponents.some( - c => c.confirmationLevel === 'UNCONFIRMED_AND_SUSPICIOUS'); +function hasSuspiciousComponent(result: AddressValidation): boolean { + return !!result.address && + result.address.components.some( + c => c.confirmationLevel === 'UNCONFIRMED_AND_SUSPICIOUS'); } -function hasUnresolvedToken(result: ValidationResult): boolean { - return (result.address.unresolvedTokens || []).length > 0; +function hasUnresolvedToken(result: AddressValidation): boolean { + return !!result.address && + (result.address.unresolvedTokens || []).length > 0; } /** * Returns true if the result has an inference for a component other than the * postal code, administrative area (1, 2, or 3), or country. */ -function hasMajorInference(result: ValidationResult): boolean { +function hasMajorInference(result: AddressValidation): boolean { const minorComponents = new Set([ POSTAL_CODE, POSTAL_CODE_SUFFIX, ADMINISTRATIVE_AREA_LEVEL_1, ADMINISTRATIVE_AREA_LEVEL_2, ADMINISTRATIVE_AREA_LEVEL_3, COUNTRY ]); - return result.address.addressComponents.some( - c => c.isInferred && !minorComponents.has(c.componentType)); + return !!result.address && + result.address.components.some( + c => c.isInferred && !minorComponents.has(c.componentType)) } -function hasReplacement(result: ValidationResult): boolean { +function hasReplacement(result: AddressValidation): boolean { return !!result.verdict?.hasReplacedComponents; } @@ -79,12 +82,16 @@ function hasReplacement(result: ValidationResult): boolean { * Returns true if this is a US address that is missing a subpremise component * (and nothing else). */ -function isMissingExactlyUSASubpremise(result: ValidationResult): boolean { - return isUSA(result.address) && +function isMissingExactlyUSASubpremise(result: AddressValidation): boolean { + return !!result.address && isUSA(result.address) && (result.address.missingComponentTypes?.length === 1) && (result.address.missingComponentTypes[0] === SUBPREMISE); } +function isIncompleteResult(result: AddressValidation): boolean { + return !result.verdict || !result.address; +} + /** * This is a JavaScript function that analyzes an Address Validation API * response and outputs a single recommended follow-up action you should take @@ -137,16 +144,16 @@ function isMissingExactlyUSASubpremise(result: ValidationResult): boolean { * @param response - A response object from the Address Validation API in the * Maps JS SDK. */ -export function suggestValidationAction(response: AddressValidationResponse): +export function suggestValidationAction(response: AddressValidation): ValidationSuggestion { - const result = response.result; - if (isMissingNonSubpremiseComponent(result) || - hasValidationGranularityOther(result) || hasSuspiciousComponent(result) || - hasUnresolvedToken(result)) { + if (isIncompleteResult(response) || + isMissingNonSubpremiseComponent(response) || + hasValidationGranularityOther(response) || + hasSuspiciousComponent(response) || hasUnresolvedToken(response)) { return {suggestedAction: SuggestedAction.FIX}; - } else if (hasMajorInference(result) || hasReplacement(result)) { + } else if (hasMajorInference(response) || hasReplacement(response)) { return {suggestedAction: SuggestedAction.CONFIRM}; - } else if (isMissingExactlyUSASubpremise(result)) { + } else if (isMissingExactlyUSASubpremise(response)) { return {suggestedAction: SuggestedAction.ADD_SUBPREMISES}; } else { return {suggestedAction: SuggestedAction.ACCEPT}; diff --git a/src/address_validation/suggest_validation_action_test.ts b/src/address_validation/suggest_validation_action_test.ts index f97a061..6c1cb4c 100644 --- a/src/address_validation/suggest_validation_action_test.ts +++ b/src/address_validation/suggest_validation_action_test.ts @@ -6,7 +6,7 @@ // import 'jasmine'; (google3-only) -import {Address, AddressComponent, AddressValidationResponse, ConfirmationLevel, Granularity, Verdict} from '../utils/googlemaps_types.js'; +import {Address, AddressComponent, AddressValidation, ConfirmationLevel, Granularity, Verdict} from '../utils/googlemaps_types.js'; import {SuggestedAction, suggestValidationAction} from './suggest_validation_action.js'; @@ -31,22 +31,33 @@ const LOCALITY_COMPONENT: AddressComponent = { }; function makeFakeValidationResponse( - address: Partial
, verdict: Verdict): AddressValidationResponse { + address: Partial
, verdict: Verdict|null): AddressValidation { return { - result: { - verdict, - address: { - formattedAddress: null, - postalAddress: null, - addressComponents: [], - ...address - }, + verdict, + address: { + formattedAddress: null, + postalAddress: null, + components: [], + ...address }, - responseId: '' + + responseId: '', }; } describe('SuggestValidationAction', () => { + it('returns FIX when an address is missing', () => { + const suggestion = suggestValidationAction( + {address: null, responseId: '', verdict: GOOD_VERDICT}); + expect(suggestion.suggestedAction).toBe(SuggestedAction.FIX); + }); + + it('returns FIX when verdict is missing', () => { + const suggestion = + suggestValidationAction(makeFakeValidationResponse({}, null)); + expect(suggestion.suggestedAction).toBe(SuggestedAction.FIX); + }); + it('returns FIX when an address is missing a non-subpremise component', () => { const suggestion = suggestValidationAction(makeFakeValidationResponse( @@ -63,7 +74,7 @@ describe('SuggestValidationAction', () => { it('returns FIX when there is a suspicious component', () => { const suggestion = suggestValidationAction(makeFakeValidationResponse( { - addressComponents: [{ + components: [{ ...LOCALITY_COMPONENT, confirmationLevel: ConfirmationLevel.UNCONFIRMED_AND_SUSPICIOUS }] @@ -81,7 +92,7 @@ describe('SuggestValidationAction', () => { it('returns CONFIRM when there is a non-minor inferred component', () => { const suggestion = suggestValidationAction(makeFakeValidationResponse( { - addressComponents: [{ + components: [{ ...LOCALITY_COMPONENT, isInferred: true, }] diff --git a/src/utils/googlemaps_types.ts b/src/utils/googlemaps_types.ts index 2507224..061788a 100644 --- a/src/utils/googlemaps_types.ts +++ b/src/utils/googlemaps_types.ts @@ -96,7 +96,7 @@ export declare interface PostalAddress { export declare interface Address { formattedAddress: string|null; postalAddress: PostalAddress|null; - addressComponents: AddressComponent[]; + components: AddressComponent[]; missingComponentTypes?: string[]; unconfirmedComponentTypes?: string[]; unresolvedTokens?: string[]; @@ -124,18 +124,17 @@ export declare interface Verdict { hasReplacedComponents: boolean; } -/** google.maps.addressValidation.ValidationResult */ -export declare interface ValidationResult { +/** google.maps.addressValidation.AddressValidation */ +export declare interface AddressValidation { + responseId: string|null; verdict: Verdict|null; - address: Address; + address: Address|null; + + // These properties exist but are not needed for the ECL. // geocode: Geocode; // metadata: AddressMetadata; // uspsData: UspsData; - // englishLatinAddress: Address; -} -/** google.maps.addressValidation.AddressValidationResponse */ -export declare interface AddressValidationResponse { - result: ValidationResult; - responseId: string; + // This property is not yet published. + // englishLatinAddress: Address; }