From 07ff7809d065f2660617fd824436c16c5e35a6c3 Mon Sep 17 00:00:00 2001
From: Extended Component Library Team
 <extended-component-library-authors@google.com>
Date: Tue, 13 May 2025 18:17:06 -0700
Subject: [PATCH] fix: update suggestValidationAction with updated
 AddressValidation syntax

PiperOrigin-RevId: 758453487
---
 src/address_validation/README.md              |  6 +-
 .../suggest_validation_action.ts              | 57 +++++++++++--------
 .../suggest_validation_action_test.ts         | 37 +++++++-----
 src/utils/googlemaps_types.ts                 | 19 +++----
 4 files changed, 68 insertions(+), 51 deletions(-)

diff --git a/src/address_validation/README.md b/src/address_validation/README.md
index 824a49e..a2f58f7 100644
--- a/src/address_validation/README.md
+++ b/src/address_validation/README.md
@@ -67,9 +67,9 @@ for guidance.
 
 **Parameters:**
 
-| Name       | Optional? | Type                        | Description                                                           |
-| ---------- | --------- | --------------------------- | --------------------------------------------------------------------- |
-| `response` |           | `AddressValidationResponse` | A response object from the Address Validation API in the Maps JS SDK. |
+| Name       | Optional? | Type                | Description                                                           |
+| ---------- | --------- | ------------------- | --------------------------------------------------------------------- |
+| `response` |           | `AddressValidation` | A response object from the Address Validation API in the Maps JS SDK. |
 
 #### Importing
 
diff --git a/src/address_validation/suggest_validation_action.ts b/src/address_validation/suggest_validation_action.ts
index a26fca3..ac369b6 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,36 @@ 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?.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 +81,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({verdict, address}: AddressValidation): boolean {
+  return !verdict || !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,18 +143,19 @@ 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)) {
+  }
+  if (hasMajorInference(response) || hasReplacement(response)) {
     return {suggestedAction: SuggestedAction.CONFIRM};
-  } else if (isMissingExactlyUSASubpremise(result)) {
-    return {suggestedAction: SuggestedAction.ADD_SUBPREMISES};
-  } else {
-    return {suggestedAction: SuggestedAction.ACCEPT};
   }
+  if (isMissingExactlyUSASubpremise(response)) {
+    return {suggestedAction: SuggestedAction.ADD_SUBPREMISES};
+  } 
+  return {suggestedAction: SuggestedAction.ACCEPT};
 }
\ No newline at end of file
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<Address>, verdict: Verdict): AddressValidationResponse {
+    address: Partial<Address>, 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;
 }