From 406bdaadfb346e9f356ff667431be20d4ba73225 Mon Sep 17 00:00:00 2001 From: Ryan Cox Date: Fri, 27 Feb 2026 16:09:58 -0700 Subject: [PATCH 01/29] Export TypeScript types (Request, Response, Sender, Sleeper) from SDK Convert index.mjs to index.ts so the build generates index.d.ts naturally, and re-export the Sender chain interfaces so consumers implementing custom senders via .withSender() can access them. --- index.mjs => index.ts | 2 ++ package.json | 1 + rollup.config.mjs | 80 +++++++++++++++++++++---------------------- tsconfig.json | 8 ++--- 4 files changed, 47 insertions(+), 44 deletions(-) rename index.mjs => index.ts (97%) diff --git a/index.mjs b/index.ts similarity index 97% rename from index.mjs rename to index.ts index c053a6c..5de054e 100644 --- a/index.mjs +++ b/index.ts @@ -36,6 +36,8 @@ import ResponseUSEnrichment from "./src/us_enrichment/Response.js"; import LookupInternationalPostalCode from "./src/international_postal_code/Lookup.js"; import ResultInternationalPostalCode from "./src/international_postal_code/Result.js"; +export type { Request, Response, Sender, Sleeper } from "./src/types.js"; + export const core = { Batch, ClientBuilder, diff --git a/package.json b/package.json index b182ce0..53dd546 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "types": "dist/types/index.d.ts", "exports": { ".": { + "types": "./dist/types/index.d.ts", "import": "./dist/esm/index.mjs", "default": "./dist/cjs/index.cjs" } diff --git a/rollup.config.mjs b/rollup.config.mjs index cef8d6c..afd4b2d 100644 --- a/rollup.config.mjs +++ b/rollup.config.mjs @@ -6,43 +6,43 @@ import { nodeResolve } from "@rollup/plugin-node-resolve"; import typescript from "@rollup/plugin-typescript"; export default { - input: "index.mjs", - external: ["axios", "axios-retry"], - output: [ - { - dir: "dist", - format: "esm", - preserveModules: true, - preserveModulesRoot: "src", - exports: "named", - entryFileNames: "esm/[name].mjs", - }, - { - dir: "dist", - format: "cjs", - preserveModules: true, - preserveModulesRoot: "src", - exports: "named", - esModule: false, - entryFileNames: "cjs/[name].cjs", - }, - ], - plugins: [ - del({ targets: "dist/*" }), - nodeResolve(), - commonjs({ - esmExternals: true, - requireReturnsDefault: true, - }), - json(), - terser(), - typescript({ - declaration: true, - emitDeclarationOnly: true, - outDir: "dist/types", - rootDir: "src", - importHelpers: false, - target: "es2015", - }), - ], -}; \ No newline at end of file + input: "index.ts", + external: ["axios", "axios-retry"], + output: [ + { + dir: "dist", + format: "esm", + preserveModules: true, + preserveModulesRoot: "src", + exports: "named", + entryFileNames: "esm/[name].mjs", + }, + { + dir: "dist", + format: "cjs", + preserveModules: true, + preserveModulesRoot: "src", + exports: "named", + esModule: false, + entryFileNames: "cjs/[name].cjs", + }, + ], + plugins: [ + del({ targets: "dist/*" }), + nodeResolve(), + commonjs({ + esmExternals: true, + requireReturnsDefault: true, + }), + json(), + terser(), + typescript({ + declaration: true, + emitDeclarationOnly: true, + outDir: "dist/types", + rootDir: ".", + importHelpers: false, + target: "es2015", + }), + ], +}; diff --git a/tsconfig.json b/tsconfig.json index ea5d2a6..b614533 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -32,9 +32,9 @@ "isolatedModules": true, "jsx": "preserve", "types": ["mocha", "chai", "node"], - "importHelpers": false, - "target": "es2015" - }, - "include": ["src/**/*", "tests/**/*"], + "importHelpers": false, + "target": "es2015" + }, + "include": ["index.ts", "src/**/*", "tests/**/*"], "exclude": ["node_modules"] } From e7a2c0fb917ac789bfc1f0843504adb9bfd98d29 Mon Sep 17 00:00:00 2001 From: Ryan Cox Date: Fri, 27 Feb 2026 16:15:28 -0700 Subject: [PATCH 02/29] Prettier formatting. --- .claude/settings.json | 21 +- .github/workflows/node-tests.yml | 25 +- .github/workflows/publish.yml | 10 +- CHANGELOG.md | 2 +- CLAUDE.md | 4 + LICENSE.md | 367 ++--- .../international_address_autocomplete.mjs | 12 +- examples/international_street.mjs | 8 +- examples/us_autocomplete_pro.mjs | 8 +- examples/us_enrichment.mjs | 2 +- examples/us_extract.mjs | 10 +- examples/us_reverse_geo.mjs | 2 +- src/AgentSender.ts | 3 +- src/Batch.js | 12 +- src/ClientBuilder.js | 15 +- src/Errors.js | 25 +- src/HttpSender.js | 32 +- src/InputData.js | 5 +- src/LicenseSender.js | 6 +- src/Request.js | 4 +- src/Response.js | 4 +- src/SigningSender.ts | 42 +- src/StatusCodeSender.js | 14 +- .../Client.js | 9 +- .../Lookup.js | 11 +- .../Suggestion.js | 2 +- src/international_street/Candidate.js | 155 +- src/international_street/Client.js | 9 +- src/international_street/Lookup.js | 21 +- src/us_autocomplete_pro/Client.js | 9 +- src/us_autocomplete_pro/Lookup.js | 2 +- src/us_autocomplete_pro/Suggestion.js | 2 +- src/us_enrichment/Client.js | 215 +-- src/us_enrichment/Lookup.js | 24 +- src/us_enrichment/Response.js | 1201 +++++++------- src/us_extract/Address.js | 6 +- src/us_extract/Client.js | 9 +- src/us_extract/Lookup.js | 2 +- src/us_extract/Result.js | 6 +- src/us_reverse_geo/Client.js | 7 +- src/us_reverse_geo/Lookup.js | 2 +- src/us_reverse_geo/Response.js | 2 +- src/us_reverse_geo/Result.js | 4 +- src/us_street/Client.js | 4 +- src/us_street/Lookup.js | 1 - src/us_zipcode/Client.js | 4 +- src/us_zipcode/Lookup.js | 2 +- src/us_zipcode/Result.js | 66 +- src/util/Sleeper.ts | 6 +- src/util/apiToSDKKeyMap.js | 78 +- src/util/buildClients.js | 2 +- src/util/buildSmartyResponse.js | 9 +- src/util/sendBatch.js | 9 +- tests/fixtures/MockSleeper.js | 2 +- tests/fixtures/mock_senders.js | 16 +- .../test_Client.js | 24 +- .../test_Lookup.js | 14 +- tests/international_street/test_Client.js | 6 +- tests/international_street/test_Lookup.js | 11 +- tests/test_Batch.js | 18 +- tests/test_HttpSender.js | 22 +- tests/test_LicenseSender.js | 6 +- tests/test_StatusCodeSender.js | 56 +- tests/us_autocomplete_pro/test_Client.js | 14 +- tests/us_autocomplete_pro/test_Lookup.js | 2 +- tests/us_autocomplete_pro/test_Suggestion.js | 2 +- tests/us_enrichment/test_Client.js | 890 +++++----- tests/us_enrichment/test_Lookup.js | 2 +- tests/us_enrichment/test_Response.js | 1468 ++++++++--------- tests/us_extract/test_Address.js | 86 +- tests/us_extract/test_Client.js | 124 +- tests/us_extract/test_Lookup.js | 2 +- tests/us_extract/test_Result.js | 32 +- tests/us_reverse_geo/test_Client.js | 31 +- tests/us_reverse_geo/test_Lookup.js | 4 +- tests/us_reverse_geo/test_Response.js | 8 +- tests/us_street/test_Client.js | 22 +- tests/us_street/test_Lookup.js | 8 +- tests/us_zipcode/test_Client.js | 31 +- tests/us_zipcode/test_Result.js | 91 +- 80 files changed, 2816 insertions(+), 2688 deletions(-) diff --git a/.claude/settings.json b/.claude/settings.json index 1210e2a..7b1927f 100644 --- a/.claude/settings.json +++ b/.claude/settings.json @@ -1,16 +1,9 @@ { - "permissions": { - "allow": [ - "Edit", - "Write", - "Bash(rm:./*)", - "Bash(git *)", - "Bash(make *)", - "Bash(npm *)" - ] - }, - "attribution": { - "commit": "", - "pr": "" - } + "permissions": { + "allow": ["Edit", "Write", "Bash(rm:./*)", "Bash(git *)", "Bash(make *)", "Bash(npm *)"] + }, + "attribution": { + "commit": "", + "pr": "" + } } diff --git a/.github/workflows/node-tests.yml b/.github/workflows/node-tests.yml index fdafee4..ee0d9dc 100644 --- a/.github/workflows/node-tests.yml +++ b/.github/workflows/node-tests.yml @@ -2,13 +2,12 @@ name: Node Tests on: push: - branches: [ master ] + branches: [master] pull_request: - branches: [ master ] + branches: [master] jobs: build: - runs-on: ubuntu-latest strategy: @@ -16,13 +15,13 @@ jobs: node-version: [20.x, 22.x, 24.x] steps: - - uses: actions/checkout@v6 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v6 - with: - node-version: ${{ matrix.node-version }} - - run: npm ci - - run: npm run build - - run: npm test - env: - CI: true + - uses: actions/checkout@v6 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v6 + with: + node-version: ${{ matrix.node-version }} + - run: npm ci + - run: npm run build + - run: npm test + env: + CI: true diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 4b69d01..986b7ac 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -3,10 +3,10 @@ name: Publish to npm on: push: tags: - - '*' + - "*" permissions: - id-token: write # Required for OIDC + id-token: write # Required for OIDC contents: read jobs: @@ -19,8 +19,8 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v6 with: - node-version: '20.x' - registry-url: 'https://registry.npmjs.org' + node-version: "20.x" + registry-url: "https://registry.npmjs.org" - name: Update npm run: npm install -g npm@'>=11.5.1' @@ -44,4 +44,4 @@ jobs: run: npm publish env: NPM_CONFIG_PROVENANCE: true - NPM_TOKEN: '' + NPM_TOKEN: "" diff --git a/CHANGELOG.md b/CHANGELOG.md index f6c8e34..3527620 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,4 +2,4 @@ See the changelog repository: -github.com/smartystreets/changelog/blob/master/sdk/javascript.md \ No newline at end of file +github.com/smartystreets/changelog/blob/master/sdk/javascript.md diff --git a/CLAUDE.md b/CLAUDE.md index bc88c23..5b8f6cc 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -15,6 +15,7 @@ npx prettier --write src/ # Format source files ``` To run a single test file: + ```bash npx mocha tests/us_street/test_Client.js # JS test npx mocha --require tsx/cjs tests/test_RetrySender.ts # TS test @@ -50,6 +51,7 @@ Each sender adds specific functionality (authentication, retries, headers, etc.) ### API Modules Each API follows the same structure in `src//`: + - `Lookup.js` - Input/output container - `Client.js` - Request/response handling - `Candidate.js`, `Result.js`, or `Suggestion.js` - Response data structures @@ -59,6 +61,7 @@ Supported APIs: `us_street`, `us_zipcode`, `us_autocomplete_pro`, `us_extract`, ### Credentials Three credential types, each implementing a `sign(request)` method used by `SigningSender`: + - **StaticCredentials** (TS) - Server-side: adds `auth-id` + `auth-token` query params - **SharedCredentials** (TS) - Client-side/browser: adds embedded `key` param + `Referer` header. Cannot be used with POST (batch) requests. - **BasicAuthCredentials** (TS) - Adds HTTP Basic Auth `Authorization` header @@ -72,6 +75,7 @@ Three credential types, each implementing a `sign(request)` method used by `Sign Tests use Mocha + Chai (`expect` style). Test files are prefixed with `test_` and mirror the source structure under `tests/`. `tests/fixtures/mock_senders.js` provides reusable mocks: + - `MockSender` - Captures the request for inspection - `MockSenderWithResponse` - Returns a fixed payload/error - `MockSenderWithStatusCodesAndHeaders` - Iterates through status codes (useful for retry tests) diff --git a/LICENSE.md b/LICENSE.md index e1b2a06..dd38c28 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,182 +1,181 @@ - Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" @@ -187,16 +186,16 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2022 Smarty +Copyright 2022 Smarty - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/examples/international_address_autocomplete.mjs b/examples/international_address_autocomplete.mjs index 2dbab98..494e564 100644 --- a/examples/international_address_autocomplete.mjs +++ b/examples/international_address_autocomplete.mjs @@ -24,19 +24,19 @@ const client = clientBuilder.buildInternationalAddressAutocompleteClient(); // www.smarty.com/docs/cloud/international-address-autocomplete-api#pro-http-request-input-fields const country = "CAN"; -const summaryLookup = new Lookup({search: "123 Anson", country}); +const summaryLookup = new Lookup({ search: "123 Anson", country }); // uncomment the following line to add a custom parameter // summaryLookup.addCustomParameter("max_results", 1); await handleRequest(summaryLookup, "Response of summary results"); -const detailedLookup = new Lookup({addressId: summaryLookup.result[0].addressId, country}); +const detailedLookup = new Lookup({ addressId: summaryLookup.result[0].addressId, country }); await handleRequest(detailedLookup, "Response using an address ID to get detailed results"); function logSuggestions(response, message) { console.log("*** " + message + " ***"); - response.result.forEach(suggestion => { + response.result.forEach((suggestion) => { if (suggestion.addressText) { console.log("Entries: ", suggestion.entries); console.log("Address Text: ", suggestion.addressText); @@ -56,7 +56,7 @@ async function handleRequest(lookup, lookupType) { try { const results = await client.send(lookup); logSuggestions(results, lookupType); - } catch(err) { - console.log(err) + } catch (err) { + console.log(err); } -} \ No newline at end of file +} diff --git a/examples/international_street.mjs b/examples/international_street.mjs index 1b37f6d..aa9463a 100644 --- a/examples/international_street.mjs +++ b/examples/international_street.mjs @@ -38,8 +38,8 @@ lookup2.administrativeArea = "SP"; lookup2.country = "Brazil"; lookup2.postalCode = "02516-050"; -await handleRequest(lookup1) -await handleRequest(lookup2) +await handleRequest(lookup1); +await handleRequest(lookup2); function displayResult(result) { console.log(result.result[0].components); @@ -53,7 +53,7 @@ async function handleRequest(lookup) { try { const result = await client.send(lookup); displayResult(result); - } catch(err) { + } catch (err) { handleError(err); } -} \ No newline at end of file +} diff --git a/examples/us_autocomplete_pro.mjs b/examples/us_autocomplete_pro.mjs index 19bf61a..46ec9c9 100644 --- a/examples/us_autocomplete_pro.mjs +++ b/examples/us_autocomplete_pro.mjs @@ -46,7 +46,7 @@ lookup = new Lookup("4770 Lincoln"); lookup.selected = "4770 N Lincoln Ave Ste 2 (3) Chicago, IL 60625"; -await handleRequest(lookup, "Using 'selected' to Expand Secondaries") +await handleRequest(lookup, "Using 'selected' to Expand Secondaries"); // ************************************************ @@ -60,7 +60,7 @@ async function handleRequest(lookup, lookupType) { try { const results = await client.send(lookup); logSuggestions(results, lookupType); - } catch(err) { - console.log(err) + } catch (err) { + console.log(err); } -} \ No newline at end of file +} diff --git a/examples/us_enrichment.mjs b/examples/us_enrichment.mjs index df918f7..708d11c 100644 --- a/examples/us_enrichment.mjs +++ b/examples/us_enrichment.mjs @@ -36,4 +36,4 @@ async function handleResponse(lookup) { } catch (err) { console.log(err); } -} \ No newline at end of file +} diff --git a/examples/us_extract.mjs b/examples/us_extract.mjs index 85f6405..bcb3e56 100644 --- a/examples/us_extract.mjs +++ b/examples/us_extract.mjs @@ -13,14 +13,16 @@ let authToken = process.env.SMARTY_AUTH_TOKEN; const credentials = new SmartyCore.BasicAuthCredentials(authId, authToken); let clientBuilder = new SmartyCore.ClientBuilder(credentials); - // .withBaseUrl("YOUR URL") // withBaseUrl() should be used if you are self-hosting the Smarty API +// .withBaseUrl("YOUR URL") // withBaseUrl() should be used if you are self-hosting the Smarty API let client = clientBuilder.buildUsExtractClient(); // Documentation for input fields can be found at: // https://www.smarty.com/docs/cloud/us-extract-api#http-request-input-fields -let lookup = new Lookup("If you work at 1600 Pennsylvania Ave NW, Washington DC you're gonna have a hard time."); +let lookup = new Lookup( + "If you work at 1600 Pennsylvania Ave NW, Washington DC you're gonna have a hard time.", +); lookup.aggressive = true; lookup.addressesHaveLineBreaks = false; lookup.addressesPerLine = 1; @@ -38,7 +40,7 @@ async function handleRequest(lookup) { try { const response = await client.send(lookup); logResult(response); - } catch(err) { + } catch (err) { console.log(err); } -} \ No newline at end of file +} diff --git a/examples/us_reverse_geo.mjs b/examples/us_reverse_geo.mjs index 8dcd519..1269a4b 100644 --- a/examples/us_reverse_geo.mjs +++ b/examples/us_reverse_geo.mjs @@ -37,7 +37,7 @@ async function handleResponse(lookup) { try { const result = await client.send(lookup); displayResult(result); - } catch(err) { + } catch (err) { handleError(err); } } diff --git a/src/AgentSender.ts b/src/AgentSender.ts index 872efa4..57358c1 100644 --- a/src/AgentSender.ts +++ b/src/AgentSender.ts @@ -9,8 +9,7 @@ export default class AgentSender { } send(request: Request): Promise { - request.parameters["agent"] = - "smarty (sdk:javascript@" + packageJson.version + ")"; + request.parameters["agent"] = "smarty (sdk:javascript@" + packageJson.version + ")"; return new Promise((resolve, reject) => { this.sender.send(request).then(resolve).catch(reject); }); diff --git a/src/Batch.js b/src/Batch.js index ccc00f7..725590d 100644 --- a/src/Batch.js +++ b/src/Batch.js @@ -5,11 +5,11 @@ const BatchFullError = require("./Errors").BatchFullError; * all at once. This is more efficient than sending them one at a time. */ class Batch { - constructor () { + constructor() { this.lookups = []; } - add (lookup) { + add(lookup) { if (this.lookupsHasRoomForLookup()) this.lookups.push(lookup); else throw new BatchFullError(); } @@ -28,7 +28,7 @@ class Batch { } getByInputId(inputId) { - return this.lookups.filter(lookup => { + return this.lookups.filter((lookup) => { return lookup.inputId === inputId; })[0]; } @@ -37,13 +37,13 @@ class Batch { * Clears the lookups stored in the batch so it can be used again.
* This helps avoid the overhead of building a new Batch object for each group of lookups. */ - clear () { + clear() { this.lookups = []; } - isEmpty () { + isEmpty() { return this.length() === 0; } } -module.exports = Batch; \ No newline at end of file +module.exports = Batch; diff --git a/src/ClientBuilder.js b/src/ClientBuilder.js index 8fa8b37..3078f8b 100644 --- a/src/ClientBuilder.js +++ b/src/ClientBuilder.js @@ -56,7 +56,11 @@ class ClientBuilder { this.customQueries = new Map(); function credentialsProvided() { - return signer instanceof StaticCredentials || signer instanceof SharedCredentials || signer instanceof BasicAuthCredentials; + return ( + signer instanceof StaticCredentials || + signer instanceof SharedCredentials || + signer instanceof BasicAuthCredentials + ); } } @@ -147,7 +151,7 @@ class ClientBuilder { if (this.appendHeaders[key].separator !== separator) { throw new Error( `Conflicting separators for appended header "${key}": ` + - `existing "${this.appendHeaders[key].separator}" vs new "${separator}"`, + `existing "${this.appendHeaders[key].separator}" vs new "${separator}"`, ); } this.appendHeaders[key].values.push(value); @@ -228,7 +232,6 @@ class ClientBuilder { return this.withCustomCommaSeperatedQuery("features", "occupant-use"); } - buildSender() { if (this.httpSender) return this.httpSender; @@ -240,7 +243,11 @@ class ClientBuilder { const retrySender = new RetrySender(this.maxRetries, signingSender, new Sleeper()); agentSender = new AgentSender(retrySender); } - const customHeaderSender = new CustomHeaderSender(agentSender, this.customHeaders, this.appendHeaders); + const customHeaderSender = new CustomHeaderSender( + agentSender, + this.customHeaders, + this.appendHeaders, + ); const baseUrlSender = new BaseUrlSender(customHeaderSender, this.baseUrl); const licenseSender = new LicenseSender(baseUrlSender, this.licenses); const customQuerySender = new CustomQuerySender(licenseSender, this.customQueries); diff --git a/src/Errors.js b/src/Errors.js index 9a79dac..57d8635 100644 --- a/src/Errors.js +++ b/src/Errors.js @@ -8,7 +8,6 @@ class DefaultError extends SmartyError { constructor(message) { super(message); } - } class BatchFullError extends SmartyError { @@ -31,13 +30,17 @@ class UndefinedLookupError extends SmartyError { class BadCredentialsError extends SmartyError { constructor() { - super("Unauthorized: The credentials were provided incorrectly or did not match any existing active credentials."); + super( + "Unauthorized: The credentials were provided incorrectly or did not match any existing active credentials.", + ); } } class PaymentRequiredError extends SmartyError { constructor() { - super("Payment Required: There is no active subscription for the account associated with the credentials submitted with the request."); + super( + "Payment Required: There is no active subscription for the account associated with the credentials submitted with the request.", + ); } } @@ -49,7 +52,9 @@ class RequestEntityTooLargeError extends SmartyError { class BadRequestError extends SmartyError { constructor() { - super("Bad Request (Malformed Payload): A GET request lacked a street field or the request body of a POST request contained malformed JSON."); + super( + "Bad Request (Malformed Payload): A GET request lacked a street field or the request body of a POST request contained malformed JSON.", + ); } } @@ -61,7 +66,9 @@ class UnprocessableEntityError extends SmartyError { class TooManyRequestsError extends SmartyError { constructor() { - super("When using the public 'embedded key' authentication, we restrict the number of requests coming from a given source over too short of a time."); + super( + "When using the public 'embedded key' authentication, we restrict the number of requests coming from a given source over too short of a time.", + ); } } @@ -79,7 +86,9 @@ class ServiceUnavailableError extends SmartyError { class GatewayTimeoutError extends SmartyError { constructor() { - super("The upstream data provider did not respond in a timely fashion and the request failed. A serious, yet rare occurrence indeed."); + super( + "The upstream data provider did not respond in a timely fashion and the request failed. A serious, yet rare occurrence indeed.", + ); } } @@ -96,5 +105,5 @@ module.exports = { InternalServerError: InternalServerError, ServiceUnavailableError: ServiceUnavailableError, GatewayTimeoutError: GatewayTimeoutError, - DefaultError: DefaultError -}; \ No newline at end of file + DefaultError: DefaultError, +}; diff --git a/src/HttpSender.js b/src/HttpSender.js index f488473..6bc9f96 100644 --- a/src/HttpSender.js +++ b/src/HttpSender.js @@ -1,5 +1,5 @@ const Axios = require("axios"); -const {buildSmartyResponse} = require("../src/util/buildSmartyResponse"); +const { buildSmartyResponse } = require("../src/util/buildSmartyResponse"); class HttpSender { constructor(timeout = 10000, proxyConfig, debug = false) { @@ -9,7 +9,7 @@ class HttpSender { if (debug) this.enableDebug(); } - buildRequestConfig({payload, parameters, headers, baseUrl}) { + buildRequestConfig({ payload, parameters, headers, baseUrl }) { let config = { method: "GET", timeout: this.timeout, @@ -35,32 +35,32 @@ class HttpSender { let requestConfig = this.buildRequestConfig(request); this.axiosInstance(requestConfig) - .then(response => { + .then((response) => { let smartyResponse = buildSmartyResponse(response); if (smartyResponse.statusCode >= 400) reject(smartyResponse); resolve(smartyResponse); }) - .catch(error => reject(buildSmartyResponse(undefined, error))); + .catch((error) => reject(buildSmartyResponse(undefined, error))); }); } enableDebug() { - this.axiosInstance.interceptors.request.use(request => { - console.log('Request:\r\n', request); - console.log('\r\n*******************************************\r\n'); - return request + this.axiosInstance.interceptors.request.use((request) => { + console.log("Request:\r\n", request); + console.log("\r\n*******************************************\r\n"); + return request; }); - this.axiosInstance.interceptors.response.use(response => { - console.log('Response:\r\n'); - console.log('Status:', response.status, response.statusText); - console.log('Headers:', response.headers); - console.log('Data:', response.data); - return response - }) + this.axiosInstance.interceptors.response.use((response) => { + console.log("Response:\r\n"); + console.log("Status:", response.status, response.statusText); + console.log("Headers:", response.headers); + console.log("Data:", response.data); + return response; + }); } } -module.exports = HttpSender; \ No newline at end of file +module.exports = HttpSender; diff --git a/src/InputData.js b/src/InputData.js index 1115738..c3d866b 100644 --- a/src/InputData.js +++ b/src/InputData.js @@ -5,7 +5,8 @@ class InputData { } add(apiField, lookupField) { - if (this.lookupFieldIsPopulated(lookupField)) this.data[apiField] = this.formatData(this.lookup[lookupField]); + if (this.lookupFieldIsPopulated(lookupField)) + this.data[apiField] = this.formatData(this.lookup[lookupField]); } addCustomParameter(key, value) { @@ -22,4 +23,4 @@ class InputData { } } -module.exports = InputData; \ No newline at end of file +module.exports = InputData; diff --git a/src/LicenseSender.js b/src/LicenseSender.js index dd6189f..813e0a5 100644 --- a/src/LicenseSender.js +++ b/src/LicenseSender.js @@ -10,11 +10,9 @@ class LicenseSender { } return new Promise((resolve, reject) => { - this.sender.send(request) - .then(resolve) - .catch(reject); + this.sender.send(request).then(resolve).catch(reject); }); } } -module.exports = LicenseSender; \ No newline at end of file +module.exports = LicenseSender; diff --git a/src/Request.js b/src/Request.js index 59294a2..b8e427b 100644 --- a/src/Request.js +++ b/src/Request.js @@ -1,5 +1,5 @@ class Request { - constructor(payload, headers = {"Content-Type": "application/json; charset=utf-8"}) { + constructor(payload, headers = { "Content-Type": "application/json; charset=utf-8" }) { this.baseUrl = ""; this.baseUrlParam = ""; this.payload = payload; @@ -9,4 +9,4 @@ class Request { } } -module.exports = Request; \ No newline at end of file +module.exports = Request; diff --git a/src/Response.js b/src/Response.js index 7cbd750..a2b0f02 100644 --- a/src/Response.js +++ b/src/Response.js @@ -1,5 +1,5 @@ class Response { - constructor (statusCode, payload, error, headers) { + constructor(statusCode, payload, error, headers) { this.statusCode = statusCode; this.payload = payload; this.error = error; @@ -7,4 +7,4 @@ class Response { } } -module.exports = Response; \ No newline at end of file +module.exports = Response; diff --git a/src/SigningSender.ts b/src/SigningSender.ts index ddb0701..b9afcc2 100644 --- a/src/SigningSender.ts +++ b/src/SigningSender.ts @@ -3,30 +3,30 @@ import SharedCredentials from "./SharedCredentials.js"; import { UnprocessableEntityError } from "./Errors.js"; interface Signer { - sign(request: Request): void; + sign(request: Request): void; } export default class SigningSender { - private signer: Signer; - private sender: Sender; + private signer: Signer; + private sender: Sender; - constructor(innerSender: Sender, signer: Signer) { - this.signer = signer; - this.sender = innerSender; - } + constructor(innerSender: Sender, signer: Signer) { + this.signer = signer; + this.sender = innerSender; + } - send(request: Request): Promise { - const sendingPostWithSharedCredentials = - request.payload && this.signer instanceof SharedCredentials; - if (sendingPostWithSharedCredentials) { - const message = - "Shared credentials cannot be used in batches with a length greater than 1 or when using the US Extract API."; - throw new UnprocessableEntityError(message); - } + send(request: Request): Promise { + const sendingPostWithSharedCredentials = + request.payload && this.signer instanceof SharedCredentials; + if (sendingPostWithSharedCredentials) { + const message = + "Shared credentials cannot be used in batches with a length greater than 1 or when using the US Extract API."; + throw new UnprocessableEntityError(message); + } - return new Promise((resolve, reject) => { - this.signer.sign(request); - this.sender.send(request).then(resolve).catch(reject); - }); - } -} \ No newline at end of file + return new Promise((resolve, reject) => { + this.signer.sign(request); + this.sender.send(request).then(resolve).catch(reject); + }); + } +} diff --git a/src/StatusCodeSender.js b/src/StatusCodeSender.js index cf40427..16dcdc2 100644 --- a/src/StatusCodeSender.js +++ b/src/StatusCodeSender.js @@ -7,9 +7,10 @@ class StatusCodeSender { send(request) { return new Promise((resolve, reject) => { - this.sender.send(request) + this.sender + .send(request) .then(resolve) - .catch(error => { + .catch((error) => { switch (error.statusCode) { case 500: error.error = new Errors.InternalServerError(); @@ -24,7 +25,12 @@ class StatusCodeSender { break; default: - error.error = new Errors.DefaultError(error && error.payload && error.payload.errors[0] && error.payload.errors[0].message); + error.error = new Errors.DefaultError( + error && + error.payload && + error.payload.errors[0] && + error.payload.errors[0].message, + ); } reject(error); }); @@ -32,4 +38,4 @@ class StatusCodeSender { } } -module.exports = StatusCodeSender; \ No newline at end of file +module.exports = StatusCodeSender; diff --git a/src/international_address_autocomplete/Client.js b/src/international_address_autocomplete/Client.js index 8f25f9a..b5ec358 100644 --- a/src/international_address_autocomplete/Client.js +++ b/src/international_address_autocomplete/Client.js @@ -20,8 +20,9 @@ class Client { } return new Promise((resolve, reject) => { - this.sender.send(request) - .then(response => { + this.sender + .send(request) + .then((response) => { if (response.error) reject(response.error); lookup.result = buildSuggestionsFromResponse(response.payload); @@ -33,9 +34,9 @@ class Client { function buildSuggestionsFromResponse(payload) { if (payload && payload.candidates === null) return []; - return payload.candidates.map(suggestion => new Suggestion(suggestion)); + return payload.candidates.map((suggestion) => new Suggestion(suggestion)); } } } -module.exports = Client; \ No newline at end of file +module.exports = Client; diff --git a/src/international_address_autocomplete/Lookup.js b/src/international_address_autocomplete/Lookup.js index ea4df48..5f0383e 100644 --- a/src/international_address_autocomplete/Lookup.js +++ b/src/international_address_autocomplete/Lookup.js @@ -1,5 +1,12 @@ class Lookup { - constructor({search, addressId, country, maxResults = 5, includeOnlyLocality, includeOnlyPostalCode} = {}) { + constructor({ + search, + addressId, + country, + maxResults = 5, + includeOnlyLocality, + includeOnlyPostalCode, + } = {}) { this.result = []; this.search = search; @@ -16,4 +23,4 @@ class Lookup { } } -module.exports = Lookup; \ No newline at end of file +module.exports = Lookup; diff --git a/src/international_address_autocomplete/Suggestion.js b/src/international_address_autocomplete/Suggestion.js index c2eecda..cfd0cc1 100644 --- a/src/international_address_autocomplete/Suggestion.js +++ b/src/international_address_autocomplete/Suggestion.js @@ -13,4 +13,4 @@ class Suggestion { } } -module.exports = Suggestion; \ No newline at end of file +module.exports = Suggestion; diff --git a/src/international_street/Candidate.js b/src/international_street/Candidate.js index 9219316..180dfe1 100644 --- a/src/international_street/Candidate.js +++ b/src/international_street/Candidate.js @@ -43,16 +43,22 @@ class Candidate { this.components.premiseType = responseData.components.premise_type; this.components.thoroughfare = responseData.components.thoroughfare; this.components.thoroughfarePredirection = responseData.components.thoroughfare_predirection; - this.components.thoroughfarePostdirection = responseData.components.thoroughfare_postdirection; + this.components.thoroughfarePostdirection = + responseData.components.thoroughfare_postdirection; this.components.thoroughfareName = responseData.components.thoroughfare_name; this.components.thoroughfareTrailingType = responseData.components.thoroughfare_trailing_type; this.components.thoroughfareType = responseData.components.thoroughfare_type; this.components.dependentThoroughfare = responseData.components.dependent_thoroughfare; - this.components.dependentThoroughfarePredirection = responseData.components.dependent_thoroughfare_predirection; - this.components.dependentThoroughfarePostdirection = responseData.components.dependent_thoroughfare_postdirection; - this.components.dependentThoroughfareName = responseData.components.dependent_thoroughfare_name; - this.components.dependentThoroughfareTrailingType = responseData.components.dependent_thoroughfare_trailing_type; - this.components.dependentThoroughfareType = responseData.components.dependent_thoroughfare_type; + this.components.dependentThoroughfarePredirection = + responseData.components.dependent_thoroughfare_predirection; + this.components.dependentThoroughfarePostdirection = + responseData.components.dependent_thoroughfare_postdirection; + this.components.dependentThoroughfareName = + responseData.components.dependent_thoroughfare_name; + this.components.dependentThoroughfareTrailingType = + responseData.components.dependent_thoroughfare_trailing_type; + this.components.dependentThoroughfareType = + responseData.components.dependent_thoroughfare_type; this.components.building = responseData.components.building; this.components.buildingLeadingType = responseData.components.building_leading_type; this.components.buildingName = responseData.components.building_name; @@ -69,7 +75,8 @@ class Candidate { this.components.additionalContent = responseData.components.additional_content; this.components.deliveryInstallation = responseData.components.delivery_installation; this.components.deliveryInstallationType = responseData.components.delivery_installation_type; - this.components.deliveryInstallationQualifierName = responseData.components.delivery_installation_qualifier_name; + this.components.deliveryInstallationQualifierName = + responseData.components.delivery_installation_qualifier_name; this.components.route = responseData.components.route; this.components.routeNumber = responseData.components.route_number; this.components.routeType = responseData.components.route_type; @@ -99,50 +106,94 @@ class Candidate { this.analysis.changes.components = {}; if (responseData.analysis.changes.components !== undefined) { - this.analysis.changes.components.countryIso3 = responseData.analysis.changes.components.country_iso_3; - this.analysis.changes.components.superAdministrativeArea = responseData.analysis.changes.components.super_administrative_area; - this.analysis.changes.components.administrativeArea = responseData.analysis.changes.components.administrative_area; - this.analysis.changes.components.administrativeAreaIso2 = responseData.analysis.changes.components.administrative_area_iso2; - this.analysis.changes.components.administrativeAreaShort = responseData.analysis.changes.components.administrative_area_short; - this.analysis.changes.components.administrativeAreaLong = responseData.analysis.changes.components.administrative_area_long; - this.analysis.changes.components.subAdministrativeArea = responseData.analysis.changes.components.sub_administrative_area; - this.analysis.changes.components.dependentLocality = responseData.analysis.changes.components.dependent_locality; - this.analysis.changes.components.dependentLocalityName = responseData.analysis.changes.components.dependent_locality_name; - this.analysis.changes.components.doubleDependentLocality = responseData.analysis.changes.components.double_dependent_locality; - this.analysis.changes.components.locality = responseData.analysis.changes.components.locality; - this.analysis.changes.components.postalCode = responseData.analysis.changes.components.postal_code; - this.analysis.changes.components.postalCodeShort = responseData.analysis.changes.components.postal_code_short; - this.analysis.changes.components.postalCodeExtra = responseData.analysis.changes.components.postal_code_extra; - this.analysis.changes.components.premise = responseData.analysis.changes.components.premise; - this.analysis.changes.components.premiseExtra = responseData.analysis.changes.components.premise_extra; - this.analysis.changes.components.premisePrefixNumber = responseData.analysis.changes.components.premise_prefix_number; - this.analysis.changes.components.premiseNumber = responseData.analysis.changes.components.premise_number; - this.analysis.changes.components.premiseType = responseData.analysis.changes.components.premise_type; - this.analysis.changes.components.thoroughfare = responseData.analysis.changes.components.thoroughfare; - this.analysis.changes.components.thoroughfarePredirection = responseData.analysis.changes.components.thoroughfare_predirection; - this.analysis.changes.components.thoroughfarePostdirection = responseData.analysis.changes.components.thoroughfare_postdirection; - this.analysis.changes.components.thoroughfareName = responseData.analysis.changes.components.thoroughfare_name; - this.analysis.changes.components.thoroughfareTrailingType = responseData.analysis.changes.components.thoroughfare_trailing_type; - this.analysis.changes.components.thoroughfareType = responseData.analysis.changes.components.thoroughfare_type; - this.analysis.changes.components.dependentThoroughfare = responseData.analysis.changes.components.dependent_thoroughfare; - this.analysis.changes.components.dependentThoroughfarePredirection = responseData.analysis.changes.components.dependent_thoroughfare_predirection; - this.analysis.changes.components.dependentThoroughfarePostdirection = responseData.analysis.changes.components.dependent_thoroughfare_postdirection; - this.analysis.changes.components.dependentThoroughfareName = responseData.analysis.changes.components.dependent_thoroughfare_name; - this.analysis.changes.components.dependentThoroughfareTrailingType = responseData.analysis.changes.components.dependent_thoroughfare_trailing_type; - this.analysis.changes.components.dependentThoroughfareType = responseData.analysis.changes.components.dependent_thoroughfare_type; - this.analysis.changes.components.building = responseData.analysis.changes.components.building; - this.analysis.changes.components.buildingLeadingType = responseData.analysis.changes.components.building_leading_type; - this.analysis.changes.components.buildingName = responseData.analysis.changes.components.building_name; - this.analysis.changes.components.buildingTrailingType = responseData.analysis.changes.components.building_trailing_type; - this.analysis.changes.components.subBuildingType = responseData.analysis.changes.components.sub_building_type; - this.analysis.changes.components.subBuildingNumber = responseData.analysis.changes.components.sub_building_number; - this.analysis.changes.components.subBuildingName = responseData.analysis.changes.components.sub_building_name; - this.analysis.changes.components.subBuilding = responseData.analysis.changes.components.sub_building; - this.analysis.changes.components.levelType = responseData.analysis.changes.components.level_type; - this.analysis.changes.components.levelNumber = responseData.analysis.changes.components.level_number; - this.analysis.changes.components.postBox = responseData.analysis.changes.components.post_box; - this.analysis.changes.components.postBoxType = responseData.analysis.changes.components.post_box_type; - this.analysis.changes.components.postBoxNumber = responseData.analysis.changes.components.post_box_number; + this.analysis.changes.components.countryIso3 = + responseData.analysis.changes.components.country_iso_3; + this.analysis.changes.components.superAdministrativeArea = + responseData.analysis.changes.components.super_administrative_area; + this.analysis.changes.components.administrativeArea = + responseData.analysis.changes.components.administrative_area; + this.analysis.changes.components.administrativeAreaIso2 = + responseData.analysis.changes.components.administrative_area_iso2; + this.analysis.changes.components.administrativeAreaShort = + responseData.analysis.changes.components.administrative_area_short; + this.analysis.changes.components.administrativeAreaLong = + responseData.analysis.changes.components.administrative_area_long; + this.analysis.changes.components.subAdministrativeArea = + responseData.analysis.changes.components.sub_administrative_area; + this.analysis.changes.components.dependentLocality = + responseData.analysis.changes.components.dependent_locality; + this.analysis.changes.components.dependentLocalityName = + responseData.analysis.changes.components.dependent_locality_name; + this.analysis.changes.components.doubleDependentLocality = + responseData.analysis.changes.components.double_dependent_locality; + this.analysis.changes.components.locality = + responseData.analysis.changes.components.locality; + this.analysis.changes.components.postalCode = + responseData.analysis.changes.components.postal_code; + this.analysis.changes.components.postalCodeShort = + responseData.analysis.changes.components.postal_code_short; + this.analysis.changes.components.postalCodeExtra = + responseData.analysis.changes.components.postal_code_extra; + this.analysis.changes.components.premise = + responseData.analysis.changes.components.premise; + this.analysis.changes.components.premiseExtra = + responseData.analysis.changes.components.premise_extra; + this.analysis.changes.components.premisePrefixNumber = + responseData.analysis.changes.components.premise_prefix_number; + this.analysis.changes.components.premiseNumber = + responseData.analysis.changes.components.premise_number; + this.analysis.changes.components.premiseType = + responseData.analysis.changes.components.premise_type; + this.analysis.changes.components.thoroughfare = + responseData.analysis.changes.components.thoroughfare; + this.analysis.changes.components.thoroughfarePredirection = + responseData.analysis.changes.components.thoroughfare_predirection; + this.analysis.changes.components.thoroughfarePostdirection = + responseData.analysis.changes.components.thoroughfare_postdirection; + this.analysis.changes.components.thoroughfareName = + responseData.analysis.changes.components.thoroughfare_name; + this.analysis.changes.components.thoroughfareTrailingType = + responseData.analysis.changes.components.thoroughfare_trailing_type; + this.analysis.changes.components.thoroughfareType = + responseData.analysis.changes.components.thoroughfare_type; + this.analysis.changes.components.dependentThoroughfare = + responseData.analysis.changes.components.dependent_thoroughfare; + this.analysis.changes.components.dependentThoroughfarePredirection = + responseData.analysis.changes.components.dependent_thoroughfare_predirection; + this.analysis.changes.components.dependentThoroughfarePostdirection = + responseData.analysis.changes.components.dependent_thoroughfare_postdirection; + this.analysis.changes.components.dependentThoroughfareName = + responseData.analysis.changes.components.dependent_thoroughfare_name; + this.analysis.changes.components.dependentThoroughfareTrailingType = + responseData.analysis.changes.components.dependent_thoroughfare_trailing_type; + this.analysis.changes.components.dependentThoroughfareType = + responseData.analysis.changes.components.dependent_thoroughfare_type; + this.analysis.changes.components.building = + responseData.analysis.changes.components.building; + this.analysis.changes.components.buildingLeadingType = + responseData.analysis.changes.components.building_leading_type; + this.analysis.changes.components.buildingName = + responseData.analysis.changes.components.building_name; + this.analysis.changes.components.buildingTrailingType = + responseData.analysis.changes.components.building_trailing_type; + this.analysis.changes.components.subBuildingType = + responseData.analysis.changes.components.sub_building_type; + this.analysis.changes.components.subBuildingNumber = + responseData.analysis.changes.components.sub_building_number; + this.analysis.changes.components.subBuildingName = + responseData.analysis.changes.components.sub_building_name; + this.analysis.changes.components.subBuilding = + responseData.analysis.changes.components.sub_building; + this.analysis.changes.components.levelType = + responseData.analysis.changes.components.level_type; + this.analysis.changes.components.levelNumber = + responseData.analysis.changes.components.level_number; + this.analysis.changes.components.postBox = + responseData.analysis.changes.components.post_box; + this.analysis.changes.components.postBoxType = + responseData.analysis.changes.components.post_box_type; + this.analysis.changes.components.postBoxNumber = + responseData.analysis.changes.components.post_box_number; } //TODO: Fill in the rest of these fields and their corresponding tests. } @@ -160,4 +211,4 @@ class Candidate { } } -module.exports = Candidate; \ No newline at end of file +module.exports = Candidate; diff --git a/src/international_street/Client.js b/src/international_street/Client.js index ef0a322..4bbfeb3 100644 --- a/src/international_street/Client.js +++ b/src/international_street/Client.js @@ -20,8 +20,9 @@ class Client { request.parameters = buildInputData(lookup, keyTranslationFormat); return new Promise((resolve, reject) => { - this.sender.send(request) - .then(response => { + this.sender + .send(request) + .then((response) => { if (response.error) reject(response.error); resolve(attachLookupCandidates(response, lookup)); @@ -30,7 +31,7 @@ class Client { }); function attachLookupCandidates(response, lookup) { - response.payload.map(rawCandidate => { + response.payload.map((rawCandidate) => { lookup.result.push(new Candidate(rawCandidate)); }); @@ -39,4 +40,4 @@ class Client { } } -module.exports = Client; \ No newline at end of file +module.exports = Client; diff --git a/src/international_street/Lookup.js b/src/international_street/Lookup.js index 4357ccb..050d990 100644 --- a/src/international_street/Lookup.js +++ b/src/international_street/Lookup.js @@ -2,12 +2,13 @@ const UnprocessableEntityError = require("../Errors").UnprocessableEntityError; const messages = { countryRequired: "Country field is required.", freeformOrAddress1Required: "Either freeform or address1 is required.", - insufficientInformation: "Insufficient information: One or more required fields were not set on the lookup.", + insufficientInformation: + "Insufficient information: One or more required fields were not set on the lookup.", badGeocode: "Invalid input: geocode can only be set to 'true' (default is 'false'.", - invalidLanguage: "Invalid input: language can only be set to 'latin' or 'native'. When not set, the the output language will match the language of the input values." + invalidLanguage: + "Invalid input: language can only be set to 'latin' or 'native'. When not set, the the output language will match the language of the input values.", }; - /** * In addition to holding all of the input data for this lookup, this class also
* will contain the result of the lookup after it comes back from the API. @@ -47,18 +48,20 @@ class Lookup { if (fieldIsSet(this.freeform)) return true; - if (fieldIsMissing(this.address1)) throw new UnprocessableEntityError(messages.freeformOrAddress1Required); + if (fieldIsMissing(this.address1)) + throw new UnprocessableEntityError(messages.freeformOrAddress1Required); if (fieldIsSet(this.postalCode)) return true; - if (fieldIsMissing(this.locality) || fieldIsMissing(this.administrativeArea)) throw new UnprocessableEntityError(messages.insufficientInformation); + if (fieldIsMissing(this.locality) || fieldIsMissing(this.administrativeArea)) + throw new UnprocessableEntityError(messages.insufficientInformation); return true; } ensureValidData() { let languageIsSetIncorrectly = () => { - let isLanguage = language => this.language.toLowerCase() === language; + let isLanguage = (language) => this.language.toLowerCase() === language; return fieldIsSet(this.language) && !(isLanguage("latin") || isLanguage("native")); }; @@ -75,7 +78,7 @@ class Lookup { } } -function fieldIsMissing (field) { +function fieldIsMissing(field) { if (!field) return true; const whitespaceCharacters = /\s/g; @@ -83,8 +86,8 @@ function fieldIsMissing (field) { return field.replace(whitespaceCharacters, "").length < 1; } -function fieldIsSet (field) { +function fieldIsSet(field) { return !fieldIsMissing(field); } -module.exports = Lookup; \ No newline at end of file +module.exports = Lookup; diff --git a/src/us_autocomplete_pro/Client.js b/src/us_autocomplete_pro/Client.js index f19703b..3b027d5 100644 --- a/src/us_autocomplete_pro/Client.js +++ b/src/us_autocomplete_pro/Client.js @@ -20,8 +20,9 @@ class Client { request.parameters = buildInputData(lookup, keyTranslationFormat); return new Promise((resolve, reject) => { - this.sender.send(request) - .then(response => { + this.sender + .send(request) + .then((response) => { if (response.error) reject(response.error); lookup.result = buildSuggestionsFromResponse(response.payload); @@ -33,9 +34,9 @@ class Client { function buildSuggestionsFromResponse(payload) { if (payload.suggestions === null) return []; - return payload.suggestions.map(suggestion => new Suggestion(suggestion)); + return payload.suggestions.map((suggestion) => new Suggestion(suggestion)); } } } -module.exports = Client; \ No newline at end of file +module.exports = Client; diff --git a/src/us_autocomplete_pro/Lookup.js b/src/us_autocomplete_pro/Lookup.js index f316c96..4ad5dfc 100644 --- a/src/us_autocomplete_pro/Lookup.js +++ b/src/us_autocomplete_pro/Lookup.js @@ -31,4 +31,4 @@ class Lookup { } } -module.exports = Lookup; \ No newline at end of file +module.exports = Lookup; diff --git a/src/us_autocomplete_pro/Suggestion.js b/src/us_autocomplete_pro/Suggestion.js index e75e0ab..c58ab3e 100644 --- a/src/us_autocomplete_pro/Suggestion.js +++ b/src/us_autocomplete_pro/Suggestion.js @@ -16,4 +16,4 @@ class Suggestion { } } -module.exports = Suggestion; \ No newline at end of file +module.exports = Suggestion; diff --git a/src/us_enrichment/Client.js b/src/us_enrichment/Client.js index dc90252..5b869d0 100644 --- a/src/us_enrichment/Client.js +++ b/src/us_enrichment/Client.js @@ -1,112 +1,117 @@ const Errors = require("../Errors"); const Request = require("../Request"); const buildInputData = require("../util/buildInputData"); -const {usEnrichment: keyTranslationFormat} = require("../util/apiToSDKKeyMap"); +const { usEnrichment: keyTranslationFormat } = require("../util/apiToSDKKeyMap"); class Client { - constructor(sender) { - this.sender = sender; - } - - sendPrincipal(lookup) { - if (typeof lookup === "undefined") throw new Errors.UndefinedLookupError(); - - let request = new Request(); - request.parameters = buildInputData(lookup, keyTranslationFormat); - - request.baseUrlParam = lookup.smartyKey + "/property/principal"; - - return new Promise((resolve, reject) => { - this.sender.send(request) - .then(response => { - if (response.error) reject(response.error); - - lookup.response = response.payload; - resolve(lookup); - }) - .catch(reject); - }); - } - - sendFinancial(lookup) { - if (typeof lookup === "undefined") throw new Errors.UndefinedLookupError(); - - let request = new Request(); - request.parameters = buildInputData(lookup, keyTranslationFormat); - - request.baseUrlParam = lookup.smartyKey + "/property/financial"; - - return new Promise((resolve, reject) => { - this.sender.send(request) - .then(response => { - if (response.error) reject(response.error); - - lookup.response = response.payload; - resolve(lookup); - }) - .catch(reject); - }); - } - - sendGeo(lookup) { - if (typeof lookup === "undefined") throw new Errors.UndefinedLookupError(); - - let request = new Request(); - request.parameters = buildInputData(lookup, keyTranslationFormat); - - request.baseUrlParam = lookup.smartyKey + "/geo-reference"; - - return new Promise((resolve, reject) => { - this.sender.send(request) - .then(response => { - if (response.error) reject(response.error); - - lookup.response = response.payload; - resolve(lookup); - }) - .catch(reject); - }); - } - - sendSecondary(lookup) { - if (typeof lookup === "undefined") throw new Errors.UndefinedLookupError(); - - let request = new Request(); - request.parameters = buildInputData(lookup, keyTranslationFormat); - - request.baseUrlParam = lookup.smartyKey + "/secondary"; - - return new Promise((resolve, reject) => { - this.sender.send(request) - .then(response => { - if (response.error) reject(response.error); - - lookup.response = response.payload; - resolve(lookup); - }) - .catch(reject); - }); - } - - sendSecondaryCount(lookup) { - if (typeof lookup === "undefined") throw new Errors.UndefinedLookupError(); - - let request = new Request(); - request.parameters = buildInputData(lookup, keyTranslationFormat); - - request.baseUrlParam = lookup.smartyKey + "/secondary/count"; - - return new Promise((resolve, reject) => { - this.sender.send(request) - .then(response => { - if (response.error) reject(response.error); - - lookup.response = response.payload; - resolve(lookup); - }) - .catch(reject); - }); - } + constructor(sender) { + this.sender = sender; + } + + sendPrincipal(lookup) { + if (typeof lookup === "undefined") throw new Errors.UndefinedLookupError(); + + let request = new Request(); + request.parameters = buildInputData(lookup, keyTranslationFormat); + + request.baseUrlParam = lookup.smartyKey + "/property/principal"; + + return new Promise((resolve, reject) => { + this.sender + .send(request) + .then((response) => { + if (response.error) reject(response.error); + + lookup.response = response.payload; + resolve(lookup); + }) + .catch(reject); + }); + } + + sendFinancial(lookup) { + if (typeof lookup === "undefined") throw new Errors.UndefinedLookupError(); + + let request = new Request(); + request.parameters = buildInputData(lookup, keyTranslationFormat); + + request.baseUrlParam = lookup.smartyKey + "/property/financial"; + + return new Promise((resolve, reject) => { + this.sender + .send(request) + .then((response) => { + if (response.error) reject(response.error); + + lookup.response = response.payload; + resolve(lookup); + }) + .catch(reject); + }); + } + + sendGeo(lookup) { + if (typeof lookup === "undefined") throw new Errors.UndefinedLookupError(); + + let request = new Request(); + request.parameters = buildInputData(lookup, keyTranslationFormat); + + request.baseUrlParam = lookup.smartyKey + "/geo-reference"; + + return new Promise((resolve, reject) => { + this.sender + .send(request) + .then((response) => { + if (response.error) reject(response.error); + + lookup.response = response.payload; + resolve(lookup); + }) + .catch(reject); + }); + } + + sendSecondary(lookup) { + if (typeof lookup === "undefined") throw new Errors.UndefinedLookupError(); + + let request = new Request(); + request.parameters = buildInputData(lookup, keyTranslationFormat); + + request.baseUrlParam = lookup.smartyKey + "/secondary"; + + return new Promise((resolve, reject) => { + this.sender + .send(request) + .then((response) => { + if (response.error) reject(response.error); + + lookup.response = response.payload; + resolve(lookup); + }) + .catch(reject); + }); + } + + sendSecondaryCount(lookup) { + if (typeof lookup === "undefined") throw new Errors.UndefinedLookupError(); + + let request = new Request(); + request.parameters = buildInputData(lookup, keyTranslationFormat); + + request.baseUrlParam = lookup.smartyKey + "/secondary/count"; + + return new Promise((resolve, reject) => { + this.sender + .send(request) + .then((response) => { + if (response.error) reject(response.error); + + lookup.response = response.payload; + resolve(lookup); + }) + .catch(reject); + }); + } } -module.exports = Client; \ No newline at end of file +module.exports = Client; diff --git a/src/us_enrichment/Lookup.js b/src/us_enrichment/Lookup.js index 045947c..c4ad2a9 100644 --- a/src/us_enrichment/Lookup.js +++ b/src/us_enrichment/Lookup.js @@ -1,19 +1,19 @@ class Lookup { - constructor(smartyKey, include, exclude, dataset, dataSubset) { - this.smartyKey = smartyKey; - this.include = include; - this.exclude = exclude; - this.dataset = dataset; - this.dataSubset = dataSubset; - this.features = undefined; + constructor(smartyKey, include, exclude, dataset, dataSubset) { + this.smartyKey = smartyKey; + this.include = include; + this.exclude = exclude; + this.dataset = dataset; + this.dataSubset = dataSubset; + this.features = undefined; - this.response = {}; - this.customParameters = {}; - }; + this.response = {}; + this.customParameters = {}; + } - addCustomParameter(key, value) { + addCustomParameter(key, value) { this.customParameters[key] = value; } } -module.exports = Lookup; \ No newline at end of file +module.exports = Lookup; diff --git a/src/us_enrichment/Response.js b/src/us_enrichment/Response.js index 26cb040..77acade 100644 --- a/src/us_enrichment/Response.js +++ b/src/us_enrichment/Response.js @@ -1,607 +1,630 @@ class Response { - constructor(responseData) { - this.smartyKey = responseData.smarty_key; - this.dataSetName = responseData.data_set_name; - this.dataSubsetName = responseData.data_subset_name; + constructor(responseData) { + this.smartyKey = responseData.smarty_key; + this.dataSetName = responseData.data_set_name; + this.dataSubsetName = responseData.data_subset_name; - this.attributes = {}; - if (responseData.attributes) { - this.attributes.firstFloorSqft = responseData.attributes["1st_floor_sqft"]; - this.attributes.secondFlootSqft = responseData.attributes["2nd_floor_sqft"]; - this.attributes.acres = responseData.attributes.acres; - this.attributes.addressInfoPrivacy = responseData.attributes.address_info_privacy; - this.attributes.airConditioner = responseData.attributes.air_conditioner; - this.attributes.arborPergola = responseData.attributes.arbor_pergola; - this.attributes.assessedImprovementPercent = responseData.attributes.assessed_improvement_percent; - this.attributes.assessedImprovementValue = responseData.attributes.assessed_improvement_value; - this.attributes.assessedLandValue = responseData.attributes.assessed_land_value; - this.attributes.assessedValue = responseData.attributes.assessed_value; - this.attributes.assessorLastUpdate = responseData.attributes.assessor_last_update; - this.attributes.assessorTaxrollUpdate = responseData.attributes.assessor_taxroll_update; - this.attributes.atticArea = responseData.attributes.attic_area; - this.attributes.atticFlag = responseData.attributes.attic_flag; - this.attributes.balcony = responseData.attributes.balcony; - this.attributes.balconyArea = responseData.attributes.balcony_area; - this.attributes.basementSqft = responseData.attributes.basement_sqft; - this.attributes.basementSqftFinished = responseData.attributes.basement_sqft_finished; - this.attributes.basementsqftUnfinished = responseData.attributes.basement_sqft_unfinished; - this.attributes.bathHouse = responseData.attributes.bath_house; - this.attributes.bathHouseSqft = responseData.attributes.bath_house_sqft; - this.attributes.bathroomsPartial = responseData.attributes.bathrooms_partial; - this.attributes.bathroomsTotal = responseData.attributes.bathrooms_total; - this.attributes.bedrooms = responseData.attributes.bedrooms; - this.attributes.block1 = responseData.attributes.block_1; - this.attributes.block2 = responseData.attributes.block_2; - this.attributes.boatAccess = responseData.attributes.boat_access; - this.attributes.boatHouse = responseData.attributes.boat_house; - this.attributes.boatHouseSqft = responseData.attributes.boat_house_sqft; - this.attributes.boatLift = responseData.attributes.boat_lift; - this.attributes.bonusRoom = responseData.attributes.bonus_room; - this.attributes.breakfastNook = responseData.attributes.breakfast_nook; - this.attributes.breezeway = responseData.attributes.breezeway; - this.attributes.buildingDefinitionCode = responseData.attributes.building_definition; - this.attributes.buildingSqft = responseData.attributes.building_sqft; - this.attributes.cabin = responseData.attributes.cabin; - this.attributes.cabinSqft = responseData.attributes.cabin_sqft; - this.attributes.canopy = responseData.attributes.canopy; - this.attributes.canopySqft = responseData.attributes.canopy_sqft; - this.attributes.carport = responseData.attributes.carport; - this.attributes.carportSqft = responseData.attributes.carport_sqft; - this.attributes.cbsaCode = responseData.attributes.cbsa_code; - this.attributes.cbsaName = responseData.attributes.cbsa_name; - this.attributes.cellar = responseData.attributes.cellar; - this.attributes.censusBlock = responseData.attributes.census_block; - this.attributes.censusTract = responseData.attributes.census_tract; - this.attributes.censusBlockGroup = responseData.attributes.census_block_group; - this.attributes.censusFipsPlaceCode = responseData.attributes.census_fips_place_code; - this.attributes.censusTract = responseData.attributes.census_tract; - this.attributes.centralVacuum = responseData.attributes.central_vacuum; - this.attributes.codeTitleCompany = responseData.attributes.code_title_company; - this.attributes.combinedStatisticalArea = responseData.attributes.combined_statistical_area; - this.attributes.communityRec = responseData.attributes.community_rec; - this.attributes.companyFlag = responseData.attributes.company_flag; - this.attributes.congressionalDistrict = responseData.attributes.congressional_district; - this.attributes.constructionType = responseData.attributes.construction_type; - this.attributes.contactCity = responseData.attributes.contact_city; - this.attributes.contactCrrt = responseData.attributes.contact_crrt; - this.attributes.contactFullAddress = responseData.attributes.contact_full_address; - this.attributes.contactHouseNumber = responseData.attributes.contact_house_number; - this.attributes.contactMailInfoFormat = responseData.attributes.contact_main_info_format; - this.attributes.contactMailInfoPrivacy = responseData.attributes.contact_mail_info_privacy; - this.attributes.contactMailingCounty = responseData.attributes.contact_mailing_county; - this.attributes.contactMailingFips = responseData.attributes.contact_mailing_fips; - this.attributes.contactPostDirection = responseData.attributes.contact_post_direction; - this.attributes.contactPreDirection = responseData.attributes.contact_pre_direction; - this.attributes.contactState = responseData.attributes.contact_state; - this.attributes.contactStreetName = responseData.attributes.contact_street_name; - this.attributes.contactSuffix = responseData.attributes.contact_suffix; - this.attributes.contactUnitDesignator = responseData.attributes.contact_unit_designator; - this.attributes.contactValue = responseData.attributes.contact_value; - this.attributes.contactZip = responseData.attributes.contact_zip; - this.attributes.contactZip4 = responseData.attributes.contact_zip4; - this.attributes.courtyard = responseData.attributes.courtyard; - this.attributes.courtyardArea = responseData.attributes.courtyard_area; - this.attributes.deck = responseData.attributes.deck; - this.attributes.deckArea = responseData.attributes.deck_area; - this.attributes.deedDocumentPage = responseData.attributes.deed_document_page; - this.attributes.deedDocumentBook = responseData.attributes.deed_document_book; - this.attributes.deedDocumentNumber = responseData.attributes.deed_document_number; - this.attributes.deedOwnerFirstName = responseData.attributes.deed_owner_first_name; - this.attributes.deedOwnerFirstName2 = responseData.attributes.deed_owner_first_name2; - this.attributes.deedOwnerFirstName3 = responseData.attributes.deed_owner_first_name3; - this.attributes.deedOwnerFirstName4 = responseData.attributes.deed_owner_first_name4; - this.attributes.deedOwnerFullName = responseData.attributes.deed_owner_full_name; - this.attributes.deedOwnerFullName2 = responseData.attributes.deed_owner_full_name2; - this.attributes.deedOwnerFullName3 = responseData.attributes.deed_owner_full_name3; - this.attributes.deedOwnerFullName4 = responseData.attributes.deed_owner_full_name4; - this.attributes.deedOwnerLastName = responseData.attributes.deed_owner_last_name; - this.attributes.deedOwnerLastName2 = responseData.attributes.deed_owner_last_name2; - this.attributes.deedOwnerLastName3 = responseData.attributes.deed_owner_last_name3; - this.attributes.deedOwnerLastName4 = responseData.attributes.deed_owner_last_name4; - this.attributes.deedOwnerMiddleName = responseData.attributes.deed_owner_middle_name; - this.attributes.deedOwnerMiddleName2 = responseData.attributes.deed_owner_middle_name2; - this.attributes.deedOwnerMiddleName3 = responseData.attributes.deed_owner_middle_name3; - this.attributes.deedOwnerMiddleName4 = responseData.attributes.deed_owner_middle_name4; - this.attributes.deedOwnerSuffix = responseData.attributes.deed_owner_suffix; - this.attributes.deedOwnerSuffix2 = responseData.attributes.deed_owner_suffix2; - this.attributes.deedOwnerSuffix3 = responseData.attributes.deed_owner_suffix3; - this.attributes.deedOwnerSuffix4 = responseData.attributes.deed_owner_suffix4; - this.attributes.deedSaleDate = responseData.attributes.deed_sale_date; - this.attributes.deedSalePrice = responseData.attributes.deed_sale_price; - this.attributes.deedTransactionId = responseData.attributes.deed_transaction_id; - this.attributes.depthLinearFootage = responseData.attributes.depth_linear_footage; - this.attributes.disabledTaxExemption = responseData.attributes.disabled_tax_exemption; - this.attributes.drivewaySqft = responseData.attributes.driveway_sqft; - this.attributes.drivewayType = responseData.attributes.driveway_type; - this.attributes.effectiveYearBuilt = responseData.attributes.effective_year_built; - this.attributes.elevationFeet = responseData.attributes.elevation_feet; - this.attributes.elevator = responseData.attributes.elevator; - this.attributes.equestrianArena = responseData.attributes.equestrian_arena; - this.attributes.escalator = responseData.attributes.escalator; - this.attributes.exerciseRoom = responseData.attributes.exercise_room; - this.attributes.exteriorWalls = responseData.attributes.exterior_walls; - this.attributes.familyRoom = responseData.attributes.family_room; - this.attributes.financialHistory = !responseData.attributes.financial_history ? [] : responseData.attributes.financial_history.map(history => { - return { - codeTitleCompany: history.code_title_company, - instrumentDate: history.instrument_date, - interestRateType2: history.interest_rate_type_2, - lenderAddress: history.lender_address, - lenderAddress2: history.lender_address_2, - lenderCity: history.lender_city, - lenderCity2: history.lender_city_2, - lenderCode: history.lender_code, - lenderCode2: history.lender_code_2, - lenderFirstName: history.lender_first_name, - lenderFirstName2: history.lender_first_name_2, - lenderLastName: history.lender_last_name, - lenderLastName2: history.lender_last_name_2, - lenderName: history.lender_name, - lenderName2: history.lender_name_2, - lenderSellerCarryBack: history.lender_seller_carry_back, - lenderSellerCarryBack2: history.lender_seller_carry_back_2, - lenderState: history.lender_state, - lenderState2: history.lender_state_2, - lenderZip: history.lender_zip, - lenderZip2: history.lender_zip_2, - lenderZipExtended: history.lender_zip_extended, - lenderZipExtended2: history.lender_zip_extended_2, - mortgageAmount: history.mortgage_amount, - mortgageAmount2: history.mortgage_amount_2, - mortgageDueDate: history.mortgage_due_date, - mortgageDueDate2: history.mortgage_due_date_2, - mortgageInterestRate: history.mortgage_interest_rate, - mortgageInterestRateType: history.mortgage_interest_rate_type, - mortgageLenderCode: history.mortgage_lender_code, - mortgageRate: history.mortgage_rate, - mortgageRate2: history.mortgage_rate_2, - mortgageRecordingDate: history.mortgage_recording_date, - mortgageRecordingDate2: history.mortgage_recording_date_2, - mortgageTerm: history.mortgage_term, - mortgageTerm2: history.mortgage_term_2, - mortgageTermType: history.mortgage_term_type, - mortgageTermType2: history.mortgage_term_type_2, - mortgageType: history.mortgage_type, - mortgageType2: history.mortgage_type_2, - multiParcelFlag: history.multi_parcel_flag, - nameTitleCompany: history.name_title_company, - recordingDate: history.recording_date, - transferAmount: history.transfer_amount, - } - }) - this.attributes.fence = responseData.attributes.fence; - this.attributes.fenceArea = responseData.attributes.fence_area; - this.attributes.fipsCode = responseData.attributes.fips_code; - this.attributes.fireResistanceCode = responseData.attributes.fire_resistance_code; - this.attributes.fireSprinklersFlag = responseData.attributes.fire_sprinkler_flag; - this.attributes.fireplace = responseData.attributes.fireplace; - this.attributes.fireplaceNumber = responseData.attributes.fireplace_number; - this.attributes.firstName = responseData.attributes.first_name; - this.attributes.firstName2 = responseData.attributes.first_name2; - this.attributes.firstName3 = responseData.attributes.first_name3; - this.attributes.firstName4 = responseData.attributes.first_name4; - this.attributes.flooring = responseData.attributes.flooring; - this.attributes.foundation = responseData.attributes.foundation; - this.attributes.gameRoom = responseData.attributes.game_room; - this.attributes.garage = responseData.attributes.garage; - this.attributes.garageSqft = responseData.attributes.garage_sqft; - this.attributes.gazebo = responseData.attributes.gazebo; - this.attributes.gazeboSqft = responseData.attributes.gazebo_sqft; - this.attributes.golfCourse = responseData.attributes.golf_course; - this.attributes.grainery = responseData.attributes.grainery; - this.attributes.grainerySqft = responseData.attributes.grainery_sqft; - this.attributes.greatRoom = responseData.attributes.great_room; - this.attributes.greenhouse = responseData.attributes.greenhouse; - this.attributes.greenhouseSqft = responseData.attributes.greenhouse_sqft; - this.attributes.grossSqft = responseData.attributes.gross_sqft; - this.attributes.guesthouse = responseData.attributes.guesthouse; - this.attributes.guesthouseSqft = responseData.attributes.guesthouse_sqft; - this.attributes.handicapAccessibility = responseData.attributes.handicap_accessibility; - this.attributes.heat = responseData.attributes.heat; - this.attributes.heatFuelType = responseData.attributes.heat_fuel_type; - this.attributes.hobbyRoom = responseData.attributes.hobby_room; - this.attributes.homeownerTaxExemption = responseData.attributes.homeowner_tax_exemption; - this.attributes.instrumentDate = responseData.attributes.instrument_date; - this.attributes.intercomSystem = responseData.attributes.intercom_system; - this.attributes.interestRateType2 = responseData.attributes.interest_rate_type_2; - this.attributes.interiorStructure = responseData.attributes.interior_structure; - this.attributes.kennel = responseData.attributes.kennel; - this.attributes.kennelSqft = responseData.attributes.kennel_sqft; - this.attributes.landUseCode = responseData.attributes.land_use_code; - this.attributes.landUseGroup = responseData.attributes.land_use_group; - this.attributes.landUseStandard = responseData.attributes.land_use_standard; - this.attributes.lastName = responseData.attributes.last_name; - this.attributes.lastName2 = responseData.attributes.last_name_2; - this.attributes.lastName3 = responseData.attributes.last_name_3; - this.attributes.lastName4 = responseData.attributes.last_name_4; - this.attributes.latitude = responseData.attributes.latitude; - this.attributes.laundry = responseData.attributes.laundry; - this.attributes.leanTo = responseData.attributes.lean_to; - this.attributes.leanToSqft = responseData.attributes.lean_to_sqft; - this.attributes.legalDescription = responseData.attributes.legal_description; - this.attributes.legalUnit = responseData.attributes.legal_unit; - this.attributes.lenderAddress = responseData.attributes.lender_address; - this.attributes.lenderAddress2 = responseData.attributes.lender_address_2; - this.attributes.lenderCity = responseData.attributes.lender_city; - this.attributes.lenderCity2 = responseData.attributes.lender_city_2; - this.attributes.lenderCode = responseData.attributes.lender_code; - this.attributes.lenderCode2 = responseData.attributes.lender_code_2; - this.attributes.lenderFirstName = responseData.attributes.lender_first_name; - this.attributes.lenderFirstName2 = responseData.attributes.lender_first_name_2; - this.attributes.lenderLastName = responseData.attributes.lender_last_name; - this.attributes.lenderLastName2 = responseData.attributes.lender_last_name_2; - this.attributes.lenderName = responseData.attributes.lender_name; - this.attributes.lenderName2 = responseData.attributes.lender_name_2; - this.attributes.lenderSellerCarryBack = responseData.attributes.lender_seller_carry_back; - this.attributes.lenderSellerCarryBack2 = responseData.attributes.lender_seller_carry_back_2; - this.attributes.lenderState = responseData.attributes.lender_state; - this.attributes.lenderState2 = responseData.attributes.lender_state_2; - this.attributes.lenderZip = responseData.attributes.lender_zip; - this.attributes.lenderZip2 = responseData.attributes.lender_zip_2; - this.attributes.lenderZipExtended = responseData.attributes.lender_zip_extended; - this.attributes.lenderZipExtended2 = responseData.attributes.lender_zip_extended_2; - this.attributes.loadingPlatform = responseData.attributes.loading_platform; - this.attributes.loadingPlatformSqft = responseData.attributes.loading_platform_sqft; - this.attributes.longitude = responseData.attributes.longitude; - this.attributes.lot1 = responseData.attributes.lot_1; - this.attributes.lot2 = responseData.attributes.lot_2; - this.attributes.lot3 = responseData.attributes.lot_3; - this.attributes.lotSqft = responseData.attributes.lot_sqft; - this.attributes.marketImprovementPercent = responseData.attributes.market_improvement_percent; - this.attributes.marketImprovementValue = responseData.attributes.market_improvement_value; - this.attributes.marketLandValue = responseData.attributes.market_land_value; - this.attributes.marketValueYear = responseData.attributes.market_value_year; - this.attributes.matchType = responseData.attributes.match_type; - this.attributes.mediaRoom = responseData.attributes.media_room; - this.attributes.metroDivision = responseData.attributes.metro_division; - this.attributes.middleName = responseData.attributes.middle_name; - this.attributes.middleName2 = responseData.attributes.middle_name_2; - this.attributes.middleName3 = responseData.attributes.middle_name_3; - this.attributes.middleName4 = responseData.attributes.middle_name_4; - this.attributes.milkhouse = responseData.attributes.milkhouse; - this.attributes.milkhouseSqft = responseData.attributes.milkhouse_sqft; - this.attributes.minorCivilDivisionCode = responseData.attributes.minor_civil_division_code; - this.attributes.minorCivilDivisionName = responseData.attributes.minor_civil_division_name; - this.attributes.mobileHomeHookup = responseData.attributes.mobile_home_hookup; - this.attributes.mortgageAmount = responseData.attributes.mortgage_amount; - this.attributes.mortgageAmount2 = responseData.attributes.mortgage_amount_2; - this.attributes.mortgageDueDate = responseData.attributes.mortgage_due_date; - this.attributes.mortgageDueDate2 = responseData.attributes.mortgage_due_date_2; - this.attributes.mortgageInterestRate = responseData.attributes.mortgage_interest_rate; - this.attributes.mortgageInterestRateType = responseData.attributes.mortgage_interest_rate_type; - this.attributes.mortgageLenderCode = responseData.attributes.mortgage_lender_code; - this.attributes.mortgageRate2 = responseData.attributes.mortgage_rate_2; - this.attributes.mortgageRecordingDate = responseData.attributes.mortgage_recording_date; - this.attributes.mortgageRecordingDate2 = responseData.attributes.mortgage_recording_date_2; - this.attributes.mortgageTerm = responseData.attributes.mortgage_term; - this.attributes.mortgageTerm2 = responseData.attributes.mortgage_term_2; - this.attributes.mortgageTermType = responseData.attributes.mortgage_term_type; - this.attributes.mortgageTermType2 = responseData.attributes.mortgage_term_type_2; - this.attributes.mortgageType = responseData.attributes.mortgage_type; - this.attributes.mortgageType2 = responseData.attributes.mortgage_type_2; - this.attributes.msaCode = responseData.attributes.msa_code; - this.attributes.msaName = responseData.attributes.msa_name; - this.attributes.mudRoom = responseData.attributes.mud_room; - this.attributes.multiParcelFlag = responseData.attributes.multi_parcel_flag; - this.attributes.nameTitleCompany = responseData.attributes.name_title_company; - this.attributes.neighborhoodCode = responseData.attributes.neighborhood_code; - this.attributes.numberOfBuildings = responseData.attributes.number_of_buildings; - this.attributes.office = responseData.attributes.office; - this.attributes.officeSqft = responseData.attributes.office_sqft; - this.attributes.otherTaxExemption = responseData.attributes.other_tax_exemption; - this.attributes.outdoorKitchenFireplace = responseData.attributes.outdoor_kitchen_fireplace; - this.attributes.overheadDoor = responseData.attributes.overhead_door; - this.attributes.ownerFullName = responseData.attributes.owner_full_name; - this.attributes.ownerFullName2 = responseData.attributes.owner_full_name_2; - this.attributes.ownerFullName3 = responseData.attributes.owner_full_name_3; - this.attributes.ownerFullName4 = responseData.attributes.owner_full_name_4; - this.attributes.ownerOccupancyStatus = responseData.attributes.owner_occupancy_status; - this.attributes.ownershipTransferDate = responseData.attributes.ownership_transfer_date; - this.attributes.ownershipTransferDocNumber = responseData.attributes.ownership_transfer_doc_number; - this.attributes.ownershipTransferTransactionId = responseData.attributes.ownership_transfer_transaction_id; - this.attributes.ownershipType = responseData.attributes.ownership_type; - this.attributes.ownershipType2 = responseData.attributes.ownership_type_2; - this.attributes.ownershipVestingRelationCode = responseData.attributes.ownership_vesting_relation_code; - this.attributes.parcelAccountNumber = responseData.attributes.parcel_account_number; - this.attributes.parcelMapBook = responseData.attributes.parcel_map_book; - this.attributes.parcelMapPage = responseData.attributes.parcel_map_page; - this.attributes.parcelNumberAlternate = responseData.attributes.parcel_number_alternate; - this.attributes.parcelNumberFormatted = responseData.attributes.parcel_number_formatted; - this.attributes.parcelNumberPrevious = responseData.attributes.parcel_number_previous; - this.attributes.parcelNumberYearAdded = responseData.attributes.parcel_number_year_added; - this.attributes.parcelNumberYearChange = responseData.attributes.parcel_number_year_change; - this.attributes.parcelRawNumber = responseData.attributes.parcel_raw_number; - this.attributes.parcelShellRecord = responseData.attributes.parcel_shell_record; - this.attributes.parkingSpaces = responseData.attributes.parking_spaces; - this.attributes.patioArea = responseData.attributes.patio_area; - this.attributes.phaseName = responseData.attributes.phase_name; - this.attributes.plumbingFixturesCount = responseData.attributes.plumbing_fixtures_count; - this.attributes.poleStruct = responseData.attributes.pole_struct; - this.attributes.poleStructSqft = responseData.attributes.pole_struct_sqft; - this.attributes.pond = responseData.attributes.pond; - this.attributes.pool = responseData.attributes.pool; - this.attributes.poolArea = responseData.attributes.pool_area; - this.attributes.poolhouse = responseData.attributes.poolhouse; - this.attributes.poolhouseSqft = responseData.attributes.poolhouse_sqft; - this.attributes.porch = responseData.attributes.porch; - this.attributes.porchArea = responseData.attributes.porch_area; - this.attributes.poultryHouse = responseData.attributes.poultry_house; - this.attributes.poultryHouseSqft = responseData.attributes.poultry_house_sqft; - this.attributes.previousAssessedValue = responseData.attributes.previous_assessed_value; - this.attributes.priorSaleAmount = responseData.attributes.prior_sale_amount; - this.attributes.priorSaleDate = responseData.attributes.prior_sale_date; - this.attributes.propertyAddressCarrierRouteCode = responseData.attributes.property_address_carrier_route_code; - this.attributes.propertyAddressCity = responseData.attributes.property_address_city; - this.attributes.propertyAddressFull = responseData.attributes.property_address_full; - this.attributes.propertyAddressHouseNumber = responseData.attributes.property_address_house_number; - this.attributes.propertyAddressPostDirection = responseData.attributes.property_address_post_direction; - this.attributes.propertyAddressPreDirection = responseData.attributes.property_address_pre_direction; - this.attributes.propertyAddressState = responseData.attributes.property_address_state; - this.attributes.propertyAddressStreetName = responseData.attributes.property_address_street_name; - this.attributes.propertyAddressStreetSuffix = responseData.attributes.property_address_street_suffix; - this.attributes.propertyAddressUnitDesignator = responseData.attributes.property_address_unit_designator; - this.attributes.propertyAddressUnitValue = responseData.attributes.property_address_unit_value; - this.attributes.propertyAddressZip4 = responseData.attributes.property_address_zip_4; - this.attributes.propertyAddressZipcode = responseData.attributes.property_address_zipcode; - this.attributes.publicationDate = responseData.attributes.publication_date; - this.attributes.quarter = responseData.attributes.quarter; - this.attributes.quarterQuarter = responseData.attributes.quarter_quarter; - this.attributes.quonset = responseData.attributes.quonset; - this.attributes.quonsetSqft = responseData.attributes.quonset_sqft; - this.attributes.range = responseData.attributes.range; - this.attributes.recordingDate = responseData.attributes.recording_date; - this.attributes.roofCover = responseData.attributes.roof_cover; - this.attributes.roofFrame = responseData.attributes.roof_frame; - this.attributes.rooms = responseData.attributes.rooms; - this.attributes.rvParking = responseData.attributes.rv_parking; - this.attributes.safeRoom = responseData.attributes.safe_room; - this.attributes.saleAmount = responseData.attributes.sale_amount; - this.attributes.saleDate = responseData.attributes.sale_date; - this.attributes.sauna = responseData.attributes.sauna; - this.attributes.section = responseData.attributes.section; - this.attributes.securityAlarm = responseData.attributes.security_alarm; - this.attributes.seniorTaxExemption = responseData.attributes.senior_tax_exemption; - this.attributes.sewerType = responseData.attributes.sewer_type; - this.attributes.shed = responseData.attributes.shed; - this.attributes.shedSqft = responseData.attributes.shed_sqft; - this.attributes.silo = responseData.attributes.silo; - this.attributes.siloSqft = responseData.attributes.silo_sqft; - this.attributes.sittingRoom = responseData.attributes.sitting_room; - this.attributes.situsCounty = responseData.attributes.situs_county; - this.attributes.situsState = responseData.attributes.situs_state; - this.attributes.soundSystem = responseData.attributes.sound_system; - this.attributes.sportsCourt = responseData.attributes.sports_court; - this.attributes.sprinklers = responseData.attributes.sprinklers; - this.attributes.stable = responseData.attributes.stable; - this.attributes.stableSqft = responseData.attributes.stable_sqft; - this.attributes.storageBuilding = responseData.attributes.storage_building; - this.attributes.storageBuildingSqft = responseData.attributes.storage_buildling_sqft; - this.attributes.storiesNumber = responseData.attributes.stories_number; - this.attributes.stormShelter = responseData.attributes.storm_shelter; - this.attributes.stormShutter = responseData.attributes.storm_shutter; - this.attributes.structureStyle = responseData.attributes.structure_style; - this.attributes.study = responseData.attributes.study; - this.attributes.subdivision = responseData.attributes.subdivision; - this.attributes.suffix = responseData.attributes.suffix; - this.attributes.suffix2 = responseData.attributes.suffix_2; - this.attributes.suffix3 = responseData.attributes.suffix_3; - this.attributes.suffix4 = responseData.attributes.suffix_4; - this.attributes.sunroom = responseData.attributes.sunroom; - this.attributes.taxAssessYear = responseData.attributes.tax_assess_year; - this.attributes.taxBilledAmount = responseData.attributes.tax_billed_amount; - this.attributes.taxDelinquentYear = responseData.attributes.tax_delinquent_year; - this.attributes.taxFiscalYear = responseData.attributes.tax_fiscal_year; - this.attributes.taxJurisdiction = responseData.attributes.tax_jurisdiction; - this.attributes.taxRateArea = responseData.attributes.tax_rate_area; - this.attributes.tennisCourt = responseData.attributes.tennis_court; - this.attributes.topographyCode = responseData.attributes.topography_code; - this.attributes.totalMarketValue = responseData.attributes.total_market_value; - this.attributes.township = responseData.attributes.township; - this.attributes.tractNumber = responseData.attributes.tract_number; - this.attributes.transferAmount = responseData.attributes.transfer_amount; - this.attributes.trustDescription = responseData.attributes.trust_description; - this.attributes.unitCount = responseData.attributes.unit_count; - this.attributes.upperFloorsSqft = responseData.attributes.upper_floors_sqft; - this.attributes.utility = responseData.attributes.utility; - this.attributes.utilityBuilding = responseData.attributes.utility_building; - this.attributes.utilityBuildingSqft = responseData.attributes.utility_building_sqft; - this.attributes.utilitySqft = responseData.attributes.utility_sqft; - this.attributes.veteranTaxExemption = responseData.attributes.veteran_tax_exemption; - this.attributes.viewDescription = responseData.attributes.view_description; - this.attributes.waterFeature = responseData.attributes.water_feature; - this.attributes.waterServiceType = responseData.attributes.water_service_type; - this.attributes.wetBar = responseData.attributes.wet_bar; - this.attributes.widowTaxExemption = responseData.attributes.widow_tax_exemption; - this.attributes.widthLinearFootage = responseData.attributes.width_linear_footage; - this.attributes.wineCellar = responseData.attributes.wine_cellar; - this.attributes.yearBuilt = responseData.attributes.year_built; - this.attributes.zoning = responseData.attributes.zoning; - } - } + this.attributes = {}; + if (responseData.attributes) { + this.attributes.firstFloorSqft = responseData.attributes["1st_floor_sqft"]; + this.attributes.secondFlootSqft = responseData.attributes["2nd_floor_sqft"]; + this.attributes.acres = responseData.attributes.acres; + this.attributes.addressInfoPrivacy = responseData.attributes.address_info_privacy; + this.attributes.airConditioner = responseData.attributes.air_conditioner; + this.attributes.arborPergola = responseData.attributes.arbor_pergola; + this.attributes.assessedImprovementPercent = + responseData.attributes.assessed_improvement_percent; + this.attributes.assessedImprovementValue = responseData.attributes.assessed_improvement_value; + this.attributes.assessedLandValue = responseData.attributes.assessed_land_value; + this.attributes.assessedValue = responseData.attributes.assessed_value; + this.attributes.assessorLastUpdate = responseData.attributes.assessor_last_update; + this.attributes.assessorTaxrollUpdate = responseData.attributes.assessor_taxroll_update; + this.attributes.atticArea = responseData.attributes.attic_area; + this.attributes.atticFlag = responseData.attributes.attic_flag; + this.attributes.balcony = responseData.attributes.balcony; + this.attributes.balconyArea = responseData.attributes.balcony_area; + this.attributes.basementSqft = responseData.attributes.basement_sqft; + this.attributes.basementSqftFinished = responseData.attributes.basement_sqft_finished; + this.attributes.basementsqftUnfinished = responseData.attributes.basement_sqft_unfinished; + this.attributes.bathHouse = responseData.attributes.bath_house; + this.attributes.bathHouseSqft = responseData.attributes.bath_house_sqft; + this.attributes.bathroomsPartial = responseData.attributes.bathrooms_partial; + this.attributes.bathroomsTotal = responseData.attributes.bathrooms_total; + this.attributes.bedrooms = responseData.attributes.bedrooms; + this.attributes.block1 = responseData.attributes.block_1; + this.attributes.block2 = responseData.attributes.block_2; + this.attributes.boatAccess = responseData.attributes.boat_access; + this.attributes.boatHouse = responseData.attributes.boat_house; + this.attributes.boatHouseSqft = responseData.attributes.boat_house_sqft; + this.attributes.boatLift = responseData.attributes.boat_lift; + this.attributes.bonusRoom = responseData.attributes.bonus_room; + this.attributes.breakfastNook = responseData.attributes.breakfast_nook; + this.attributes.breezeway = responseData.attributes.breezeway; + this.attributes.buildingDefinitionCode = responseData.attributes.building_definition; + this.attributes.buildingSqft = responseData.attributes.building_sqft; + this.attributes.cabin = responseData.attributes.cabin; + this.attributes.cabinSqft = responseData.attributes.cabin_sqft; + this.attributes.canopy = responseData.attributes.canopy; + this.attributes.canopySqft = responseData.attributes.canopy_sqft; + this.attributes.carport = responseData.attributes.carport; + this.attributes.carportSqft = responseData.attributes.carport_sqft; + this.attributes.cbsaCode = responseData.attributes.cbsa_code; + this.attributes.cbsaName = responseData.attributes.cbsa_name; + this.attributes.cellar = responseData.attributes.cellar; + this.attributes.censusBlock = responseData.attributes.census_block; + this.attributes.censusTract = responseData.attributes.census_tract; + this.attributes.censusBlockGroup = responseData.attributes.census_block_group; + this.attributes.censusFipsPlaceCode = responseData.attributes.census_fips_place_code; + this.attributes.censusTract = responseData.attributes.census_tract; + this.attributes.centralVacuum = responseData.attributes.central_vacuum; + this.attributes.codeTitleCompany = responseData.attributes.code_title_company; + this.attributes.combinedStatisticalArea = responseData.attributes.combined_statistical_area; + this.attributes.communityRec = responseData.attributes.community_rec; + this.attributes.companyFlag = responseData.attributes.company_flag; + this.attributes.congressionalDistrict = responseData.attributes.congressional_district; + this.attributes.constructionType = responseData.attributes.construction_type; + this.attributes.contactCity = responseData.attributes.contact_city; + this.attributes.contactCrrt = responseData.attributes.contact_crrt; + this.attributes.contactFullAddress = responseData.attributes.contact_full_address; + this.attributes.contactHouseNumber = responseData.attributes.contact_house_number; + this.attributes.contactMailInfoFormat = responseData.attributes.contact_main_info_format; + this.attributes.contactMailInfoPrivacy = responseData.attributes.contact_mail_info_privacy; + this.attributes.contactMailingCounty = responseData.attributes.contact_mailing_county; + this.attributes.contactMailingFips = responseData.attributes.contact_mailing_fips; + this.attributes.contactPostDirection = responseData.attributes.contact_post_direction; + this.attributes.contactPreDirection = responseData.attributes.contact_pre_direction; + this.attributes.contactState = responseData.attributes.contact_state; + this.attributes.contactStreetName = responseData.attributes.contact_street_name; + this.attributes.contactSuffix = responseData.attributes.contact_suffix; + this.attributes.contactUnitDesignator = responseData.attributes.contact_unit_designator; + this.attributes.contactValue = responseData.attributes.contact_value; + this.attributes.contactZip = responseData.attributes.contact_zip; + this.attributes.contactZip4 = responseData.attributes.contact_zip4; + this.attributes.courtyard = responseData.attributes.courtyard; + this.attributes.courtyardArea = responseData.attributes.courtyard_area; + this.attributes.deck = responseData.attributes.deck; + this.attributes.deckArea = responseData.attributes.deck_area; + this.attributes.deedDocumentPage = responseData.attributes.deed_document_page; + this.attributes.deedDocumentBook = responseData.attributes.deed_document_book; + this.attributes.deedDocumentNumber = responseData.attributes.deed_document_number; + this.attributes.deedOwnerFirstName = responseData.attributes.deed_owner_first_name; + this.attributes.deedOwnerFirstName2 = responseData.attributes.deed_owner_first_name2; + this.attributes.deedOwnerFirstName3 = responseData.attributes.deed_owner_first_name3; + this.attributes.deedOwnerFirstName4 = responseData.attributes.deed_owner_first_name4; + this.attributes.deedOwnerFullName = responseData.attributes.deed_owner_full_name; + this.attributes.deedOwnerFullName2 = responseData.attributes.deed_owner_full_name2; + this.attributes.deedOwnerFullName3 = responseData.attributes.deed_owner_full_name3; + this.attributes.deedOwnerFullName4 = responseData.attributes.deed_owner_full_name4; + this.attributes.deedOwnerLastName = responseData.attributes.deed_owner_last_name; + this.attributes.deedOwnerLastName2 = responseData.attributes.deed_owner_last_name2; + this.attributes.deedOwnerLastName3 = responseData.attributes.deed_owner_last_name3; + this.attributes.deedOwnerLastName4 = responseData.attributes.deed_owner_last_name4; + this.attributes.deedOwnerMiddleName = responseData.attributes.deed_owner_middle_name; + this.attributes.deedOwnerMiddleName2 = responseData.attributes.deed_owner_middle_name2; + this.attributes.deedOwnerMiddleName3 = responseData.attributes.deed_owner_middle_name3; + this.attributes.deedOwnerMiddleName4 = responseData.attributes.deed_owner_middle_name4; + this.attributes.deedOwnerSuffix = responseData.attributes.deed_owner_suffix; + this.attributes.deedOwnerSuffix2 = responseData.attributes.deed_owner_suffix2; + this.attributes.deedOwnerSuffix3 = responseData.attributes.deed_owner_suffix3; + this.attributes.deedOwnerSuffix4 = responseData.attributes.deed_owner_suffix4; + this.attributes.deedSaleDate = responseData.attributes.deed_sale_date; + this.attributes.deedSalePrice = responseData.attributes.deed_sale_price; + this.attributes.deedTransactionId = responseData.attributes.deed_transaction_id; + this.attributes.depthLinearFootage = responseData.attributes.depth_linear_footage; + this.attributes.disabledTaxExemption = responseData.attributes.disabled_tax_exemption; + this.attributes.drivewaySqft = responseData.attributes.driveway_sqft; + this.attributes.drivewayType = responseData.attributes.driveway_type; + this.attributes.effectiveYearBuilt = responseData.attributes.effective_year_built; + this.attributes.elevationFeet = responseData.attributes.elevation_feet; + this.attributes.elevator = responseData.attributes.elevator; + this.attributes.equestrianArena = responseData.attributes.equestrian_arena; + this.attributes.escalator = responseData.attributes.escalator; + this.attributes.exerciseRoom = responseData.attributes.exercise_room; + this.attributes.exteriorWalls = responseData.attributes.exterior_walls; + this.attributes.familyRoom = responseData.attributes.family_room; + this.attributes.financialHistory = !responseData.attributes.financial_history + ? [] + : responseData.attributes.financial_history.map((history) => { + return { + codeTitleCompany: history.code_title_company, + instrumentDate: history.instrument_date, + interestRateType2: history.interest_rate_type_2, + lenderAddress: history.lender_address, + lenderAddress2: history.lender_address_2, + lenderCity: history.lender_city, + lenderCity2: history.lender_city_2, + lenderCode: history.lender_code, + lenderCode2: history.lender_code_2, + lenderFirstName: history.lender_first_name, + lenderFirstName2: history.lender_first_name_2, + lenderLastName: history.lender_last_name, + lenderLastName2: history.lender_last_name_2, + lenderName: history.lender_name, + lenderName2: history.lender_name_2, + lenderSellerCarryBack: history.lender_seller_carry_back, + lenderSellerCarryBack2: history.lender_seller_carry_back_2, + lenderState: history.lender_state, + lenderState2: history.lender_state_2, + lenderZip: history.lender_zip, + lenderZip2: history.lender_zip_2, + lenderZipExtended: history.lender_zip_extended, + lenderZipExtended2: history.lender_zip_extended_2, + mortgageAmount: history.mortgage_amount, + mortgageAmount2: history.mortgage_amount_2, + mortgageDueDate: history.mortgage_due_date, + mortgageDueDate2: history.mortgage_due_date_2, + mortgageInterestRate: history.mortgage_interest_rate, + mortgageInterestRateType: history.mortgage_interest_rate_type, + mortgageLenderCode: history.mortgage_lender_code, + mortgageRate: history.mortgage_rate, + mortgageRate2: history.mortgage_rate_2, + mortgageRecordingDate: history.mortgage_recording_date, + mortgageRecordingDate2: history.mortgage_recording_date_2, + mortgageTerm: history.mortgage_term, + mortgageTerm2: history.mortgage_term_2, + mortgageTermType: history.mortgage_term_type, + mortgageTermType2: history.mortgage_term_type_2, + mortgageType: history.mortgage_type, + mortgageType2: history.mortgage_type_2, + multiParcelFlag: history.multi_parcel_flag, + nameTitleCompany: history.name_title_company, + recordingDate: history.recording_date, + transferAmount: history.transfer_amount, + }; + }); + this.attributes.fence = responseData.attributes.fence; + this.attributes.fenceArea = responseData.attributes.fence_area; + this.attributes.fipsCode = responseData.attributes.fips_code; + this.attributes.fireResistanceCode = responseData.attributes.fire_resistance_code; + this.attributes.fireSprinklersFlag = responseData.attributes.fire_sprinkler_flag; + this.attributes.fireplace = responseData.attributes.fireplace; + this.attributes.fireplaceNumber = responseData.attributes.fireplace_number; + this.attributes.firstName = responseData.attributes.first_name; + this.attributes.firstName2 = responseData.attributes.first_name2; + this.attributes.firstName3 = responseData.attributes.first_name3; + this.attributes.firstName4 = responseData.attributes.first_name4; + this.attributes.flooring = responseData.attributes.flooring; + this.attributes.foundation = responseData.attributes.foundation; + this.attributes.gameRoom = responseData.attributes.game_room; + this.attributes.garage = responseData.attributes.garage; + this.attributes.garageSqft = responseData.attributes.garage_sqft; + this.attributes.gazebo = responseData.attributes.gazebo; + this.attributes.gazeboSqft = responseData.attributes.gazebo_sqft; + this.attributes.golfCourse = responseData.attributes.golf_course; + this.attributes.grainery = responseData.attributes.grainery; + this.attributes.grainerySqft = responseData.attributes.grainery_sqft; + this.attributes.greatRoom = responseData.attributes.great_room; + this.attributes.greenhouse = responseData.attributes.greenhouse; + this.attributes.greenhouseSqft = responseData.attributes.greenhouse_sqft; + this.attributes.grossSqft = responseData.attributes.gross_sqft; + this.attributes.guesthouse = responseData.attributes.guesthouse; + this.attributes.guesthouseSqft = responseData.attributes.guesthouse_sqft; + this.attributes.handicapAccessibility = responseData.attributes.handicap_accessibility; + this.attributes.heat = responseData.attributes.heat; + this.attributes.heatFuelType = responseData.attributes.heat_fuel_type; + this.attributes.hobbyRoom = responseData.attributes.hobby_room; + this.attributes.homeownerTaxExemption = responseData.attributes.homeowner_tax_exemption; + this.attributes.instrumentDate = responseData.attributes.instrument_date; + this.attributes.intercomSystem = responseData.attributes.intercom_system; + this.attributes.interestRateType2 = responseData.attributes.interest_rate_type_2; + this.attributes.interiorStructure = responseData.attributes.interior_structure; + this.attributes.kennel = responseData.attributes.kennel; + this.attributes.kennelSqft = responseData.attributes.kennel_sqft; + this.attributes.landUseCode = responseData.attributes.land_use_code; + this.attributes.landUseGroup = responseData.attributes.land_use_group; + this.attributes.landUseStandard = responseData.attributes.land_use_standard; + this.attributes.lastName = responseData.attributes.last_name; + this.attributes.lastName2 = responseData.attributes.last_name_2; + this.attributes.lastName3 = responseData.attributes.last_name_3; + this.attributes.lastName4 = responseData.attributes.last_name_4; + this.attributes.latitude = responseData.attributes.latitude; + this.attributes.laundry = responseData.attributes.laundry; + this.attributes.leanTo = responseData.attributes.lean_to; + this.attributes.leanToSqft = responseData.attributes.lean_to_sqft; + this.attributes.legalDescription = responseData.attributes.legal_description; + this.attributes.legalUnit = responseData.attributes.legal_unit; + this.attributes.lenderAddress = responseData.attributes.lender_address; + this.attributes.lenderAddress2 = responseData.attributes.lender_address_2; + this.attributes.lenderCity = responseData.attributes.lender_city; + this.attributes.lenderCity2 = responseData.attributes.lender_city_2; + this.attributes.lenderCode = responseData.attributes.lender_code; + this.attributes.lenderCode2 = responseData.attributes.lender_code_2; + this.attributes.lenderFirstName = responseData.attributes.lender_first_name; + this.attributes.lenderFirstName2 = responseData.attributes.lender_first_name_2; + this.attributes.lenderLastName = responseData.attributes.lender_last_name; + this.attributes.lenderLastName2 = responseData.attributes.lender_last_name_2; + this.attributes.lenderName = responseData.attributes.lender_name; + this.attributes.lenderName2 = responseData.attributes.lender_name_2; + this.attributes.lenderSellerCarryBack = responseData.attributes.lender_seller_carry_back; + this.attributes.lenderSellerCarryBack2 = responseData.attributes.lender_seller_carry_back_2; + this.attributes.lenderState = responseData.attributes.lender_state; + this.attributes.lenderState2 = responseData.attributes.lender_state_2; + this.attributes.lenderZip = responseData.attributes.lender_zip; + this.attributes.lenderZip2 = responseData.attributes.lender_zip_2; + this.attributes.lenderZipExtended = responseData.attributes.lender_zip_extended; + this.attributes.lenderZipExtended2 = responseData.attributes.lender_zip_extended_2; + this.attributes.loadingPlatform = responseData.attributes.loading_platform; + this.attributes.loadingPlatformSqft = responseData.attributes.loading_platform_sqft; + this.attributes.longitude = responseData.attributes.longitude; + this.attributes.lot1 = responseData.attributes.lot_1; + this.attributes.lot2 = responseData.attributes.lot_2; + this.attributes.lot3 = responseData.attributes.lot_3; + this.attributes.lotSqft = responseData.attributes.lot_sqft; + this.attributes.marketImprovementPercent = responseData.attributes.market_improvement_percent; + this.attributes.marketImprovementValue = responseData.attributes.market_improvement_value; + this.attributes.marketLandValue = responseData.attributes.market_land_value; + this.attributes.marketValueYear = responseData.attributes.market_value_year; + this.attributes.matchType = responseData.attributes.match_type; + this.attributes.mediaRoom = responseData.attributes.media_room; + this.attributes.metroDivision = responseData.attributes.metro_division; + this.attributes.middleName = responseData.attributes.middle_name; + this.attributes.middleName2 = responseData.attributes.middle_name_2; + this.attributes.middleName3 = responseData.attributes.middle_name_3; + this.attributes.middleName4 = responseData.attributes.middle_name_4; + this.attributes.milkhouse = responseData.attributes.milkhouse; + this.attributes.milkhouseSqft = responseData.attributes.milkhouse_sqft; + this.attributes.minorCivilDivisionCode = responseData.attributes.minor_civil_division_code; + this.attributes.minorCivilDivisionName = responseData.attributes.minor_civil_division_name; + this.attributes.mobileHomeHookup = responseData.attributes.mobile_home_hookup; + this.attributes.mortgageAmount = responseData.attributes.mortgage_amount; + this.attributes.mortgageAmount2 = responseData.attributes.mortgage_amount_2; + this.attributes.mortgageDueDate = responseData.attributes.mortgage_due_date; + this.attributes.mortgageDueDate2 = responseData.attributes.mortgage_due_date_2; + this.attributes.mortgageInterestRate = responseData.attributes.mortgage_interest_rate; + this.attributes.mortgageInterestRateType = + responseData.attributes.mortgage_interest_rate_type; + this.attributes.mortgageLenderCode = responseData.attributes.mortgage_lender_code; + this.attributes.mortgageRate2 = responseData.attributes.mortgage_rate_2; + this.attributes.mortgageRecordingDate = responseData.attributes.mortgage_recording_date; + this.attributes.mortgageRecordingDate2 = responseData.attributes.mortgage_recording_date_2; + this.attributes.mortgageTerm = responseData.attributes.mortgage_term; + this.attributes.mortgageTerm2 = responseData.attributes.mortgage_term_2; + this.attributes.mortgageTermType = responseData.attributes.mortgage_term_type; + this.attributes.mortgageTermType2 = responseData.attributes.mortgage_term_type_2; + this.attributes.mortgageType = responseData.attributes.mortgage_type; + this.attributes.mortgageType2 = responseData.attributes.mortgage_type_2; + this.attributes.msaCode = responseData.attributes.msa_code; + this.attributes.msaName = responseData.attributes.msa_name; + this.attributes.mudRoom = responseData.attributes.mud_room; + this.attributes.multiParcelFlag = responseData.attributes.multi_parcel_flag; + this.attributes.nameTitleCompany = responseData.attributes.name_title_company; + this.attributes.neighborhoodCode = responseData.attributes.neighborhood_code; + this.attributes.numberOfBuildings = responseData.attributes.number_of_buildings; + this.attributes.office = responseData.attributes.office; + this.attributes.officeSqft = responseData.attributes.office_sqft; + this.attributes.otherTaxExemption = responseData.attributes.other_tax_exemption; + this.attributes.outdoorKitchenFireplace = responseData.attributes.outdoor_kitchen_fireplace; + this.attributes.overheadDoor = responseData.attributes.overhead_door; + this.attributes.ownerFullName = responseData.attributes.owner_full_name; + this.attributes.ownerFullName2 = responseData.attributes.owner_full_name_2; + this.attributes.ownerFullName3 = responseData.attributes.owner_full_name_3; + this.attributes.ownerFullName4 = responseData.attributes.owner_full_name_4; + this.attributes.ownerOccupancyStatus = responseData.attributes.owner_occupancy_status; + this.attributes.ownershipTransferDate = responseData.attributes.ownership_transfer_date; + this.attributes.ownershipTransferDocNumber = + responseData.attributes.ownership_transfer_doc_number; + this.attributes.ownershipTransferTransactionId = + responseData.attributes.ownership_transfer_transaction_id; + this.attributes.ownershipType = responseData.attributes.ownership_type; + this.attributes.ownershipType2 = responseData.attributes.ownership_type_2; + this.attributes.ownershipVestingRelationCode = + responseData.attributes.ownership_vesting_relation_code; + this.attributes.parcelAccountNumber = responseData.attributes.parcel_account_number; + this.attributes.parcelMapBook = responseData.attributes.parcel_map_book; + this.attributes.parcelMapPage = responseData.attributes.parcel_map_page; + this.attributes.parcelNumberAlternate = responseData.attributes.parcel_number_alternate; + this.attributes.parcelNumberFormatted = responseData.attributes.parcel_number_formatted; + this.attributes.parcelNumberPrevious = responseData.attributes.parcel_number_previous; + this.attributes.parcelNumberYearAdded = responseData.attributes.parcel_number_year_added; + this.attributes.parcelNumberYearChange = responseData.attributes.parcel_number_year_change; + this.attributes.parcelRawNumber = responseData.attributes.parcel_raw_number; + this.attributes.parcelShellRecord = responseData.attributes.parcel_shell_record; + this.attributes.parkingSpaces = responseData.attributes.parking_spaces; + this.attributes.patioArea = responseData.attributes.patio_area; + this.attributes.phaseName = responseData.attributes.phase_name; + this.attributes.plumbingFixturesCount = responseData.attributes.plumbing_fixtures_count; + this.attributes.poleStruct = responseData.attributes.pole_struct; + this.attributes.poleStructSqft = responseData.attributes.pole_struct_sqft; + this.attributes.pond = responseData.attributes.pond; + this.attributes.pool = responseData.attributes.pool; + this.attributes.poolArea = responseData.attributes.pool_area; + this.attributes.poolhouse = responseData.attributes.poolhouse; + this.attributes.poolhouseSqft = responseData.attributes.poolhouse_sqft; + this.attributes.porch = responseData.attributes.porch; + this.attributes.porchArea = responseData.attributes.porch_area; + this.attributes.poultryHouse = responseData.attributes.poultry_house; + this.attributes.poultryHouseSqft = responseData.attributes.poultry_house_sqft; + this.attributes.previousAssessedValue = responseData.attributes.previous_assessed_value; + this.attributes.priorSaleAmount = responseData.attributes.prior_sale_amount; + this.attributes.priorSaleDate = responseData.attributes.prior_sale_date; + this.attributes.propertyAddressCarrierRouteCode = + responseData.attributes.property_address_carrier_route_code; + this.attributes.propertyAddressCity = responseData.attributes.property_address_city; + this.attributes.propertyAddressFull = responseData.attributes.property_address_full; + this.attributes.propertyAddressHouseNumber = + responseData.attributes.property_address_house_number; + this.attributes.propertyAddressPostDirection = + responseData.attributes.property_address_post_direction; + this.attributes.propertyAddressPreDirection = + responseData.attributes.property_address_pre_direction; + this.attributes.propertyAddressState = responseData.attributes.property_address_state; + this.attributes.propertyAddressStreetName = + responseData.attributes.property_address_street_name; + this.attributes.propertyAddressStreetSuffix = + responseData.attributes.property_address_street_suffix; + this.attributes.propertyAddressUnitDesignator = + responseData.attributes.property_address_unit_designator; + this.attributes.propertyAddressUnitValue = + responseData.attributes.property_address_unit_value; + this.attributes.propertyAddressZip4 = responseData.attributes.property_address_zip_4; + this.attributes.propertyAddressZipcode = responseData.attributes.property_address_zipcode; + this.attributes.publicationDate = responseData.attributes.publication_date; + this.attributes.quarter = responseData.attributes.quarter; + this.attributes.quarterQuarter = responseData.attributes.quarter_quarter; + this.attributes.quonset = responseData.attributes.quonset; + this.attributes.quonsetSqft = responseData.attributes.quonset_sqft; + this.attributes.range = responseData.attributes.range; + this.attributes.recordingDate = responseData.attributes.recording_date; + this.attributes.roofCover = responseData.attributes.roof_cover; + this.attributes.roofFrame = responseData.attributes.roof_frame; + this.attributes.rooms = responseData.attributes.rooms; + this.attributes.rvParking = responseData.attributes.rv_parking; + this.attributes.safeRoom = responseData.attributes.safe_room; + this.attributes.saleAmount = responseData.attributes.sale_amount; + this.attributes.saleDate = responseData.attributes.sale_date; + this.attributes.sauna = responseData.attributes.sauna; + this.attributes.section = responseData.attributes.section; + this.attributes.securityAlarm = responseData.attributes.security_alarm; + this.attributes.seniorTaxExemption = responseData.attributes.senior_tax_exemption; + this.attributes.sewerType = responseData.attributes.sewer_type; + this.attributes.shed = responseData.attributes.shed; + this.attributes.shedSqft = responseData.attributes.shed_sqft; + this.attributes.silo = responseData.attributes.silo; + this.attributes.siloSqft = responseData.attributes.silo_sqft; + this.attributes.sittingRoom = responseData.attributes.sitting_room; + this.attributes.situsCounty = responseData.attributes.situs_county; + this.attributes.situsState = responseData.attributes.situs_state; + this.attributes.soundSystem = responseData.attributes.sound_system; + this.attributes.sportsCourt = responseData.attributes.sports_court; + this.attributes.sprinklers = responseData.attributes.sprinklers; + this.attributes.stable = responseData.attributes.stable; + this.attributes.stableSqft = responseData.attributes.stable_sqft; + this.attributes.storageBuilding = responseData.attributes.storage_building; + this.attributes.storageBuildingSqft = responseData.attributes.storage_buildling_sqft; + this.attributes.storiesNumber = responseData.attributes.stories_number; + this.attributes.stormShelter = responseData.attributes.storm_shelter; + this.attributes.stormShutter = responseData.attributes.storm_shutter; + this.attributes.structureStyle = responseData.attributes.structure_style; + this.attributes.study = responseData.attributes.study; + this.attributes.subdivision = responseData.attributes.subdivision; + this.attributes.suffix = responseData.attributes.suffix; + this.attributes.suffix2 = responseData.attributes.suffix_2; + this.attributes.suffix3 = responseData.attributes.suffix_3; + this.attributes.suffix4 = responseData.attributes.suffix_4; + this.attributes.sunroom = responseData.attributes.sunroom; + this.attributes.taxAssessYear = responseData.attributes.tax_assess_year; + this.attributes.taxBilledAmount = responseData.attributes.tax_billed_amount; + this.attributes.taxDelinquentYear = responseData.attributes.tax_delinquent_year; + this.attributes.taxFiscalYear = responseData.attributes.tax_fiscal_year; + this.attributes.taxJurisdiction = responseData.attributes.tax_jurisdiction; + this.attributes.taxRateArea = responseData.attributes.tax_rate_area; + this.attributes.tennisCourt = responseData.attributes.tennis_court; + this.attributes.topographyCode = responseData.attributes.topography_code; + this.attributes.totalMarketValue = responseData.attributes.total_market_value; + this.attributes.township = responseData.attributes.township; + this.attributes.tractNumber = responseData.attributes.tract_number; + this.attributes.transferAmount = responseData.attributes.transfer_amount; + this.attributes.trustDescription = responseData.attributes.trust_description; + this.attributes.unitCount = responseData.attributes.unit_count; + this.attributes.upperFloorsSqft = responseData.attributes.upper_floors_sqft; + this.attributes.utility = responseData.attributes.utility; + this.attributes.utilityBuilding = responseData.attributes.utility_building; + this.attributes.utilityBuildingSqft = responseData.attributes.utility_building_sqft; + this.attributes.utilitySqft = responseData.attributes.utility_sqft; + this.attributes.veteranTaxExemption = responseData.attributes.veteran_tax_exemption; + this.attributes.viewDescription = responseData.attributes.view_description; + this.attributes.waterFeature = responseData.attributes.water_feature; + this.attributes.waterServiceType = responseData.attributes.water_service_type; + this.attributes.wetBar = responseData.attributes.wet_bar; + this.attributes.widowTaxExemption = responseData.attributes.widow_tax_exemption; + this.attributes.widthLinearFootage = responseData.attributes.width_linear_footage; + this.attributes.wineCellar = responseData.attributes.wine_cellar; + this.attributes.yearBuilt = responseData.attributes.year_built; + this.attributes.zoning = responseData.attributes.zoning; + } + } } class FinancialResponse { - constructor(responseData) { - this.smartyKey = responseData.smarty_key; - this.dataSetName = responseData.data_set_name; - this.dataSubsetName = responseData.data_subset_name; + constructor(responseData) { + this.smartyKey = responseData.smarty_key; + this.dataSetName = responseData.data_set_name; + this.dataSubsetName = responseData.data_subset_name; - this.attributes = {}; - if (responseData.attributes) { - this.attributes.assessedImprovementPercent = responseData.attributes.assessed_improvement_percent; - this.attributes.assessedImprovementValue = responseData.attributes.assessed_improvement_value; - this.attributes.assessedLandValue = responseData.attributes.assessed_land_value; - this.attributes.assessedValue = responseData.attributes.assessed_value; - this.attributes.assessorLastUpdate = responseData.attributes.assessor_last_update; - this.attributes.assessorTaxrollUpdate = responseData.attributes.assessor_taxroll_update; - this.attributes.contactCity = responseData.attributes.contact_city; - this.attributes.contactCrrt = responseData.attributes.contact_crrt; - this.attributes.contactFullAddress = responseData.attributes.contact_full_address; - this.attributes.contactHouseNumber = responseData.attributes.contact_house_number; - this.attributes.contactMailInfoFormat = responseData.attributes.contact_main_info_format; - this.attributes.contactMailInfoPrivacy = responseData.attributes.contact_mail_info_privacy; - this.attributes.contactMailingCounty = responseData.attributes.contact_mailing_county; - this.attributes.contactMailingFips = responseData.attributes.contact_mailing_fips; - this.attributes.contactPostDirection = responseData.attributes.contact_post_direction; - this.attributes.contactPreDirection = responseData.attributes.contact_pre_direction; - this.attributes.contactState = responseData.attributes.contact_state; - this.attributes.contactStreetName = responseData.attributes.contact_street_name; - this.attributes.contactSuffix = responseData.attributes.contact_suffix; - this.attributes.contactUnitDesignator = responseData.attributes.contact_unit_designator; - this.attributes.contactValue = responseData.attributes.contact_value; - this.attributes.contactZip = responseData.attributes.contact_zip; - this.attributes.contactZip4 = responseData.attributes.contact_zip4; - this.attributes.deedDocumentPage = responseData.attributes.deed_document_page; - this.attributes.deedDocumentBook = responseData.attributes.deed_document_book; - this.attributes.deedDocumentNumber = responseData.attributes.deed_document_number; - this.attributes.deedOwnerFirstName = responseData.attributes.deed_owner_first_name; - this.attributes.deedOwnerFirstName2 = responseData.attributes.deed_owner_first_name2; - this.attributes.deedOwnerFirstName3 = responseData.attributes.deed_owner_first_name3; - this.attributes.deedOwnerFirstName4 = responseData.attributes.deed_owner_first_name4; - this.attributes.deedOwnerFullName = responseData.attributes.deed_owner_full_name; - this.attributes.deedOwnerFullName2 = responseData.attributes.deed_owner_full_name2; - this.attributes.deedOwnerFullName3 = responseData.attributes.deed_owner_full_name3; - this.attributes.deedOwnerFullName4 = responseData.attributes.deed_owner_full_name4; - this.attributes.deedOwnerLastName = responseData.attributes.deed_owner_last_name; - this.attributes.deedOwnerLastName2 = responseData.attributes.deed_owner_last_name2; - this.attributes.deedOwnerLastName3 = responseData.attributes.deed_owner_last_name3; - this.attributes.deedOwnerLastName4 = responseData.attributes.deed_owner_last_name4; - this.attributes.deedOwnerMiddleName = responseData.attributes.deed_owner_middle_name; - this.attributes.deedOwnerMiddleName2 = responseData.attributes.deed_owner_middle_name2; - this.attributes.deedOwnerMiddleName3 = responseData.attributes.deed_owner_middle_name3; - this.attributes.deedOwnerMiddleName4 = responseData.attributes.deed_owner_middle_name4; - this.attributes.deedOwnerSuffix = responseData.attributes.deed_owner_suffix; - this.attributes.deedOwnerSuffix2 = responseData.attributes.deed_owner_suffix2; - this.attributes.deedOwnerSuffix3 = responseData.attributes.deed_owner_suffix3; - this.attributes.deedOwnerSuffix4 = responseData.attributes.deed_owner_suffix4; - this.attributes.deedSaleDate = responseData.attributes.deed_sale_date; - this.attributes.deedSalePrice = responseData.attributes.deed_sale_price; - this.attributes.deedTransactionId = responseData.attributes.deed_transaction_id; - this.attributes.disabledTaxExemption = responseData.attributes.disabled_tax_exemption; + this.attributes = {}; + if (responseData.attributes) { + this.attributes.assessedImprovementPercent = + responseData.attributes.assessed_improvement_percent; + this.attributes.assessedImprovementValue = responseData.attributes.assessed_improvement_value; + this.attributes.assessedLandValue = responseData.attributes.assessed_land_value; + this.attributes.assessedValue = responseData.attributes.assessed_value; + this.attributes.assessorLastUpdate = responseData.attributes.assessor_last_update; + this.attributes.assessorTaxrollUpdate = responseData.attributes.assessor_taxroll_update; + this.attributes.contactCity = responseData.attributes.contact_city; + this.attributes.contactCrrt = responseData.attributes.contact_crrt; + this.attributes.contactFullAddress = responseData.attributes.contact_full_address; + this.attributes.contactHouseNumber = responseData.attributes.contact_house_number; + this.attributes.contactMailInfoFormat = responseData.attributes.contact_main_info_format; + this.attributes.contactMailInfoPrivacy = responseData.attributes.contact_mail_info_privacy; + this.attributes.contactMailingCounty = responseData.attributes.contact_mailing_county; + this.attributes.contactMailingFips = responseData.attributes.contact_mailing_fips; + this.attributes.contactPostDirection = responseData.attributes.contact_post_direction; + this.attributes.contactPreDirection = responseData.attributes.contact_pre_direction; + this.attributes.contactState = responseData.attributes.contact_state; + this.attributes.contactStreetName = responseData.attributes.contact_street_name; + this.attributes.contactSuffix = responseData.attributes.contact_suffix; + this.attributes.contactUnitDesignator = responseData.attributes.contact_unit_designator; + this.attributes.contactValue = responseData.attributes.contact_value; + this.attributes.contactZip = responseData.attributes.contact_zip; + this.attributes.contactZip4 = responseData.attributes.contact_zip4; + this.attributes.deedDocumentPage = responseData.attributes.deed_document_page; + this.attributes.deedDocumentBook = responseData.attributes.deed_document_book; + this.attributes.deedDocumentNumber = responseData.attributes.deed_document_number; + this.attributes.deedOwnerFirstName = responseData.attributes.deed_owner_first_name; + this.attributes.deedOwnerFirstName2 = responseData.attributes.deed_owner_first_name2; + this.attributes.deedOwnerFirstName3 = responseData.attributes.deed_owner_first_name3; + this.attributes.deedOwnerFirstName4 = responseData.attributes.deed_owner_first_name4; + this.attributes.deedOwnerFullName = responseData.attributes.deed_owner_full_name; + this.attributes.deedOwnerFullName2 = responseData.attributes.deed_owner_full_name2; + this.attributes.deedOwnerFullName3 = responseData.attributes.deed_owner_full_name3; + this.attributes.deedOwnerFullName4 = responseData.attributes.deed_owner_full_name4; + this.attributes.deedOwnerLastName = responseData.attributes.deed_owner_last_name; + this.attributes.deedOwnerLastName2 = responseData.attributes.deed_owner_last_name2; + this.attributes.deedOwnerLastName3 = responseData.attributes.deed_owner_last_name3; + this.attributes.deedOwnerLastName4 = responseData.attributes.deed_owner_last_name4; + this.attributes.deedOwnerMiddleName = responseData.attributes.deed_owner_middle_name; + this.attributes.deedOwnerMiddleName2 = responseData.attributes.deed_owner_middle_name2; + this.attributes.deedOwnerMiddleName3 = responseData.attributes.deed_owner_middle_name3; + this.attributes.deedOwnerMiddleName4 = responseData.attributes.deed_owner_middle_name4; + this.attributes.deedOwnerSuffix = responseData.attributes.deed_owner_suffix; + this.attributes.deedOwnerSuffix2 = responseData.attributes.deed_owner_suffix2; + this.attributes.deedOwnerSuffix3 = responseData.attributes.deed_owner_suffix3; + this.attributes.deedOwnerSuffix4 = responseData.attributes.deed_owner_suffix4; + this.attributes.deedSaleDate = responseData.attributes.deed_sale_date; + this.attributes.deedSalePrice = responseData.attributes.deed_sale_price; + this.attributes.deedTransactionId = responseData.attributes.deed_transaction_id; + this.attributes.disabledTaxExemption = responseData.attributes.disabled_tax_exemption; - this.attributes.financialHistory = !responseData.attributes.financial_history ? [] : responseData.attributes.financial_history.map(history => { - return { - codeTitleCompany: history.code_title_company, - instrumentDate: history.instrument_date, - interestRateType2: history.interest_rate_type_2, - lenderAddress: history.lender_address, - lenderAddress2: history.lender_address_2, - lenderCity: history.lender_city, - lenderCity2: history.lender_city_2, - lenderCode: history.lender_code, - lenderCode2: history.lender_code_2, - lenderFirstName: history.lender_first_name, - lenderFirstName2: history.lender_first_name_2, - lenderLastName: history.lender_last_name, - lenderLastName2: history.lender_last_name_2, - lenderName: history.lender_name, - lenderName2: history.lender_name_2, - lenderSellerCarryBack: history.lender_seller_carry_back, - lenderSellerCarryBack2: history.lender_seller_carry_back_2, - lenderState: history.lender_state, - lenderState2: history.lender_state_2, - lenderZip: history.lender_zip, - lenderZip2: history.lender_zip_2, - lenderZipExtended: history.lender_zip_extended, - lenderZipExtended2: history.lender_zip_extended_2, - mortgageAmount: history.mortgage_amount, - mortgageAmount2: history.mortgage_amount_2, - mortgageDueDate: history.mortgage_due_date, - mortgageDueDate2: history.mortgage_due_date_2, - mortgageInterestRate: history.mortgage_interest_rate, - mortgageInterestRateType: history.mortgage_interest_rate_type, - mortgageLenderCode: history.mortgage_lender_code, - mortgageRate: history.mortgage_rate, - mortgageRate2: history.mortgage_rate_2, - mortgageRecordingDate: history.mortgage_recording_date, - mortgageRecordingDate2: history.mortgage_recording_date_2, - mortgageTerm: history.mortgage_term, - mortgageTerm2: history.mortgage_term_2, - mortgageTermType: history.mortgage_term_type, - mortgageTermType2: history.mortgage_term_type_2, - mortgageType: history.mortgage_type, - mortgageType2: history.mortgage_type_2, - multiParcelFlag: history.multi_parcel_flag, - nameTitleCompany: history.name_title_company, - recordingDate: history.recording_date, - transferAmount: history.transfer_amount, - } - }) - this.attributes.homeownerTaxExemption = responseData.attributes.homeowner_tax_exemption; - this.attributes.marketImprovementPercent = responseData.attributes.market_improvement_percent; - this.attributes.marketImprovementValue = responseData.attributes.market_improvement_value; - this.attributes.marketLandValue = responseData.attributes.market_land_value; - this.attributes.marketValueYear = responseData.attributes.market_value_year; - this.attributes.matchType = responseData.attributes.match_type; - this.attributes.otherTaxExemption = responseData.attributes.other_tax_exemption; - this.attributes.ownershipTransferDate = responseData.attributes.ownership_transfer_date; - this.attributes.ownershipTransferDocNumber = responseData.attributes.ownership_transfer_doc_number; - this.attributes.ownershipTransferTransactionId = responseData.attributes.ownership_transfer_transaction_id; - this.attributes.ownershipType = responseData.attributes.ownership_type; - this.attributes.ownershipType2 = responseData.attributes.ownership_type_2; - this.attributes.previousAssessedValue = responseData.attributes.previous_assessed_value; - this.attributes.priorSaleAmount = responseData.attributes.prior_sale_amount; - this.attributes.priorSaleDate = responseData.attributes.prior_sale_date; - this.attributes.saleAmount = responseData.attributes.sale_amount; - this.attributes.saleDate = responseData.attributes.sale_date; - this.attributes.seniorTaxExemption = responseData.attributes.senior_tax_exemption; - this.attributes.taxAssessYear = responseData.attributes.tax_assess_year; - this.attributes.taxBilledAmount = responseData.attributes.tax_billed_amount; - this.attributes.taxDelinquentYear = responseData.attributes.tax_delinquent_year; - this.attributes.taxFiscalYear = responseData.attributes.tax_fiscal_year; - this.attributes.taxRateArea = responseData.attributes.tax_rate_area; - this.attributes.totalMarketValue = responseData.attributes.total_market_value; - this.attributes.trustDescription = responseData.attributes.trust_description; - this.attributes.veteranTaxExemption = responseData.attributes.veteran_tax_exemption; - this.attributes.widow_tax_exemption = responseData.attributes.widow_tax_exemption; - } - } + this.attributes.financialHistory = !responseData.attributes.financial_history + ? [] + : responseData.attributes.financial_history.map((history) => { + return { + codeTitleCompany: history.code_title_company, + instrumentDate: history.instrument_date, + interestRateType2: history.interest_rate_type_2, + lenderAddress: history.lender_address, + lenderAddress2: history.lender_address_2, + lenderCity: history.lender_city, + lenderCity2: history.lender_city_2, + lenderCode: history.lender_code, + lenderCode2: history.lender_code_2, + lenderFirstName: history.lender_first_name, + lenderFirstName2: history.lender_first_name_2, + lenderLastName: history.lender_last_name, + lenderLastName2: history.lender_last_name_2, + lenderName: history.lender_name, + lenderName2: history.lender_name_2, + lenderSellerCarryBack: history.lender_seller_carry_back, + lenderSellerCarryBack2: history.lender_seller_carry_back_2, + lenderState: history.lender_state, + lenderState2: history.lender_state_2, + lenderZip: history.lender_zip, + lenderZip2: history.lender_zip_2, + lenderZipExtended: history.lender_zip_extended, + lenderZipExtended2: history.lender_zip_extended_2, + mortgageAmount: history.mortgage_amount, + mortgageAmount2: history.mortgage_amount_2, + mortgageDueDate: history.mortgage_due_date, + mortgageDueDate2: history.mortgage_due_date_2, + mortgageInterestRate: history.mortgage_interest_rate, + mortgageInterestRateType: history.mortgage_interest_rate_type, + mortgageLenderCode: history.mortgage_lender_code, + mortgageRate: history.mortgage_rate, + mortgageRate2: history.mortgage_rate_2, + mortgageRecordingDate: history.mortgage_recording_date, + mortgageRecordingDate2: history.mortgage_recording_date_2, + mortgageTerm: history.mortgage_term, + mortgageTerm2: history.mortgage_term_2, + mortgageTermType: history.mortgage_term_type, + mortgageTermType2: history.mortgage_term_type_2, + mortgageType: history.mortgage_type, + mortgageType2: history.mortgage_type_2, + multiParcelFlag: history.multi_parcel_flag, + nameTitleCompany: history.name_title_company, + recordingDate: history.recording_date, + transferAmount: history.transfer_amount, + }; + }); + this.attributes.homeownerTaxExemption = responseData.attributes.homeowner_tax_exemption; + this.attributes.marketImprovementPercent = responseData.attributes.market_improvement_percent; + this.attributes.marketImprovementValue = responseData.attributes.market_improvement_value; + this.attributes.marketLandValue = responseData.attributes.market_land_value; + this.attributes.marketValueYear = responseData.attributes.market_value_year; + this.attributes.matchType = responseData.attributes.match_type; + this.attributes.otherTaxExemption = responseData.attributes.other_tax_exemption; + this.attributes.ownershipTransferDate = responseData.attributes.ownership_transfer_date; + this.attributes.ownershipTransferDocNumber = + responseData.attributes.ownership_transfer_doc_number; + this.attributes.ownershipTransferTransactionId = + responseData.attributes.ownership_transfer_transaction_id; + this.attributes.ownershipType = responseData.attributes.ownership_type; + this.attributes.ownershipType2 = responseData.attributes.ownership_type_2; + this.attributes.previousAssessedValue = responseData.attributes.previous_assessed_value; + this.attributes.priorSaleAmount = responseData.attributes.prior_sale_amount; + this.attributes.priorSaleDate = responseData.attributes.prior_sale_date; + this.attributes.saleAmount = responseData.attributes.sale_amount; + this.attributes.saleDate = responseData.attributes.sale_date; + this.attributes.seniorTaxExemption = responseData.attributes.senior_tax_exemption; + this.attributes.taxAssessYear = responseData.attributes.tax_assess_year; + this.attributes.taxBilledAmount = responseData.attributes.tax_billed_amount; + this.attributes.taxDelinquentYear = responseData.attributes.tax_delinquent_year; + this.attributes.taxFiscalYear = responseData.attributes.tax_fiscal_year; + this.attributes.taxRateArea = responseData.attributes.tax_rate_area; + this.attributes.totalMarketValue = responseData.attributes.total_market_value; + this.attributes.trustDescription = responseData.attributes.trust_description; + this.attributes.veteranTaxExemption = responseData.attributes.veteran_tax_exemption; + this.attributes.widow_tax_exemption = responseData.attributes.widow_tax_exemption; + } + } } class GeoResponse { - constructor(responseData) { - this.smartyKey = responseData.smarty_key; - this.dataSetName = responseData.data_set_name; + constructor(responseData) { + this.smartyKey = responseData.smarty_key; + this.dataSetName = responseData.data_set_name; - this.attributes = {}; - if (responseData.attributes) { - this.attributes.censusBlock = {}; - if (responseData.attributes.census_block) { - this.attributes.censusBlock.accuracy = responseData.attributes.census_block.accuracy; - this.attributes.censusBlock.geoid = responseData.attributes.census_block.geoid; - } + this.attributes = {}; + if (responseData.attributes) { + this.attributes.censusBlock = {}; + if (responseData.attributes.census_block) { + this.attributes.censusBlock.accuracy = responseData.attributes.census_block.accuracy; + this.attributes.censusBlock.geoid = responseData.attributes.census_block.geoid; + } - this.attributes.censusCountyDivision = {}; - if (responseData.attributes.census_county_division) { - this.attributes.censusCountyDivision.accuracy = responseData.attributes.census_county_division.accuracy; - this.attributes.censusCountyDivision.code = responseData.attributes.census_county_division.code; - this.attributes.censusCountyDivision.name = responseData.attributes.census_county_division.name; - } + this.attributes.censusCountyDivision = {}; + if (responseData.attributes.census_county_division) { + this.attributes.censusCountyDivision.accuracy = + responseData.attributes.census_county_division.accuracy; + this.attributes.censusCountyDivision.code = + responseData.attributes.census_county_division.code; + this.attributes.censusCountyDivision.name = + responseData.attributes.census_county_division.name; + } - this.attributes.censusTract = {}; - if (responseData.attributes.census_tract) { - this.attributes.censusTract.code = responseData.attributes.census_tract.code; - } + this.attributes.censusTract = {}; + if (responseData.attributes.census_tract) { + this.attributes.censusTract.code = responseData.attributes.census_tract.code; + } - this.attributes.coreBasedStatArea = {}; - if (responseData.attributes.core_based_stat_area) { - this.attributes.coreBasedStatArea.code = responseData.attributes.core_based_stat_area.code; - this.attributes.coreBasedStatArea.name = responseData.attributes.core_based_stat_area.name; - } + this.attributes.coreBasedStatArea = {}; + if (responseData.attributes.core_based_stat_area) { + this.attributes.coreBasedStatArea.code = responseData.attributes.core_based_stat_area.code; + this.attributes.coreBasedStatArea.name = responseData.attributes.core_based_stat_area.name; + } - this.attributes.place = {}; - if (responseData.attributes.place) { - this.attributes.place.accuracy = responseData.attributes.place.accuracy; - this.attributes.place.code = responseData.attributes.place.code; - this.attributes.place.name = responseData.attributes.place.name; - this.attributes.place.type = responseData.attributes.place.type; - } - } - } + this.attributes.place = {}; + if (responseData.attributes.place) { + this.attributes.place.accuracy = responseData.attributes.place.accuracy; + this.attributes.place.code = responseData.attributes.place.code; + this.attributes.place.name = responseData.attributes.place.name; + this.attributes.place.type = responseData.attributes.place.type; + } + } + } } module.exports = { - Response, - FinancialResponse, - GeoResponse, -}; \ No newline at end of file + Response, + FinancialResponse, + GeoResponse, +}; diff --git a/src/us_extract/Address.js b/src/us_extract/Address.js index e800e4c..817f178 100644 --- a/src/us_extract/Address.js +++ b/src/us_extract/Address.js @@ -4,14 +4,14 @@ const Candidate = require("../us_street/Candidate"); * @see Smarty US Extract API docs */ class Address { - constructor (responseData) { + constructor(responseData) { this.text = responseData.text; this.verified = responseData.verified; this.line = responseData.line; this.start = responseData.start; this.end = responseData.end; - this.candidates = responseData.api_output.map(rawAddress => new Candidate(rawAddress)); + this.candidates = responseData.api_output.map((rawAddress) => new Candidate(rawAddress)); } } -module.exports = Address; \ No newline at end of file +module.exports = Address; diff --git a/src/us_extract/Client.js b/src/us_extract/Client.js index c2a9202..dfc73bf 100644 --- a/src/us_extract/Client.js +++ b/src/us_extract/Client.js @@ -16,12 +16,13 @@ class Client { send(lookup) { if (typeof lookup === "undefined") throw new Errors.UndefinedLookupError(); - let request = new Request(lookup.text, {"Content-Type": "text/plain; charset=utf-8"}); + let request = new Request(lookup.text, { "Content-Type": "text/plain; charset=utf-8" }); request.parameters = buildInputData(lookup, keyTranslationFormat); return new Promise((resolve, reject) => { - this.sender.send(request) - .then(response => { + this.sender + .send(request) + .then((response) => { if (response.error) reject(response.error); lookup.result = new Result(response.payload); @@ -32,4 +33,4 @@ class Client { } } -module.exports = Client; \ No newline at end of file +module.exports = Client; diff --git a/src/us_extract/Lookup.js b/src/us_extract/Lookup.js index adf43d4..0b12633 100644 --- a/src/us_extract/Lookup.js +++ b/src/us_extract/Lookup.js @@ -26,4 +26,4 @@ class Lookup { } } -module.exports = Lookup; \ No newline at end of file +module.exports = Lookup; diff --git a/src/us_extract/Result.js b/src/us_extract/Result.js index 73bf2ab..eefa86f 100644 --- a/src/us_extract/Result.js +++ b/src/us_extract/Result.js @@ -4,7 +4,7 @@ const Address = require("./Address"); * @see Smarty US Extract API docs */ class Result { - constructor({meta, addresses}) { + constructor({ meta, addresses }) { this.meta = { lines: meta.lines, unicode: meta.unicode, @@ -14,8 +14,8 @@ class Result { characterCount: meta.character_count, }; - this.addresses = addresses.map(rawAddress => new Address(rawAddress)); + this.addresses = addresses.map((rawAddress) => new Address(rawAddress)); } } -module.exports = Result; \ No newline at end of file +module.exports = Result; diff --git a/src/us_reverse_geo/Client.js b/src/us_reverse_geo/Client.js index 910b236..c5fcdca 100644 --- a/src/us_reverse_geo/Client.js +++ b/src/us_reverse_geo/Client.js @@ -2,7 +2,7 @@ const Request = require("../Request"); const Response = require("./Response"); const buildInputData = require("../util/buildInputData"); const keyTranslationFormat = require("../util/apiToSDKKeyMap").usReverseGeo; -const {UndefinedLookupError} = require("../Errors.js"); +const { UndefinedLookupError } = require("../Errors.js"); /** * This client sends lookups to the Smarty US Reverse Geo API,
@@ -20,8 +20,9 @@ class Client { request.parameters = buildInputData(lookup, keyTranslationFormat); return new Promise((resolve, reject) => { - this.sender.send(request) - .then(response => { + this.sender + .send(request) + .then((response) => { if (response.error) reject(response.error); resolve(attachLookupResults(response, lookup)); diff --git a/src/us_reverse_geo/Lookup.js b/src/us_reverse_geo/Lookup.js index abb36da..ce8446a 100644 --- a/src/us_reverse_geo/Lookup.js +++ b/src/us_reverse_geo/Lookup.js @@ -6,7 +6,7 @@ const Response = require("./Response"); * @see "https://www.smarty.com/docs/cloud/us-street-api#input-fields" */ class Lookup { - constructor(latitude, longitude, source="") { + constructor(latitude, longitude, source = "") { this.latitude = latitude.toFixed(8); this.longitude = longitude.toFixed(8); this.source = source; diff --git a/src/us_reverse_geo/Response.js b/src/us_reverse_geo/Response.js index a226fdb..ea9b0e2 100644 --- a/src/us_reverse_geo/Response.js +++ b/src/us_reverse_geo/Response.js @@ -8,7 +8,7 @@ class Response { this.results = []; if (responseData) - responseData.results.map(rawResult => { + responseData.results.map((rawResult) => { this.results.push(new Result(rawResult)); }); } diff --git a/src/us_reverse_geo/Result.js b/src/us_reverse_geo/Result.js index f20cd4f..f1f0a56 100644 --- a/src/us_reverse_geo/Result.js +++ b/src/us_reverse_geo/Result.js @@ -14,7 +14,7 @@ class Result { this.address.city = responseData.address.city; this.address.state_abbreviation = responseData.address.state_abbreviation; this.address.zipcode = responseData.address.zipcode; - this.address.source = responseData.address.source + this.address.source = responseData.address.source; } this.coordinate = {}; @@ -33,4 +33,4 @@ class Result { } } -module.exports = Result; \ No newline at end of file +module.exports = Result; diff --git a/src/us_street/Client.js b/src/us_street/Client.js index e9ab0e5..3bee62b 100644 --- a/src/us_street/Client.js +++ b/src/us_street/Client.js @@ -23,7 +23,7 @@ class Client { const dataIsBatch = data instanceof Batch; const dataIsLookup = data instanceof Lookup; - if (!dataIsLookup && !dataIsBatch) throw new UndefinedLookupError; + if (!dataIsLookup && !dataIsBatch) throw new UndefinedLookupError(); let batch; @@ -38,4 +38,4 @@ class Client { } } -module.exports = Client; \ No newline at end of file +module.exports = Client; diff --git a/src/us_street/Lookup.js b/src/us_street/Lookup.js index 59d2a61..0088b1e 100644 --- a/src/us_street/Lookup.js +++ b/src/us_street/Lookup.js @@ -41,7 +41,6 @@ class Lookup { addCustomParameter(key, value) { this.customParameters[key] = value; } - } module.exports = Lookup; diff --git a/src/us_zipcode/Client.js b/src/us_zipcode/Client.js index 4c81ec3..4b7c7df 100644 --- a/src/us_zipcode/Client.js +++ b/src/us_zipcode/Client.js @@ -23,7 +23,7 @@ class Client { const dataIsBatch = data instanceof Batch; const dataIsLookup = data instanceof Lookup; - if (!dataIsLookup && !dataIsBatch) throw new UndefinedLookupError; + if (!dataIsLookup && !dataIsBatch) throw new UndefinedLookupError(); let batch; @@ -36,4 +36,4 @@ class Client { } } -module.exports = Client; \ No newline at end of file +module.exports = Client; diff --git a/src/us_zipcode/Lookup.js b/src/us_zipcode/Lookup.js index d74c4b4..558c140 100644 --- a/src/us_zipcode/Lookup.js +++ b/src/us_zipcode/Lookup.js @@ -18,4 +18,4 @@ class Lookup { } } -module.exports = Lookup; \ No newline at end of file +module.exports = Lookup; diff --git a/src/us_zipcode/Result.js b/src/us_zipcode/Result.js index 5d7f572..f92188a 100644 --- a/src/us_zipcode/Result.js +++ b/src/us_zipcode/Result.js @@ -8,38 +8,44 @@ class Result { this.reason = responseData.reason; this.valid = this.status === undefined && this.reason === undefined; - this.cities = !responseData.city_states ? [] : responseData.city_states.map(city => { - return { - city: city.city, - stateAbbreviation: city.state_abbreviation, - state: city.state, - mailableCity: city.mailable_city, - }; - }); + this.cities = !responseData.city_states + ? [] + : responseData.city_states.map((city) => { + return { + city: city.city, + stateAbbreviation: city.state_abbreviation, + state: city.state, + mailableCity: city.mailable_city, + }; + }); - this.zipcodes = !responseData.zipcodes ? [] : responseData.zipcodes.map(zipcode => { - return { - zipcode: zipcode.zipcode, - zipcodeType: zipcode.zipcode_type, - defaultCity: zipcode.default_city, - countyFips: zipcode.county_fips, - countyName: zipcode.county_name, - latitude: zipcode.latitude, - longitude: zipcode.longitude, - precision: zipcode.precision, - stateAbbreviation: zipcode.state_abbreviation, - state: zipcode.state, - alternateCounties: !zipcode.alternate_counties ? [] : zipcode.alternate_counties.map(county => { + this.zipcodes = !responseData.zipcodes + ? [] + : responseData.zipcodes.map((zipcode) => { return { - countyFips: county.county_fips, - countyName: county.county_name, - stateAbbreviation: county.state_abbreviation, - state: county.state, - } - }), - }; - }); + zipcode: zipcode.zipcode, + zipcodeType: zipcode.zipcode_type, + defaultCity: zipcode.default_city, + countyFips: zipcode.county_fips, + countyName: zipcode.county_name, + latitude: zipcode.latitude, + longitude: zipcode.longitude, + precision: zipcode.precision, + stateAbbreviation: zipcode.state_abbreviation, + state: zipcode.state, + alternateCounties: !zipcode.alternate_counties + ? [] + : zipcode.alternate_counties.map((county) => { + return { + countyFips: county.county_fips, + countyName: county.county_name, + stateAbbreviation: county.state_abbreviation, + state: county.state, + }; + }), + }; + }); } } -module.exports = Result; \ No newline at end of file +module.exports = Result; diff --git a/src/util/Sleeper.ts b/src/util/Sleeper.ts index e3a8983..d66a0e2 100644 --- a/src/util/Sleeper.ts +++ b/src/util/Sleeper.ts @@ -1,6 +1,6 @@ export default class Sleeper { - constructor () {} + constructor() {} sleep(seconds: number) { - return new Promise((resolve) => setTimeout(resolve, seconds*1000)); + return new Promise((resolve) => setTimeout(resolve, seconds * 1000)); } -} \ No newline at end of file +} diff --git a/src/util/apiToSDKKeyMap.js b/src/util/apiToSDKKeyMap.js index 6201311..069a9e3 100644 --- a/src/util/apiToSDKKeyMap.js +++ b/src/util/apiToSDKKeyMap.js @@ -1,19 +1,19 @@ module.exports = { usStreet: { - "street": "street", - "street2": "street2", - "secondary": "secondary", - "city": "city", - "state": "state", - "zipcode": "zipCode", - "lastline": "lastLine", - "addressee": "addressee", - "urbanization": "urbanization", - "match": "match", - "format": "format", - "candidates": "maxCandidates", - "county_source": "countySource", - "input_id": "inputId" + street: "street", + street2: "street2", + secondary: "secondary", + city: "city", + state: "state", + zipcode: "zipCode", + lastline: "lastLine", + addressee: "addressee", + urbanization: "urbanization", + match: "match", + format: "format", + candidates: "maxCandidates", + county_source: "countySource", + input_id: "inputId", }, usAutocompletePro: { search: "search", @@ -31,23 +31,23 @@ module.exports = { source: "source", }, usZipcode: { - "city": "city", - "state": "state", - "zipcode": "zipCode", + city: "city", + state: "state", + zipcode: "zipCode", }, internationalStreet: { - "country": "country", - "freeform": "freeform", - "address1": "address1", - "address2": "address2", - "address3": "address3", - "address4": "address4", - "organization": "organization", - "locality": "locality", - "administrative_area": "administrativeArea", - "postal_code": "postalCode", - "geocode": "geocode", - "language": "language", + country: "country", + freeform: "freeform", + address1: "address1", + address2: "address2", + address3: "address3", + address4: "address4", + organization: "organization", + locality: "locality", + administrative_area: "administrativeArea", + postal_code: "postalCode", + geocode: "geocode", + language: "language", }, internationalAddressAutocomplete: { search: "search", @@ -58,9 +58,9 @@ module.exports = { include_only_postal_code: "includeOnlyPostalCode", }, usReverseGeo: { - "latitude": "latitude", - "longitude": "longitude", - "source": "source" + latitude: "latitude", + longitude: "longitude", + source: "source", }, usExtract: { html: "html", @@ -75,10 +75,10 @@ module.exports = { data_subset: "dataSubset", }, internationalPostalCode: { - "input_id": "inputId", - "country": "country", - "locality": "locality", - "administrative_area": "administrativeArea", - "postal_code": "postalCode", - } -}; \ No newline at end of file + input_id: "inputId", + country: "country", + locality: "locality", + administrative_area: "administrativeArea", + postal_code: "postalCode", + }, +}; diff --git a/src/util/buildClients.js b/src/util/buildClients.js index 3e84776..dc59b09 100644 --- a/src/util/buildClients.js +++ b/src/util/buildClients.js @@ -50,4 +50,4 @@ module.exports = { internationalAddressAutocomplete: buildInternationalAddressAutocompleteApiClient, usEnrichment: buildUsEnrichmentApiClient, internationalPostalCode: buildInternationalPostalCodeApiClient, -}; \ No newline at end of file +}; diff --git a/src/util/buildSmartyResponse.js b/src/util/buildSmartyResponse.js index 3e80df5..86dc0d5 100644 --- a/src/util/buildSmartyResponse.js +++ b/src/util/buildSmartyResponse.js @@ -1,10 +1,11 @@ const Response = require("../Response.js"); function buildSmartyResponse(response, error) { - if (response) return new Response(response.status, response.data, response.error, response.headers); - return new Response(undefined, undefined, error) + if (response) + return new Response(response.status, response.data, response.error, response.headers); + return new Response(undefined, undefined, error); } module.exports = { - buildSmartyResponse -}; \ No newline at end of file + buildSmartyResponse, +}; diff --git a/src/util/sendBatch.js b/src/util/sendBatch.js index a32ab63..9165f73 100644 --- a/src/util/sendBatch.js +++ b/src/util/sendBatch.js @@ -3,7 +3,7 @@ const Errors = require("../Errors"); const buildInputData = require("../util/buildInputData"); module.exports = (batch, sender, Result, keyTranslationFormat, customBuildInputData) => { - if (batch.isEmpty()) throw new Errors.BatchEmptyError; + if (batch.isEmpty()) throw new Errors.BatchEmptyError(); let request = new Request(); @@ -11,8 +11,9 @@ module.exports = (batch, sender, Result, keyTranslationFormat, customBuildInputD else request.payload = generateRequestPayload(batch); return new Promise((resolve, reject) => { - sender.send(request) - .then(response => { + sender + .send(request) + .then((response) => { if (response.error) reject(response.error); resolve(assignResultsToLookups(batch, response)); @@ -30,7 +31,7 @@ module.exports = (batch, sender, Result, keyTranslationFormat, customBuildInputD } function assignResultsToLookups(batch, response) { - response.payload.map(rawResult => { + response.payload.map((rawResult) => { let result = new Result(rawResult); let lookup = batch.getByIndex(result.inputIndex); diff --git a/tests/fixtures/MockSleeper.js b/tests/fixtures/MockSleeper.js index c4aa527..3b0ba5f 100644 --- a/tests/fixtures/MockSleeper.js +++ b/tests/fixtures/MockSleeper.js @@ -7,4 +7,4 @@ class MockSleeper { } } -module.exports = MockSleeper; \ No newline at end of file +module.exports = MockSleeper; diff --git a/tests/fixtures/mock_senders.js b/tests/fixtures/mock_senders.js index 861466c..f8af607 100644 --- a/tests/fixtures/mock_senders.js +++ b/tests/fixtures/mock_senders.js @@ -1,4 +1,4 @@ -const {buildSmartyResponse} = require("../../src/util/buildSmartyResponse.js"); +const { buildSmartyResponse } = require("../../src/util/buildSmartyResponse.js"); const Response = require("../../src/Response"); module.exports = { @@ -14,16 +14,20 @@ module.exports = { request.payload = clientRequest.payload; request.parameters = clientRequest.parameters; request.baseUrlParam = clientRequest.baseUrlParam; - } + }; }, MockSenderWithResponse: function (expectedPayload, expectedError) { this.send = function () { return new Promise((resolve, reject) => { resolve(new Response("", expectedPayload, expectedError)); }); - } + }; }, - MockSenderWithStatusCodesAndHeaders: function (statusCodes, headers = undefined, error = undefined) { + MockSenderWithStatusCodesAndHeaders: function ( + statusCodes, + headers = undefined, + error = undefined, + ) { this.statusCodes = statusCodes; this.headers = headers; this.error = error; @@ -38,6 +42,6 @@ module.exports = { const response = buildSmartyResponse(mockResponse); this.currentStatusCodeIndex += 1; return response; - } - } + }; + }, }; diff --git a/tests/international_address_autocomplete/test_Client.js b/tests/international_address_autocomplete/test_Client.js index 9db7bf7..a4c50fe 100644 --- a/tests/international_address_autocomplete/test_Client.js +++ b/tests/international_address_autocomplete/test_Client.js @@ -12,7 +12,7 @@ describe("An International Address Autocomplete Client", function () { let mockSender = new MockSender(); let client = new Client(mockSender); let search = "("; - let lookup = new Lookup({search}); + let lookup = new Lookup({ search }); let expectedParameters = { max_results: 5, search: "(", @@ -26,7 +26,7 @@ describe("An International Address Autocomplete Client", function () { let mockSender = new MockSender(); let client = new Client(mockSender); let search = "("; - let lookup = new Lookup({search}); + let lookup = new Lookup({ search }); lookup.search = search; lookup.country = "Russia"; let expectedParameters = { @@ -43,7 +43,7 @@ describe("An International Address Autocomplete Client", function () { let mockSender = new MockSender(); let client = new Client(mockSender); let search = "("; - let lookup = new Lookup({search}); + let lookup = new Lookup({ search }); lookup.search = search; lookup.maxResults = 10; let expectedParameters = { @@ -65,22 +65,22 @@ describe("An International Address Autocomplete Client", function () { const responseData = { candidates: [ { - "street": "L alleya", - "locality": "Novosibirsk", - "administrative_area": "Novosibirskaya oblast'", - "postal_code": "40000", - "country_iso3": "RUS", - } - ] + street: "L alleya", + locality: "Novosibirsk", + administrative_area: "Novosibirskaya oblast'", + postal_code: "40000", + country_iso3: "RUS", + }, + ], }; let mockSender = new MockSenderWithResponse(responseData); let client = new Client(mockSender); - let lookup = new Lookup({search: "f"}); + let lookup = new Lookup({ search: "f" }); let expectedSuggestion = new Suggestion(responseData.candidates[0]); return client.send(lookup).then(() => { expect(lookup.result[0]).to.deep.equal(expectedSuggestion); }); }); -}); \ No newline at end of file +}); diff --git a/tests/international_address_autocomplete/test_Lookup.js b/tests/international_address_autocomplete/test_Lookup.js index 7d47618..d0bc05c 100644 --- a/tests/international_address_autocomplete/test_Lookup.js +++ b/tests/international_address_autocomplete/test_Lookup.js @@ -5,37 +5,37 @@ const Lookup = require("../../src/international_address_autocomplete/Lookup"); describe("An International Address Autocomplete lookup", function () { it("Can be newed up with a prefix", function () { const expectedPrefix = "z"; - let lookup = new Lookup({search: expectedPrefix}); + let lookup = new Lookup({ search: expectedPrefix }); expect(lookup.search).to.equal(expectedPrefix); }); it("Set address ID", function () { const addressId = "111"; - let lookup = new Lookup({addressId}); + let lookup = new Lookup({ addressId }); expect(lookup.addressId).to.equal(addressId); }); it("Set country", function () { const country = "Russia"; - let lookup = new Lookup({country}); + let lookup = new Lookup({ country }); expect(lookup.country).to.equal(country); }); it("Set max results", function () { const maxResults = 10000; - let lookup = new Lookup({maxResults}); + let lookup = new Lookup({ maxResults }); expect(lookup.maxResults).to.equal(maxResults); }); it("Set include only include locality param", function () { const onlyIncludeLocality = "locality"; - let lookup = new Lookup({includeOnlyLocality: onlyIncludeLocality}); + let lookup = new Lookup({ includeOnlyLocality: onlyIncludeLocality }); expect(lookup.includeOnlyLocality).to.equal(onlyIncludeLocality); }); it("Set include only include postal code param", function () { const onlyIncludePostalCode = "post code"; - let lookup = new Lookup({includeOnlyPostalCode: onlyIncludePostalCode}); + let lookup = new Lookup({ includeOnlyPostalCode: onlyIncludePostalCode }); expect(lookup.includeOnlyPostalCode).to.equal(onlyIncludePostalCode); }); @@ -53,4 +53,4 @@ describe("An International Address Autocomplete lookup", function () { let lookup = new Lookup(); expect(lookup).to.deep.equal(defaultLookup); }); -}); \ No newline at end of file +}); diff --git a/tests/international_street/test_Client.js b/tests/international_street/test_Client.js index 20e64e7..f5158b9 100644 --- a/tests/international_street/test_Client.js +++ b/tests/international_street/test_Client.js @@ -57,13 +57,13 @@ describe("An International Street client", function () { }); it("attaches a match candidate from a response to a lookup.", function () { - const expectedMockPayload = [{address1: "A", }]; + const expectedMockPayload = [{ address1: "A" }]; let mockSender = new MockSenderWithResponse(expectedMockPayload); const client = new Client(mockSender); let lookup = new Lookup(); - let expectedResult = new Candidate({address1: "A"}); + let expectedResult = new Candidate({ address1: "A" }); - return client.send(lookup).then(response => { + return client.send(lookup).then((response) => { expect(lookup.result[0]).to.deep.equal(expectedResult); }); }); diff --git a/tests/international_street/test_Lookup.js b/tests/international_street/test_Lookup.js index ed4e40f..178e771 100644 --- a/tests/international_street/test_Lookup.js +++ b/tests/international_street/test_Lookup.js @@ -7,9 +7,11 @@ describe("An International Street lookup", function () { const messages = { countryRequired: "Country field is required.", freeformOrAddress1Required: "Either freeform or address1 is required.", - insufficientInformation: "Insufficient information: One or more required fields were not set on the lookup.", + insufficientInformation: + "Insufficient information: One or more required fields were not set on the lookup.", badGeocode: "Invalid input: geocode can only be set to 'true' (default is 'false'.", - invalidLanguage: "Invalid input: language can only be set to 'latin' or 'native'. When not set, the the output language will match the language of the input values." + invalidLanguage: + "Invalid input: language can only be set to 'latin' or 'native'. When not set, the the output language will match the language of the input values.", }; it("correctly populates fields.", function () { @@ -99,10 +101,9 @@ describe("An International Street lookup", function () { try { callback(); expect(true).to.equal(false); - } - catch (error) { + } catch (error) { expect(error.message).to.equal(expectedError.message); expect(error).to.be.an.instanceOf(errors.UnprocessableEntityError); } } -}); \ No newline at end of file +}); diff --git a/tests/test_Batch.js b/tests/test_Batch.js index 383cefb..3ecd33c 100644 --- a/tests/test_Batch.js +++ b/tests/test_Batch.js @@ -11,18 +11,18 @@ describe("A batch", function () { batch = new Batch(); }); - it ("has a lookups field.", function () { + it("has a lookups field.", function () { expect(batch.hasOwnProperty("lookups")).to.equal(true); expect(Array.isArray(batch.lookups)).to.equal(true); }); - it ("can add a lookup to its array of lookups.", function () { + it("can add a lookup to its array of lookups.", function () { expect(batch.lookups.length).to.equal(0); batch.add("Hi."); expect(batch.lookups.length).to.equal(1); }); - it ("errors if you add a lookup when it's full.", function () { + it("errors if you add a lookup when it's full.", function () { for (let i = 0; i < 100; i++) { let lookup = {}; batch.add(lookup); @@ -31,13 +31,13 @@ describe("A batch", function () { expect(() => batch.add({})).to.throw(errors.BatchFullError); }); - it ("can be cleared.", function () { + it("can be cleared.", function () { batch.add("Hi."); batch.clear(); expect(batch.lookups.length).to.equal(0); }); - it ("has a length.", function () { + it("has a length.", function () { expect(batch.length()).to.equal(0); for (let i = 0; i < 50; i++) { batch.add(i); @@ -45,7 +45,7 @@ describe("A batch", function () { expect(batch.length()).to.equal(50); }); - it ("returns a lookup by index.", function () { + it("returns a lookup by index.", function () { for (let i = 0; i < 100; i++) { batch.add(i); } @@ -53,7 +53,7 @@ describe("A batch", function () { expect(batch.getByIndex(50)).to.equal(50); }); - it ("returns a lookup by input id.", function () { + it("returns a lookup by input id.", function () { for (let i = 0; i < 100; i++) { let lookup = new Lookup(); lookup.inputId = i; @@ -65,9 +65,9 @@ describe("A batch", function () { expect(batch.getByInputId(50)).to.deep.equal(expectedLookup); }); - it ("knows if it's empty.", function () { + it("knows if it's empty.", function () { expect(batch.isEmpty()).to.equal(true); batch.add("1"); expect(batch.isEmpty()).to.equal(false); }); -}); \ No newline at end of file +}); diff --git a/tests/test_HttpSender.js b/tests/test_HttpSender.js index f526fe2..f7eb222 100644 --- a/tests/test_HttpSender.js +++ b/tests/test_HttpSender.js @@ -2,9 +2,9 @@ const chai = require("chai"); const expect = chai.expect; const Request = require("../src/Request"); const HttpSender = require("../src/HttpSender"); -const {buildSmartyResponse} = require("../src/util/buildSmartyResponse"); +const { buildSmartyResponse } = require("../src/util/buildSmartyResponse"); -describe ("An Axios implementation of a HTTP sender", function () { +describe("An Axios implementation of a HTTP sender", function () { it("adds a data payload to the HTTP request config.", function () { let expectedPayload = "test payload"; let request = new Request(expectedPayload); @@ -15,7 +15,7 @@ describe ("An Axios implementation of a HTTP sender", function () { expect(requestConfig.data).to.equal(expectedPayload); }); - it ("adds a POST method to the HTTP request config when appropriate.", function () { + it("adds a POST method to the HTTP request config when appropriate.", function () { let request = new Request("test payload"); let sender = new HttpSender(); let requestConfig = sender.buildRequestConfig(request); @@ -24,7 +24,7 @@ describe ("An Axios implementation of a HTTP sender", function () { expect(requestConfig.method).to.equal("POST"); }); - it ("adds a GET method to the HTTP request config when appropriate.", function () { + it("adds a GET method to the HTTP request config when appropriate.", function () { let request = new Request(); let sender = new HttpSender(); let requestConfig = sender.buildRequestConfig(request); @@ -33,7 +33,7 @@ describe ("An Axios implementation of a HTTP sender", function () { expect(requestConfig.method).to.equal("GET"); }); - it ("add a timeout to the HTTP request config.", function () { + it("add a timeout to the HTTP request config.", function () { let request = new Request("test payload"); let sender = new HttpSender(); let requestConfig = sender.buildRequestConfig(request); @@ -47,7 +47,7 @@ describe ("An Axios implementation of a HTTP sender", function () { expect(customTimeoutRequestConfig.timeout).to.equal(5); }); - it ("adds parameters to the HTTP request config.", function () { + it("adds parameters to the HTTP request config.", function () { let request = new Request(""); let sender = new HttpSender(); request.parameters.test = "1"; @@ -57,7 +57,7 @@ describe ("An Axios implementation of a HTTP sender", function () { expect(requestConfig.params).to.deep.equal(request.parameters); }); - it ("adds headers to the HTTP request config.", function () { + it("adds headers to the HTTP request config.", function () { let request = new Request(""); let sender = new HttpSender(); let requestConfig = sender.buildRequestConfig(request); @@ -67,10 +67,10 @@ describe ("An Axios implementation of a HTTP sender", function () { expect(requestConfig.headers["Content-Type"]).to.equal("application/json; charset=utf-8"); }); - it ("has a response with the right status code.", function () { + it("has a response with the right status code.", function () { let sender = new HttpSender(); let mockResponse = { - status: 200 + status: 200, }; let smartyResponse = buildSmartyResponse(mockResponse); @@ -78,12 +78,12 @@ describe ("An Axios implementation of a HTTP sender", function () { expect(smartyResponse.statusCode).to.equal(200); }); - it ("has a response with a payload.", function () { + it("has a response with a payload.", function () { let sender = new HttpSender(); let mockData = [1, 2, 3]; let mockResponse = { status: 200, - data: mockData + data: mockData, }; let smartyResponse = buildSmartyResponse(mockResponse); diff --git a/tests/test_LicenseSender.js b/tests/test_LicenseSender.js index bbe7971..152b3ae 100644 --- a/tests/test_LicenseSender.js +++ b/tests/test_LicenseSender.js @@ -11,7 +11,7 @@ describe("A license sender", function () { beforeEach(() => { innerSender = { - send: () => true + send: () => true, }; request = new Request(); }); @@ -21,14 +21,14 @@ describe("A license sender", function () { licenseSender = new LicenseSender(innerSender, licenses); licenseSender.send(request); - expect(request.parameters).contains({"license": "0,1,2"}); + expect(request.parameters).contains({ license: "0,1,2" }); }); it("doesn't append license to query if array is empty.", function () { licenses = []; licenseSender = new LicenseSender(innerSender, licenses); licenseSender.send(request); - + expect(request.parameters).to.not.have.property("license"); }); diff --git a/tests/test_StatusCodeSender.js b/tests/test_StatusCodeSender.js index 4d5637b..06df7dc 100644 --- a/tests/test_StatusCodeSender.js +++ b/tests/test_StatusCodeSender.js @@ -12,29 +12,27 @@ describe("A status code sender", function () { return new Promise((resolve, reject) => { resolve(new Response(200)); }); - } + }, }; let statusCodeSender = new StatusCodeSender(mockSender); let request = new Request(); - return statusCodeSender.send(request).then(response => { + return statusCodeSender.send(request).then((response) => { expect(response.error === undefined).to.equal(true); }); }); it("gives a custom message for 400", function () { const payload = { - errors: [ - {message: "custom message"} - ] + errors: [{ message: "custom message" }], }; return expectedErrorWithPayloadMessage(400, payload); - }) + }); it("returns an error message if payload is undefined", function () { - return expectedDefaultError() - }) + return expectedDefaultError(); + }); it("gives an Internal Server Error on a 500.", function () { return expectedErrorForStatusCode(errors.InternalServerError, 500); @@ -54,42 +52,48 @@ const expectedErrorWithPayloadMessage = (errorCode, payload) => { let statusCodeSender = new StatusCodeSender(mockSender); let request = new Request(); - return statusCodeSender.send(request).then(() => { - }, error => { - expect(error.error).to.be.an.instanceOf(errors.DefaultError); - expect(error.error.message).to.be.equal(payload.errors[0].message); - }) -} + return statusCodeSender.send(request).then( + () => {}, + (error) => { + expect(error.error).to.be.an.instanceOf(errors.DefaultError); + expect(error.error.message).to.be.equal(payload.errors[0].message); + }, + ); +}; const expectedDefaultError = () => { let mockSender = generateMockSender(400); let statusCodeSender = new StatusCodeSender(mockSender); let request = new Request(); - return statusCodeSender.send(request).then(() => { - }, error => { - expect(error.error).to.be.an.instanceOf(errors.DefaultError); - expect(error.error.message).to.be.equal("unexpected error"); - }) -} + return statusCodeSender.send(request).then( + () => {}, + (error) => { + expect(error.error).to.be.an.instanceOf(errors.DefaultError); + expect(error.error.message).to.be.equal("unexpected error"); + }, + ); +}; function expectedErrorForStatusCode(expectedError, errorCode) { let mockSender = generateMockSender(errorCode); let statusCodeSender = new StatusCodeSender(mockSender); let request = new Request(); - return statusCodeSender.send(request).then(() => { - }, error => { - expect(error.error).to.be.an.instanceOf(expectedError); - }) + return statusCodeSender.send(request).then( + () => {}, + (error) => { + expect(error.error).to.be.an.instanceOf(expectedError); + }, + ); } function generateMockSender(errorCode, payload) { return { send: () => { return new Promise((resolve, reject) => { - reject(new Response(errorCode, payload)) + reject(new Response(errorCode, payload)); }); - } + }, }; } diff --git a/tests/us_autocomplete_pro/test_Client.js b/tests/us_autocomplete_pro/test_Client.js index fa9bfed..be7d43f 100644 --- a/tests/us_autocomplete_pro/test_Client.js +++ b/tests/us_autocomplete_pro/test_Client.js @@ -79,17 +79,19 @@ describe("A US Autocomplete Pro Client", function () { let client = new Client(mockSender); let lookup = new Lookup("¯\\_(ツ)_/¯"); - return client.send(lookup).catch((e) => {expect(e).to.equal(expectedError);}); + return client.send(lookup).catch((e) => { + expect(e).to.equal(expectedError); + }); }); it("returns an empty array when no suggestions are returned.", () => { - let mockExpectedPayload = {suggestions: null}; + let mockExpectedPayload = { suggestions: null }; let mockSender = new MockSenderWithResponse(mockExpectedPayload); let client = new Client(mockSender); let lookup = new Lookup("Please let this be easy to test."); let expectedSuggestion = []; - return client.send(lookup).then(response => { + return client.send(lookup).then((response) => { expect(lookup.result).to.deep.equal(expectedSuggestion); }); }); @@ -103,14 +105,14 @@ describe("A US Autocomplete Pro Client", function () { zipcode: "e", entries: "f", }; - let mockExpectedPayload = {suggestions: [responseData]}; + let mockExpectedPayload = { suggestions: [responseData] }; let mockSender = new MockSenderWithResponse(mockExpectedPayload); let client = new Client(mockSender); let lookup = new Lookup("Trevor the Vampire"); let expectedSuggestion = new Suggestion(responseData); - return client.send(lookup).then(response => { + return client.send(lookup).then((response) => { expect(lookup.result[0]).to.deep.equal(expectedSuggestion); }); - }) + }); }); diff --git a/tests/us_autocomplete_pro/test_Lookup.js b/tests/us_autocomplete_pro/test_Lookup.js index 0c5a084..6c355bc 100644 --- a/tests/us_autocomplete_pro/test_Lookup.js +++ b/tests/us_autocomplete_pro/test_Lookup.js @@ -8,4 +8,4 @@ describe("A US Autocomplete Pro Lookup", function () { let lookup = new Lookup(expectedSearch); expect(lookup.search).to.equal(expectedSearch); }); -}); \ No newline at end of file +}); diff --git a/tests/us_autocomplete_pro/test_Suggestion.js b/tests/us_autocomplete_pro/test_Suggestion.js index 872484d..6770355 100644 --- a/tests/us_autocomplete_pro/test_Suggestion.js +++ b/tests/us_autocomplete_pro/test_Suggestion.js @@ -21,4 +21,4 @@ describe("A US Autocomplete Pro Suggestion", function () { expect(suggestion.zipcode).to.equal("e"); expect(suggestion.entries).to.equal("f"); }); -}); \ No newline at end of file +}); diff --git a/tests/us_enrichment/test_Client.js b/tests/us_enrichment/test_Client.js index 27cc556..987c442 100644 --- a/tests/us_enrichment/test_Client.js +++ b/tests/us_enrichment/test_Client.js @@ -5,451 +5,451 @@ const Lookup = require("../../src/us_enrichment/Lookup"); const errors = require("../../src/Errors"); const MockSender = require("../fixtures/mock_senders").MockSender; const MockSenderWithResponse = require("../fixtures/mock_senders").MockSenderWithResponse; -const {Response, FinancialResponse, GeoResponse} = require("../../src/us_enrichment/Response"); +const { Response, FinancialResponse, GeoResponse } = require("../../src/us_enrichment/Response"); describe("A US Enrichment Client", function () { - it("composes principal url path properly", function () { - let mockSender = new MockSender(); - let client = new Client(mockSender); - let smartyKey = "0"; - let lookup = new Lookup(smartyKey); - - client.sendPrincipal(lookup); - - expect(mockSender.request.baseUrlParam).to.deep.equal("0/property/principal"); - }) - - it("composes financial url path properly", function () { - let mockSender = new MockSender(); - let client = new Client(mockSender); - let smartyKey = "0"; - let lookup = new Lookup(smartyKey); - - client.sendFinancial(lookup); - - expect(mockSender.request.baseUrlParam).to.deep.equal("0/property/financial"); - }) - - it("composes geo url path properly", function () { - let mockSender = new MockSender(); - let client = new Client(mockSender); - let smartyKey = "0"; - let lookup = new Lookup(smartyKey); - - client.sendGeo(lookup); - - expect(mockSender.request.baseUrlParam).to.deep.equal("0/geo-reference"); - }) - - it("composes secondary url path properly", function () { - let mockSender = new MockSender(); - let client = new Client(mockSender); - let smartyKey = "0"; - let lookup = new Lookup(smartyKey); - - client.sendSecondary(lookup); - - expect(mockSender.request.baseUrlParam).to.deep.equal("0/secondary"); - }) - - it("composes secondary count url path properly", function () { - let mockSender = new MockSender(); - let client = new Client(mockSender); - let smartyKey = "0"; - let lookup = new Lookup(smartyKey); - - client.sendSecondaryCount(lookup); - - expect(mockSender.request.baseUrlParam).to.deep.equal("0/secondary/count"); - }) - - it("correctly builds parameters for a smartyKey only principal lookup.", function () { - let mockSender = new MockSender(); - let client = new Client(mockSender); - let smartyKey = '(>")>#'; - let include = "1"; - let lookup = new Lookup(smartyKey, include); - let expectedParameters = { - include: include, - }; - - client.sendPrincipal(lookup); - - expect(mockSender.request.parameters).to.deep.equal(expectedParameters); - }); - - it("correctly builds parameters for a smartyKey only financial lookup.", function () { - let mockSender = new MockSender(); - let client = new Client(mockSender); - let smartyKey = '(>")>#'; - let include = "1"; - let lookup = new Lookup(smartyKey, include); - let expectedParameters = { - include: include, - }; - - client.sendFinancial(lookup); - - expect(mockSender.request.parameters).to.deep.equal(expectedParameters); - }); - - it("correctly builds parameters for a smartyKey only geo lookup.", function () { - let mockSender = new MockSender(); - let client = new Client(mockSender); - let smartyKey = '(>")>#'; - let include = "1"; - let lookup = new Lookup(smartyKey, include); - let expectedParameters = { - include: include, - }; - - client.sendGeo(lookup); - - expect(mockSender.request.parameters).to.deep.equal(expectedParameters); - }); - - it("correctly builds parameters for a smartyKey only secondary lookup.", function () { - let mockSender = new MockSender(); - let client = new Client(mockSender); - let smartyKey = '(>")>#'; - let include = "1"; - let lookup = new Lookup(smartyKey, include); - let expectedParameters = { - include: include, - }; - - client.sendSecondary(lookup); - - expect(mockSender.request.parameters).to.deep.equal(expectedParameters); - }); - - it("correctly builds parameters for a smartyKey only secondary count lookup.", function () { - let mockSender = new MockSender(); - let client = new Client(mockSender); - let smartyKey = '(>")>#'; - let include = "1"; - let lookup = new Lookup(smartyKey, include); - let expectedParameters = { - include: include, - }; - - client.sendSecondaryCount(lookup); - - expect(mockSender.request.parameters).to.deep.equal(expectedParameters); - }); - - it("correctly builds parameters for a fully-populated principal lookup.", function () { - let mockSender = new MockSender(); - let client = new Client(mockSender); - let lookup = new Lookup("0", "1", "2", "3", "4"); - - let expectedParameters = { - include: "1", - exclude: "2", - dataset: "3", - data_subset: "4", - }; - - client.sendPrincipal(lookup); - expect(mockSender.request.parameters).to.deep.equal(expectedParameters); - }); - - it("correctly builds parameters for a fully-populated financial lookup.", function () { - let mockSender = new MockSender(); - let client = new Client(mockSender); - let lookup = new Lookup("0", "1", "2", "3", "4"); - - let expectedParameters = { - include: "1", - exclude: "2", - dataset: "3", - data_subset: "4", - }; - - client.sendFinancial(lookup); - expect(mockSender.request.parameters).to.deep.equal(expectedParameters); - }); - - it("correctly builds parameters for a fully-populated geo lookup.", function () { - let mockSender = new MockSender(); - let client = new Client(mockSender); - let lookup = new Lookup("0", "1", "2", "3", "4"); - - let expectedParameters = { - include: "1", - exclude: "2", - dataset: "3", - data_subset: "4", - }; - - client.sendGeo(lookup); - expect(mockSender.request.parameters).to.deep.equal(expectedParameters); - }); - - it("correctly builds parameters for a fully-populated secondary lookup.", function () { - let mockSender = new MockSender(); - let client = new Client(mockSender); - let lookup = new Lookup("0", "1", "2", "3", "4"); - - let expectedParameters = { - include: "1", - exclude: "2", - dataset: "3", - data_subset: "4", - }; - - client.sendSecondary(lookup); - expect(mockSender.request.parameters).to.deep.equal(expectedParameters); - }); - - it("correctly builds parameters for a fully-populated secondary count lookup.", function () { - let mockSender = new MockSender(); - let client = new Client(mockSender); - let lookup = new Lookup("0", "1", "2", "3", "4"); - - let expectedParameters = { - include: "1", - exclude: "2", - dataset: "3", - data_subset: "4", - }; - - client.sendSecondaryCount(lookup); - expect(mockSender.request.parameters).to.deep.equal(expectedParameters); - }); - - it("throws an error if sending without a principal lookup.", function () { - let mockSender = new MockSender(); - let client = new Client(mockSender); - expect(client.sendPrincipal).to.throw(errors.UndefinedLookupError); - }); - - it("throws an error if sending without a financial lookup.", function () { - let mockSender = new MockSender(); - let client = new Client(mockSender); - expect(client.sendFinancial).to.throw(errors.UndefinedLookupError); - }); - - it("throws an error if sending without a geo lookup.", function () { - let mockSender = new MockSender(); - let client = new Client(mockSender); - expect(client.sendGeo).to.throw(errors.UndefinedLookupError); - }); - - it("throws an error if sending without a secondary lookup.", function () { - let mockSender = new MockSender(); - let client = new Client(mockSender); - expect(client.sendSecondary).to.throw(errors.UndefinedLookupError); - }); - - it("throws an error if sending without a secondary count lookup.", function () { - let mockSender = new MockSender(); - let client = new Client(mockSender); - expect(client.sendSecondaryCount).to.throw(errors.UndefinedLookupError); - }); - - it("rejects with an exception if the principal response comes back with an error.", function () { - let expectedError = new Error("I'm the error."); - let mockSender = new MockSenderWithResponse("", expectedError); - let client = new Client(mockSender); - let lookup = new Lookup("¯\\_(ツ)_/¯"); - - return client.sendPrincipal(lookup).catch((e) => { - expect(e).to.equal(expectedError); - }); - }); - - it("rejects with an exception if the financial response comes back with an error.", function () { - let expectedError = new Error("I'm the error."); - let mockSender = new MockSenderWithResponse("", expectedError); - let client = new Client(mockSender); - let lookup = new Lookup("¯\\_(ツ)_/¯"); - - return client.sendFinancial(lookup).catch((e) => { - expect(e).to.equal(expectedError); - }); - }); - - it("rejects with an exception if the geo response comes back with an error.", function () { - let expectedError = new Error("I'm the error."); - let mockSender = new MockSenderWithResponse("", expectedError); - let client = new Client(mockSender); - let lookup = new Lookup("¯\\_(ツ)_/¯"); - - return client.sendGeo(lookup).catch((e) => { - expect(e).to.equal(expectedError); - }); - }); - - it("rejects with an exception if the secondary response comes back with an error.", function () { - let expectedError = new Error("I'm the error."); - let mockSender = new MockSenderWithResponse("", expectedError); - let client = new Client(mockSender); - let lookup = new Lookup("¯\\_(ツ)_/¯"); - - return client.sendSecondary(lookup).catch((e) => { - expect(e).to.equal(expectedError); - }); - }); - - it("rejects with an exception if the secondary count response comes back with an error.", function () { - let expectedError = new Error("I'm the error."); - let mockSender = new MockSenderWithResponse("", expectedError); - let client = new Client(mockSender); - let lookup = new Lookup("¯\\_(ツ)_/¯"); - - return client.sendSecondaryCount(lookup).catch((e) => { - expect(e).to.equal(expectedError); - }); - }); - - it("returns an empty array when no principal respo are returned.", () => { - let mockSender = new MockSenderWithResponse({}); - let client = new Client(mockSender); - let lookup = new Lookup("smartyKey"); - - return client.sendPrincipal(lookup).then(response => { - expect(lookup.response).to.deep.equal({}); - }); - }); - - it("returns an empty array when no financial suggestions are returned.", () => { - let mockSender = new MockSenderWithResponse({}); - let client = new Client(mockSender); - let lookup = new Lookup("smartyKey"); - - return client.sendFinancial(lookup).then(response => { - expect(lookup.response).to.deep.equal({}); - }); - }); - - it("returns an empty array when no geo suggestions are returned.", () => { - let mockSender = new MockSenderWithResponse({}); - let client = new Client(mockSender); - let lookup = new Lookup("smartyKey"); - - return client.sendGeo(lookup).then(response => { - expect(lookup.response).to.deep.equal({}); - }); - }); - - it("returns an empty array when no secondary suggestions are returned.", () => { - let mockSender = new MockSenderWithResponse({}); - let client = new Client(mockSender); - let lookup = new Lookup("smartyKey"); - - return client.sendSecondary(lookup).then(response => { - expect(lookup.response).to.deep.equal({}); - }); - }); - - it("returns an empty array when no secondary count suggestions are returned.", () => { - let mockSender = new MockSenderWithResponse({}); - let client = new Client(mockSender); - let lookup = new Lookup("smartyKey"); - - return client.sendSecondaryCount(lookup).then(response => { - expect(lookup.response).to.deep.equal({}); - }); - }); - - it("attaches response to a principal lookup.", function () { - const rawMockResponse = { - smarty_key: "a", - data_set_name: "b", - data_subset_name: "c", - attributes: { - assessed_improvement_percent: "1" - }, - }; - let mockResponse = new Response(rawMockResponse); - - let mockSender = new MockSenderWithResponse(mockResponse); - let client = new Client(mockSender); - let lookup = new Lookup("smartyKey"); - - return client.sendPrincipal(lookup).then(response => { - expect(lookup.response).to.deep.equal(mockResponse); - }); - }) - - it("attaches response to a financial lookup.", function () { - const rawMockResponse = { - smarty_key: "a", - data_set_name: "b", - data_subset_name: "c", - attributes: { - assessed_improvement_percent: "1" - }, - }; - let mockResponse = new FinancialResponse(rawMockResponse); - - let mockSender = new MockSenderWithResponse(mockResponse); - let client = new Client(mockSender); - let lookup = new Lookup("smartyKey"); - - return client.sendFinancial(lookup).then(response => { - expect(lookup.response).to.deep.equal(mockResponse); - }); - }) - - it("attaches response to a geo lookup.", function () { - const rawMockResponse = { - smarty_key: "a", - data_set_name: "b", - data_subset_name: "c", - attributes: { - assessed_improvement_percent: "1" - }, - }; - let mockResponse = new GeoResponse(rawMockResponse); - - let mockSender = new MockSenderWithResponse(mockResponse); - let client = new Client(mockSender); - let lookup = new Lookup("smartyKey"); - - return client.sendGeo(lookup).then(response => { - expect(lookup.response).to.deep.equal(mockResponse); - }); - }) - - it("attaches response to a secondary lookup.", function () { - const rawMockResponse = { - smarty_key: "a", - data_set_name: "b", - data_subset_name: "c", - attributes: { - assessed_improvement_percent: "1" - }, - }; - let mockResponse = new Response(rawMockResponse); - - let mockSender = new MockSenderWithResponse(mockResponse); - let client = new Client(mockSender); - let lookup = new Lookup("smartyKey"); - - return client.sendSecondary(lookup).then(response => { - expect(lookup.response).to.deep.equal(mockResponse); - }); - }) - - it("attaches response to a secondary count lookup.", function () { - const rawMockResponse = { - smarty_key: "a", - data_set_name: "b", - data_subset_name: "c", - attributes: { - assessed_improvement_percent: "1" - }, - }; - let mockResponse = new Response(rawMockResponse); - - let mockSender = new MockSenderWithResponse(mockResponse); - let client = new Client(mockSender); - let lookup = new Lookup("smartyKey"); - - return client.sendSecondaryCount(lookup).then(response => { - expect(lookup.response).to.deep.equal(mockResponse); - }); - }) + it("composes principal url path properly", function () { + let mockSender = new MockSender(); + let client = new Client(mockSender); + let smartyKey = "0"; + let lookup = new Lookup(smartyKey); + + client.sendPrincipal(lookup); + + expect(mockSender.request.baseUrlParam).to.deep.equal("0/property/principal"); + }); + + it("composes financial url path properly", function () { + let mockSender = new MockSender(); + let client = new Client(mockSender); + let smartyKey = "0"; + let lookup = new Lookup(smartyKey); + + client.sendFinancial(lookup); + + expect(mockSender.request.baseUrlParam).to.deep.equal("0/property/financial"); + }); + + it("composes geo url path properly", function () { + let mockSender = new MockSender(); + let client = new Client(mockSender); + let smartyKey = "0"; + let lookup = new Lookup(smartyKey); + + client.sendGeo(lookup); + + expect(mockSender.request.baseUrlParam).to.deep.equal("0/geo-reference"); + }); + + it("composes secondary url path properly", function () { + let mockSender = new MockSender(); + let client = new Client(mockSender); + let smartyKey = "0"; + let lookup = new Lookup(smartyKey); + + client.sendSecondary(lookup); + + expect(mockSender.request.baseUrlParam).to.deep.equal("0/secondary"); + }); + + it("composes secondary count url path properly", function () { + let mockSender = new MockSender(); + let client = new Client(mockSender); + let smartyKey = "0"; + let lookup = new Lookup(smartyKey); + + client.sendSecondaryCount(lookup); + + expect(mockSender.request.baseUrlParam).to.deep.equal("0/secondary/count"); + }); + + it("correctly builds parameters for a smartyKey only principal lookup.", function () { + let mockSender = new MockSender(); + let client = new Client(mockSender); + let smartyKey = '(>")>#'; + let include = "1"; + let lookup = new Lookup(smartyKey, include); + let expectedParameters = { + include: include, + }; + + client.sendPrincipal(lookup); + + expect(mockSender.request.parameters).to.deep.equal(expectedParameters); + }); + + it("correctly builds parameters for a smartyKey only financial lookup.", function () { + let mockSender = new MockSender(); + let client = new Client(mockSender); + let smartyKey = '(>")>#'; + let include = "1"; + let lookup = new Lookup(smartyKey, include); + let expectedParameters = { + include: include, + }; + + client.sendFinancial(lookup); + + expect(mockSender.request.parameters).to.deep.equal(expectedParameters); + }); + + it("correctly builds parameters for a smartyKey only geo lookup.", function () { + let mockSender = new MockSender(); + let client = new Client(mockSender); + let smartyKey = '(>")>#'; + let include = "1"; + let lookup = new Lookup(smartyKey, include); + let expectedParameters = { + include: include, + }; + + client.sendGeo(lookup); + + expect(mockSender.request.parameters).to.deep.equal(expectedParameters); + }); + + it("correctly builds parameters for a smartyKey only secondary lookup.", function () { + let mockSender = new MockSender(); + let client = new Client(mockSender); + let smartyKey = '(>")>#'; + let include = "1"; + let lookup = new Lookup(smartyKey, include); + let expectedParameters = { + include: include, + }; + + client.sendSecondary(lookup); + + expect(mockSender.request.parameters).to.deep.equal(expectedParameters); + }); + + it("correctly builds parameters for a smartyKey only secondary count lookup.", function () { + let mockSender = new MockSender(); + let client = new Client(mockSender); + let smartyKey = '(>")>#'; + let include = "1"; + let lookup = new Lookup(smartyKey, include); + let expectedParameters = { + include: include, + }; + + client.sendSecondaryCount(lookup); + + expect(mockSender.request.parameters).to.deep.equal(expectedParameters); + }); + + it("correctly builds parameters for a fully-populated principal lookup.", function () { + let mockSender = new MockSender(); + let client = new Client(mockSender); + let lookup = new Lookup("0", "1", "2", "3", "4"); + + let expectedParameters = { + include: "1", + exclude: "2", + dataset: "3", + data_subset: "4", + }; + + client.sendPrincipal(lookup); + expect(mockSender.request.parameters).to.deep.equal(expectedParameters); + }); + + it("correctly builds parameters for a fully-populated financial lookup.", function () { + let mockSender = new MockSender(); + let client = new Client(mockSender); + let lookup = new Lookup("0", "1", "2", "3", "4"); + + let expectedParameters = { + include: "1", + exclude: "2", + dataset: "3", + data_subset: "4", + }; + + client.sendFinancial(lookup); + expect(mockSender.request.parameters).to.deep.equal(expectedParameters); + }); + + it("correctly builds parameters for a fully-populated geo lookup.", function () { + let mockSender = new MockSender(); + let client = new Client(mockSender); + let lookup = new Lookup("0", "1", "2", "3", "4"); + + let expectedParameters = { + include: "1", + exclude: "2", + dataset: "3", + data_subset: "4", + }; + + client.sendGeo(lookup); + expect(mockSender.request.parameters).to.deep.equal(expectedParameters); + }); + + it("correctly builds parameters for a fully-populated secondary lookup.", function () { + let mockSender = new MockSender(); + let client = new Client(mockSender); + let lookup = new Lookup("0", "1", "2", "3", "4"); + + let expectedParameters = { + include: "1", + exclude: "2", + dataset: "3", + data_subset: "4", + }; + + client.sendSecondary(lookup); + expect(mockSender.request.parameters).to.deep.equal(expectedParameters); + }); + + it("correctly builds parameters for a fully-populated secondary count lookup.", function () { + let mockSender = new MockSender(); + let client = new Client(mockSender); + let lookup = new Lookup("0", "1", "2", "3", "4"); + + let expectedParameters = { + include: "1", + exclude: "2", + dataset: "3", + data_subset: "4", + }; + + client.sendSecondaryCount(lookup); + expect(mockSender.request.parameters).to.deep.equal(expectedParameters); + }); + + it("throws an error if sending without a principal lookup.", function () { + let mockSender = new MockSender(); + let client = new Client(mockSender); + expect(client.sendPrincipal).to.throw(errors.UndefinedLookupError); + }); + + it("throws an error if sending without a financial lookup.", function () { + let mockSender = new MockSender(); + let client = new Client(mockSender); + expect(client.sendFinancial).to.throw(errors.UndefinedLookupError); + }); + + it("throws an error if sending without a geo lookup.", function () { + let mockSender = new MockSender(); + let client = new Client(mockSender); + expect(client.sendGeo).to.throw(errors.UndefinedLookupError); + }); + + it("throws an error if sending without a secondary lookup.", function () { + let mockSender = new MockSender(); + let client = new Client(mockSender); + expect(client.sendSecondary).to.throw(errors.UndefinedLookupError); + }); + + it("throws an error if sending without a secondary count lookup.", function () { + let mockSender = new MockSender(); + let client = new Client(mockSender); + expect(client.sendSecondaryCount).to.throw(errors.UndefinedLookupError); + }); + + it("rejects with an exception if the principal response comes back with an error.", function () { + let expectedError = new Error("I'm the error."); + let mockSender = new MockSenderWithResponse("", expectedError); + let client = new Client(mockSender); + let lookup = new Lookup("¯\\_(ツ)_/¯"); + + return client.sendPrincipal(lookup).catch((e) => { + expect(e).to.equal(expectedError); + }); + }); + + it("rejects with an exception if the financial response comes back with an error.", function () { + let expectedError = new Error("I'm the error."); + let mockSender = new MockSenderWithResponse("", expectedError); + let client = new Client(mockSender); + let lookup = new Lookup("¯\\_(ツ)_/¯"); + + return client.sendFinancial(lookup).catch((e) => { + expect(e).to.equal(expectedError); + }); + }); + + it("rejects with an exception if the geo response comes back with an error.", function () { + let expectedError = new Error("I'm the error."); + let mockSender = new MockSenderWithResponse("", expectedError); + let client = new Client(mockSender); + let lookup = new Lookup("¯\\_(ツ)_/¯"); + + return client.sendGeo(lookup).catch((e) => { + expect(e).to.equal(expectedError); + }); + }); + + it("rejects with an exception if the secondary response comes back with an error.", function () { + let expectedError = new Error("I'm the error."); + let mockSender = new MockSenderWithResponse("", expectedError); + let client = new Client(mockSender); + let lookup = new Lookup("¯\\_(ツ)_/¯"); + + return client.sendSecondary(lookup).catch((e) => { + expect(e).to.equal(expectedError); + }); + }); + + it("rejects with an exception if the secondary count response comes back with an error.", function () { + let expectedError = new Error("I'm the error."); + let mockSender = new MockSenderWithResponse("", expectedError); + let client = new Client(mockSender); + let lookup = new Lookup("¯\\_(ツ)_/¯"); + + return client.sendSecondaryCount(lookup).catch((e) => { + expect(e).to.equal(expectedError); + }); + }); + + it("returns an empty array when no principal respo are returned.", () => { + let mockSender = new MockSenderWithResponse({}); + let client = new Client(mockSender); + let lookup = new Lookup("smartyKey"); + + return client.sendPrincipal(lookup).then((response) => { + expect(lookup.response).to.deep.equal({}); + }); + }); + + it("returns an empty array when no financial suggestions are returned.", () => { + let mockSender = new MockSenderWithResponse({}); + let client = new Client(mockSender); + let lookup = new Lookup("smartyKey"); + + return client.sendFinancial(lookup).then((response) => { + expect(lookup.response).to.deep.equal({}); + }); + }); + + it("returns an empty array when no geo suggestions are returned.", () => { + let mockSender = new MockSenderWithResponse({}); + let client = new Client(mockSender); + let lookup = new Lookup("smartyKey"); + + return client.sendGeo(lookup).then((response) => { + expect(lookup.response).to.deep.equal({}); + }); + }); + + it("returns an empty array when no secondary suggestions are returned.", () => { + let mockSender = new MockSenderWithResponse({}); + let client = new Client(mockSender); + let lookup = new Lookup("smartyKey"); + + return client.sendSecondary(lookup).then((response) => { + expect(lookup.response).to.deep.equal({}); + }); + }); + + it("returns an empty array when no secondary count suggestions are returned.", () => { + let mockSender = new MockSenderWithResponse({}); + let client = new Client(mockSender); + let lookup = new Lookup("smartyKey"); + + return client.sendSecondaryCount(lookup).then((response) => { + expect(lookup.response).to.deep.equal({}); + }); + }); + + it("attaches response to a principal lookup.", function () { + const rawMockResponse = { + smarty_key: "a", + data_set_name: "b", + data_subset_name: "c", + attributes: { + assessed_improvement_percent: "1", + }, + }; + let mockResponse = new Response(rawMockResponse); + + let mockSender = new MockSenderWithResponse(mockResponse); + let client = new Client(mockSender); + let lookup = new Lookup("smartyKey"); + + return client.sendPrincipal(lookup).then((response) => { + expect(lookup.response).to.deep.equal(mockResponse); + }); + }); + + it("attaches response to a financial lookup.", function () { + const rawMockResponse = { + smarty_key: "a", + data_set_name: "b", + data_subset_name: "c", + attributes: { + assessed_improvement_percent: "1", + }, + }; + let mockResponse = new FinancialResponse(rawMockResponse); + + let mockSender = new MockSenderWithResponse(mockResponse); + let client = new Client(mockSender); + let lookup = new Lookup("smartyKey"); + + return client.sendFinancial(lookup).then((response) => { + expect(lookup.response).to.deep.equal(mockResponse); + }); + }); + + it("attaches response to a geo lookup.", function () { + const rawMockResponse = { + smarty_key: "a", + data_set_name: "b", + data_subset_name: "c", + attributes: { + assessed_improvement_percent: "1", + }, + }; + let mockResponse = new GeoResponse(rawMockResponse); + + let mockSender = new MockSenderWithResponse(mockResponse); + let client = new Client(mockSender); + let lookup = new Lookup("smartyKey"); + + return client.sendGeo(lookup).then((response) => { + expect(lookup.response).to.deep.equal(mockResponse); + }); + }); + + it("attaches response to a secondary lookup.", function () { + const rawMockResponse = { + smarty_key: "a", + data_set_name: "b", + data_subset_name: "c", + attributes: { + assessed_improvement_percent: "1", + }, + }; + let mockResponse = new Response(rawMockResponse); + + let mockSender = new MockSenderWithResponse(mockResponse); + let client = new Client(mockSender); + let lookup = new Lookup("smartyKey"); + + return client.sendSecondary(lookup).then((response) => { + expect(lookup.response).to.deep.equal(mockResponse); + }); + }); + + it("attaches response to a secondary count lookup.", function () { + const rawMockResponse = { + smarty_key: "a", + data_set_name: "b", + data_subset_name: "c", + attributes: { + assessed_improvement_percent: "1", + }, + }; + let mockResponse = new Response(rawMockResponse); + + let mockSender = new MockSenderWithResponse(mockResponse); + let client = new Client(mockSender); + let lookup = new Lookup("smartyKey"); + + return client.sendSecondaryCount(lookup).then((response) => { + expect(lookup.response).to.deep.equal(mockResponse); + }); + }); }); diff --git a/tests/us_enrichment/test_Lookup.js b/tests/us_enrichment/test_Lookup.js index 419c944..6f860ce 100644 --- a/tests/us_enrichment/test_Lookup.js +++ b/tests/us_enrichment/test_Lookup.js @@ -26,4 +26,4 @@ describe("A US Enrichment Lookup", function () { expect(lookup.dataSubset).to.equal(expectedDataSubset); expect(lookup.features).to.equal(expectedFeatures); }); -}); \ No newline at end of file +}); diff --git a/tests/us_enrichment/test_Response.js b/tests/us_enrichment/test_Response.js index 0c4b549..b665a7a 100644 --- a/tests/us_enrichment/test_Response.js +++ b/tests/us_enrichment/test_Response.js @@ -1,739 +1,739 @@ const chai = require("chai"); const expect = chai.expect; -const {Response} = require("../../src/us_enrichment/Response.js"); +const { Response } = require("../../src/us_enrichment/Response.js"); describe("A US Enrichment Response", function () { - it("is initialized correctly with API response data.", function () { - const mockResponse = { - smarty_key: "a", - data_set_name: "b", - data_subset_name: "c", - attributes: { - "1st_floor_sqft": "01", - "2nd_floor_sqft": "02", - acres: "0", - address_info_privacy: "1", - air_conditioner: "2", - arbor_pergola: "3", - assessed_improvement_percent: "4", - assessed_improvement_value: "5", - assessed_land_value: "6", - assessed_value: "7", - assessor_last_update: "8", - assessor_taxroll_update: "9", - attic_area: "10", - attic_flag: "11", - balcony: "12", - balcony_area: "13", - basement_sqft: "14", - basement_sqft_finished: "15", - basement_sqft_unfinished: "16", - bath_house: "17", - bath_house_sqft: "18", - bathrooms_partial: "19", - bathrooms_total: "20", - bedrooms: "21", - block_1: "22", - block_2: "23", - boat_access: "24", - boat_house: "25", - boat_house_sqft: "26", - boat_lift: "27", - bonus_room: "28", - breakfast_nook: "29", - breezeway: "30", - building_definition: "31", - building_sqft: "32", - cabin: "33", - cabin_sqft: "34", - canopy: "35", - canopy_sqft: "36", - carport: "37", - carport_sqft: "38", - cbsa_code: "39", - cbsa_name: "40", - cellar: "41", - census_block: "42", - census_block_group: "43", - census_fips_place_code: "44", - census_tract: "45", - central_vacuum: "46", - code_title_company: "47", - combined_statistical_area: "48", - community_rec: "49", - company_flag: "50", - congressional_district: "51", - construction_type: "52", - contact_city: "53", - contact_crrt: "54", - contact_full_address: "55", - contact_house_number: "56", - contact_main_info_format: "57", - contact_mail_info_privacy: "58", - contact_mailing_county: "59", - contact_mailing_fips: "60", - contact_post_direction: "61", - contact_pre_direction: "62", - contact_state: "63", - contact_street_name: "64", - contact_suffix: "65", - contact_unit_designator: "66", - contact_value: "67", - contact_zip: "68", - contact_zip4: "69", - courtyard: "70", - courtyard_area: "71", - deck: "72", - deck_area: "73", - deed_document_page: "74", - deed_document_book: "75", - deed_document_number: "76", - deed_owner_first_name: "77", - deed_owner_first_name2: "78", - deed_owner_first_name3: "79", - deed_owner_first_name4: "80", - deed_owner_full_name: "81", - deed_owner_full_name2: "82", - deed_owner_full_name3: "83", - deed_owner_full_name4: "84", - deed_owner_last_name: "85", - deed_owner_last_name2: "86", - deed_owner_last_name3: "87", - deed_owner_last_name4: "88", - deed_owner_middle_name: "89", - deed_owner_middle_name2: "90", - deed_owner_middle_name3: "91", - deed_owner_middle_name4: "92", - deed_owner_suffix: "93", - deed_owner_suffix2: "94", - deed_owner_suffix3: "95", - deed_owner_suffix4: "96", - deed_sale_date: "97", - deed_sale_price: "98", - deed_transaction_id: "99", - depth_linear_footage: "100", - disabled_tax_exemption: "101", - driveway_sqft: "102", - driveway_type: "103", - effective_year_built: "104", - elevation_feet: "105", - elevator: "106", - equestrian_arena: "107", - escalator: "108", - exercise_room: "109", - exterior_walls: "110", - family_room: "111", - fence: "112", - fence_area: "113", - fips_code: "114", - fire_resistance_code: "115", - fire_sprinkler_flag: "116", - fireplace: "117", - fireplace_number: "118", - first_name: "119", - first_name2: "120", - first_name3: "121", - first_name4: "122", - flooring: "123", - foundation: "124", - game_room: "125", - garage: "126", - garage_sqft: "127", - gazebo: "128", - gazebo_sqft: "129", - golf_course: "130", - grainery: "131", - grainery_sqft: "132", - great_room: "133", - greenhouse: "134", - greenhouse_sqft: "135", - gross_sqft: "136", - guesthouse: "137", - guesthouse_sqft: "138", - handicap_accessibility: "139", - heat: "140", - heat_fuel_type: "141", - hobby_room: "142", - homeowner_tax_exemption: "143", - instrument_date: "144", - intercom_system: "145", - interest_rate_type_2: "146", - interior_structure: "147", - kennel: "148", - kennel_sqft: "149", - land_use_code: "150", - land_use_group: "151", - land_use_standard: "152", - last_name: "153", - last_name_2: "154", - last_name_3: "155", - last_name_4: "156", - latitude: "157", - laundry: "158", - lean_to: "159", - lean_to_sqft: "160", - legal_description: "161", - legal_unit: "162", - lender_address: "163", - lender_address_2: "164", - lender_city: "165", - lender_city_2: "166", - lender_code: "167", - lender_code_2: "168", - lender_first_name: "169", - lender_first_name_2: "170", - lender_last_name: "171", - lender_last_name_2: "172", - lender_name: "173", - lender_name_2: "174", - lender_seller_carry_back: "175", - lender_seller_carry_back_2: "176", - lender_state: "177", - lender_state_2: "178", - lender_zip: "179", - lender_zip_2: "180", - lender_zip_extended: "181", - lender_zip_extended_2: "182", - loading_platform: "183", - loading_platform_sqft: "184", - longitude: "185", - lot_1: "186", - lot_2: "187", - lot_3: "188", - lot_sqft: "189", - market_improvement_percent: "190", - market_improvement_value: "191", - market_land_value: "192", - market_value_year: "193", - match_type: "194", - media_room: "195", - metro_division: "196", - middle_name: "197", - middle_name_2: "198", - middle_name_3: "199", - middle_name_4: "200", - milkhouse: "201", - milkhouse_sqft: "202", - minor_civil_division_code: "203", - minor_civil_division_name: "204", - mobile_home_hookup: "205", - mortgage_amount: "206", - mortgage_amount_2: "207", - mortgage_due_date: "208", - mortgage_due_date_2: "209", - mortgage_interest_rate: "210", - mortgage_interest_rate_type: "211", - mortgage_lender_code: "212", - mortgage_rate_2: "213", - mortgage_recording_date: "214", - mortgage_recording_date_2: "215", - mortgage_term: "216", - mortgage_term_2: "217", - mortgage_term_type: "218", - mortgage_term_type_2: "219", - mortgage_type: "220", - mortgage_type_2: "221", - msa_code: "222", - msa_name: "223", - mud_room: "224", - multi_parcel_flag: "225", - name_title_company: "226", - neighborhood_code: "227", - number_of_buildings: "228", - office: "229", - office_sqft: "230", - other_tax_exemption: "231", - outdoor_kitchen_fireplace: "232", - overhead_door: "233", - owner_full_name: "234", - owner_full_name_2: "235", - owner_full_name_3: "236", - owner_full_name_4: "237", - owner_occupancy_status: "238", - ownership_transfer_date: "239", - ownership_transfer_doc_number: "240", - ownership_transfer_transaction_id: "241", - ownership_type: "242", - ownership_type_2: "243", - ownership_vesting_relation_code: "244", - parcel_account_number: "245", - parcel_map_book: "246", - parcel_map_page: "247", - parcel_number_alternate: "248", - parcel_number_formatted: "249", - parcel_number_previous: "250", - parcel_number_year_added: "251", - parcel_number_year_change: "252", - parcel_raw_number: "253", - parcel_shell_record: "254", - parking_spaces: "255", - patio_area: "256", - phase_name: "257", - plumbing_fixtures_count: "257", - pole_struct: "258", - pole_struct_sqft: "259", - pond: "260", - pool: "261", - pool_area: "262", - poolhouse: "263", - poolhouse_sqft: "264", - porch: "265", - porch_area: "266", - poultry_house: "267", - poultry_house_sqft: "268", - previous_assessed_value: "269", - prior_sale_amount: "270", - prior_sale_date: "271", - property_address_carrier_route_code: "272", - property_address_city: "273", - property_address_full: "274", - property_address_house_number: "275", - property_address_post_direction: "276", - property_address_pre_direction: "277", - property_address_state: "278", - property_address_street_name: "279", - property_address_street_suffix: "280", - property_address_unit_designator: "281", - property_address_unit_value: "282", - property_address_zip_4: "283", - property_address_zipcode: "284", - publication_date: "285", - quarter: "286", - quarter_quarter: "287", - quonset: "288", - quonset_sqft: "289", - range: "290", - recording_date: "291", - roof_cover: "292", - roof_frame: "293", - rooms: "294", - rv_parking: "295", - safe_room: "296", - sale_amount: "297", - sale_date: "298", - sauna: "299", - section: "300", - security_alarm: "301", - senior_tax_exemption: "302", - sewer_type: "303", - shed: "304", - shed_sqft: "305", - silo: "306", - silo_sqft: "307", - sitting_room: "308", - situs_county: "309", - situs_state: "310", - sound_system: "311", - sports_court: "312", - sprinklers: "313", - stable: "314", - stable_sqft: "315", - storage_building: "316", - storage_buildling_sqft: "317", - stories_number: "318", - storm_shelter: "319", - storm_shutter: "320", - structure_style: "321", - study: "322", - subdivision: "323", - suffix: "324", - suffix_2: "325", - suffix_3: "326", - suffix_4: "327", - sunroom: "328", - tax_assess_year: "329", - tax_billed_amount: "330", - tax_delinquent_year: "331", - tax_fiscal_year: "332", - tax_jurisdiction: "333", - tax_rate_area: "334", - tennis_court: "335", - topography_code: "336", - total_market_value: "337", - township: "338", - tract_number: "339", - transfer_amount: "340", - trust_description: "341", - unit_count: "342", - upper_floors_sqft: "343", - utility: "344", - utility_building: "345", - utility_building_sqft: "346", - utility_sqft: "347", - veteran_tax_exemption: "348", - view_description: "349", - water_feature: "350", - water_service_type: "351", - wet_bar: "352", - widow_tax_exemption: "353", - width_linear_footage: "354", - wine_cellar: "355", - year_built: "356", - zoning: "357", - }, - }; - let response = new Response(mockResponse); + it("is initialized correctly with API response data.", function () { + const mockResponse = { + smarty_key: "a", + data_set_name: "b", + data_subset_name: "c", + attributes: { + "1st_floor_sqft": "01", + "2nd_floor_sqft": "02", + acres: "0", + address_info_privacy: "1", + air_conditioner: "2", + arbor_pergola: "3", + assessed_improvement_percent: "4", + assessed_improvement_value: "5", + assessed_land_value: "6", + assessed_value: "7", + assessor_last_update: "8", + assessor_taxroll_update: "9", + attic_area: "10", + attic_flag: "11", + balcony: "12", + balcony_area: "13", + basement_sqft: "14", + basement_sqft_finished: "15", + basement_sqft_unfinished: "16", + bath_house: "17", + bath_house_sqft: "18", + bathrooms_partial: "19", + bathrooms_total: "20", + bedrooms: "21", + block_1: "22", + block_2: "23", + boat_access: "24", + boat_house: "25", + boat_house_sqft: "26", + boat_lift: "27", + bonus_room: "28", + breakfast_nook: "29", + breezeway: "30", + building_definition: "31", + building_sqft: "32", + cabin: "33", + cabin_sqft: "34", + canopy: "35", + canopy_sqft: "36", + carport: "37", + carport_sqft: "38", + cbsa_code: "39", + cbsa_name: "40", + cellar: "41", + census_block: "42", + census_block_group: "43", + census_fips_place_code: "44", + census_tract: "45", + central_vacuum: "46", + code_title_company: "47", + combined_statistical_area: "48", + community_rec: "49", + company_flag: "50", + congressional_district: "51", + construction_type: "52", + contact_city: "53", + contact_crrt: "54", + contact_full_address: "55", + contact_house_number: "56", + contact_main_info_format: "57", + contact_mail_info_privacy: "58", + contact_mailing_county: "59", + contact_mailing_fips: "60", + contact_post_direction: "61", + contact_pre_direction: "62", + contact_state: "63", + contact_street_name: "64", + contact_suffix: "65", + contact_unit_designator: "66", + contact_value: "67", + contact_zip: "68", + contact_zip4: "69", + courtyard: "70", + courtyard_area: "71", + deck: "72", + deck_area: "73", + deed_document_page: "74", + deed_document_book: "75", + deed_document_number: "76", + deed_owner_first_name: "77", + deed_owner_first_name2: "78", + deed_owner_first_name3: "79", + deed_owner_first_name4: "80", + deed_owner_full_name: "81", + deed_owner_full_name2: "82", + deed_owner_full_name3: "83", + deed_owner_full_name4: "84", + deed_owner_last_name: "85", + deed_owner_last_name2: "86", + deed_owner_last_name3: "87", + deed_owner_last_name4: "88", + deed_owner_middle_name: "89", + deed_owner_middle_name2: "90", + deed_owner_middle_name3: "91", + deed_owner_middle_name4: "92", + deed_owner_suffix: "93", + deed_owner_suffix2: "94", + deed_owner_suffix3: "95", + deed_owner_suffix4: "96", + deed_sale_date: "97", + deed_sale_price: "98", + deed_transaction_id: "99", + depth_linear_footage: "100", + disabled_tax_exemption: "101", + driveway_sqft: "102", + driveway_type: "103", + effective_year_built: "104", + elevation_feet: "105", + elevator: "106", + equestrian_arena: "107", + escalator: "108", + exercise_room: "109", + exterior_walls: "110", + family_room: "111", + fence: "112", + fence_area: "113", + fips_code: "114", + fire_resistance_code: "115", + fire_sprinkler_flag: "116", + fireplace: "117", + fireplace_number: "118", + first_name: "119", + first_name2: "120", + first_name3: "121", + first_name4: "122", + flooring: "123", + foundation: "124", + game_room: "125", + garage: "126", + garage_sqft: "127", + gazebo: "128", + gazebo_sqft: "129", + golf_course: "130", + grainery: "131", + grainery_sqft: "132", + great_room: "133", + greenhouse: "134", + greenhouse_sqft: "135", + gross_sqft: "136", + guesthouse: "137", + guesthouse_sqft: "138", + handicap_accessibility: "139", + heat: "140", + heat_fuel_type: "141", + hobby_room: "142", + homeowner_tax_exemption: "143", + instrument_date: "144", + intercom_system: "145", + interest_rate_type_2: "146", + interior_structure: "147", + kennel: "148", + kennel_sqft: "149", + land_use_code: "150", + land_use_group: "151", + land_use_standard: "152", + last_name: "153", + last_name_2: "154", + last_name_3: "155", + last_name_4: "156", + latitude: "157", + laundry: "158", + lean_to: "159", + lean_to_sqft: "160", + legal_description: "161", + legal_unit: "162", + lender_address: "163", + lender_address_2: "164", + lender_city: "165", + lender_city_2: "166", + lender_code: "167", + lender_code_2: "168", + lender_first_name: "169", + lender_first_name_2: "170", + lender_last_name: "171", + lender_last_name_2: "172", + lender_name: "173", + lender_name_2: "174", + lender_seller_carry_back: "175", + lender_seller_carry_back_2: "176", + lender_state: "177", + lender_state_2: "178", + lender_zip: "179", + lender_zip_2: "180", + lender_zip_extended: "181", + lender_zip_extended_2: "182", + loading_platform: "183", + loading_platform_sqft: "184", + longitude: "185", + lot_1: "186", + lot_2: "187", + lot_3: "188", + lot_sqft: "189", + market_improvement_percent: "190", + market_improvement_value: "191", + market_land_value: "192", + market_value_year: "193", + match_type: "194", + media_room: "195", + metro_division: "196", + middle_name: "197", + middle_name_2: "198", + middle_name_3: "199", + middle_name_4: "200", + milkhouse: "201", + milkhouse_sqft: "202", + minor_civil_division_code: "203", + minor_civil_division_name: "204", + mobile_home_hookup: "205", + mortgage_amount: "206", + mortgage_amount_2: "207", + mortgage_due_date: "208", + mortgage_due_date_2: "209", + mortgage_interest_rate: "210", + mortgage_interest_rate_type: "211", + mortgage_lender_code: "212", + mortgage_rate_2: "213", + mortgage_recording_date: "214", + mortgage_recording_date_2: "215", + mortgage_term: "216", + mortgage_term_2: "217", + mortgage_term_type: "218", + mortgage_term_type_2: "219", + mortgage_type: "220", + mortgage_type_2: "221", + msa_code: "222", + msa_name: "223", + mud_room: "224", + multi_parcel_flag: "225", + name_title_company: "226", + neighborhood_code: "227", + number_of_buildings: "228", + office: "229", + office_sqft: "230", + other_tax_exemption: "231", + outdoor_kitchen_fireplace: "232", + overhead_door: "233", + owner_full_name: "234", + owner_full_name_2: "235", + owner_full_name_3: "236", + owner_full_name_4: "237", + owner_occupancy_status: "238", + ownership_transfer_date: "239", + ownership_transfer_doc_number: "240", + ownership_transfer_transaction_id: "241", + ownership_type: "242", + ownership_type_2: "243", + ownership_vesting_relation_code: "244", + parcel_account_number: "245", + parcel_map_book: "246", + parcel_map_page: "247", + parcel_number_alternate: "248", + parcel_number_formatted: "249", + parcel_number_previous: "250", + parcel_number_year_added: "251", + parcel_number_year_change: "252", + parcel_raw_number: "253", + parcel_shell_record: "254", + parking_spaces: "255", + patio_area: "256", + phase_name: "257", + plumbing_fixtures_count: "257", + pole_struct: "258", + pole_struct_sqft: "259", + pond: "260", + pool: "261", + pool_area: "262", + poolhouse: "263", + poolhouse_sqft: "264", + porch: "265", + porch_area: "266", + poultry_house: "267", + poultry_house_sqft: "268", + previous_assessed_value: "269", + prior_sale_amount: "270", + prior_sale_date: "271", + property_address_carrier_route_code: "272", + property_address_city: "273", + property_address_full: "274", + property_address_house_number: "275", + property_address_post_direction: "276", + property_address_pre_direction: "277", + property_address_state: "278", + property_address_street_name: "279", + property_address_street_suffix: "280", + property_address_unit_designator: "281", + property_address_unit_value: "282", + property_address_zip_4: "283", + property_address_zipcode: "284", + publication_date: "285", + quarter: "286", + quarter_quarter: "287", + quonset: "288", + quonset_sqft: "289", + range: "290", + recording_date: "291", + roof_cover: "292", + roof_frame: "293", + rooms: "294", + rv_parking: "295", + safe_room: "296", + sale_amount: "297", + sale_date: "298", + sauna: "299", + section: "300", + security_alarm: "301", + senior_tax_exemption: "302", + sewer_type: "303", + shed: "304", + shed_sqft: "305", + silo: "306", + silo_sqft: "307", + sitting_room: "308", + situs_county: "309", + situs_state: "310", + sound_system: "311", + sports_court: "312", + sprinklers: "313", + stable: "314", + stable_sqft: "315", + storage_building: "316", + storage_buildling_sqft: "317", + stories_number: "318", + storm_shelter: "319", + storm_shutter: "320", + structure_style: "321", + study: "322", + subdivision: "323", + suffix: "324", + suffix_2: "325", + suffix_3: "326", + suffix_4: "327", + sunroom: "328", + tax_assess_year: "329", + tax_billed_amount: "330", + tax_delinquent_year: "331", + tax_fiscal_year: "332", + tax_jurisdiction: "333", + tax_rate_area: "334", + tennis_court: "335", + topography_code: "336", + total_market_value: "337", + township: "338", + tract_number: "339", + transfer_amount: "340", + trust_description: "341", + unit_count: "342", + upper_floors_sqft: "343", + utility: "344", + utility_building: "345", + utility_building_sqft: "346", + utility_sqft: "347", + veteran_tax_exemption: "348", + view_description: "349", + water_feature: "350", + water_service_type: "351", + wet_bar: "352", + widow_tax_exemption: "353", + width_linear_footage: "354", + wine_cellar: "355", + year_built: "356", + zoning: "357", + }, + }; + let response = new Response(mockResponse); - expect(response.attributes.firstFloorSqft).to.equal("01"); - expect(response.attributes.secondFlootSqft).to.equal("02"); - expect(response.attributes.acres).to.equal("0"); - expect(response.attributes.addressInfoPrivacy).to.equal("1"); - expect(response.attributes.airConditioner).to.equal("2"); - expect(response.attributes.arborPergola).to.equal("3"); - expect(response.attributes.assessedImprovementPercent).to.equal("4"); - expect(response.attributes.assessedImprovementValue).to.equal("5"); - expect(response.attributes.assessedLandValue).to.equal("6"); - expect(response.attributes.assessedValue).to.equal("7"); - expect(response.attributes.assessorLastUpdate).to.equal("8"); - expect(response.attributes.assessorTaxrollUpdate).to.equal("9"); - expect(response.attributes.atticArea).to.equal("10"); - expect(response.attributes.atticFlag).to.equal("11"); - expect(response.attributes.balcony).to.equal("12"); - expect(response.attributes.balconyArea).to.equal("13"); - expect(response.attributes.basementSqft).to.equal("14"); - expect(response.attributes.basementSqftFinished).to.equal("15"); - expect(response.attributes.basementsqftUnfinished).to.equal("16"); - expect(response.attributes.bathHouse).to.equal("17"); - expect(response.attributes.bathHouseSqft).to.equal("18"); - expect(response.attributes.bathroomsPartial).to.equal("19"); - expect(response.attributes.bathroomsTotal).to.equal("20"); - expect(response.attributes.bedrooms).to.equal("21"); - expect(response.attributes.block1).to.equal("22"); - expect(response.attributes.block2).to.equal("23"); - expect(response.attributes.boatAccess).to.equal("24"); - expect(response.attributes.boatHouse).to.equal("25"); - expect(response.attributes.boatHouseSqft).to.equal("26"); - expect(response.attributes.boatLift).to.equal("27"); - expect(response.attributes.bonusRoom).to.equal("28"); - expect(response.attributes.breakfastNook).to.equal("29"); - expect(response.attributes.breezeway).to.equal("30"); - expect(response.attributes.buildingDefinitionCode).to.equal("31"); - expect(response.attributes.buildingSqft).to.equal("32"); - expect(response.attributes.cabin).to.equal("33"); - expect(response.attributes.cabinSqft).to.equal("34"); - expect(response.attributes.canopy).to.equal("35"); - expect(response.attributes.canopySqft).to.equal("36"); - expect(response.attributes.carport).to.equal("37"); - expect(response.attributes.carportSqft).to.equal("38"); - expect(response.attributes.cbsaCode).to.equal("39"); - expect(response.attributes.cbsaName).to.equal("40"); - expect(response.attributes.cellar).to.equal("41"); - expect(response.attributes.censusBlock).to.equal("42"); - expect(response.attributes.censusBlockGroup).to.equal("43"); - expect(response.attributes.censusFipsPlaceCode).to.equal("44"); - expect(response.attributes.censusTract).to.equal("45"); - expect(response.attributes.centralVacuum).to.equal("46"); - expect(response.attributes.codeTitleCompany).to.equal("47"); - expect(response.attributes.combinedStatisticalArea).to.equal("48"); - expect(response.attributes.communityRec).to.equal("49"); - expect(response.attributes.companyFlag).to.equal("50"); - expect(response.attributes.congressionalDistrict).to.equal("51"); - expect(response.attributes.constructionType).to.equal("52"); - expect(response.attributes.contactCity).to.equal("53"); - expect(response.attributes.contactCrrt).to.equal("54"); - expect(response.attributes.contactFullAddress).to.equal("55"); - expect(response.attributes.contactHouseNumber).to.equal("56"); - expect(response.attributes.contactMailInfoFormat).to.equal("57"); - expect(response.attributes.contactMailInfoPrivacy).to.equal("58"); - expect(response.attributes.contactMailingCounty).to.equal("59"); - expect(response.attributes.contactMailingFips).to.equal("60"); - expect(response.attributes.contactPostDirection).to.equal("61"); - expect(response.attributes.contactPreDirection).to.equal("62"); - expect(response.attributes.contactState).to.equal("63"); - expect(response.attributes.contactStreetName).to.equal("64"); - expect(response.attributes.contactSuffix).to.equal("65"); - expect(response.attributes.contactUnitDesignator).to.equal("66"); - expect(response.attributes.contactValue).to.equal("67"); - expect(response.attributes.contactZip).to.equal("68"); - expect(response.attributes.contactZip4).to.equal("69"); - expect(response.attributes.courtyard).to.equal("70"); - expect(response.attributes.courtyardArea).to.equal("71"); - expect(response.attributes.deck).to.equal("72"); - expect(response.attributes.deckArea).to.equal("73"); - expect(response.attributes.deedDocumentPage).to.equal("74"); - expect(response.attributes.deedDocumentBook).to.equal("75"); - expect(response.attributes.deedDocumentNumber).to.equal("76"); - expect(response.attributes.deedOwnerFirstName).to.equal("77"); - expect(response.attributes.deedOwnerFirstName2).to.equal("78"); - expect(response.attributes.deedOwnerFirstName3).to.equal("79"); - expect(response.attributes.deedOwnerFirstName4).to.equal("80"); - expect(response.attributes.deedOwnerFullName).to.equal("81"); - expect(response.attributes.deedOwnerFullName2).to.equal("82"); - expect(response.attributes.deedOwnerFullName3).to.equal("83"); - expect(response.attributes.deedOwnerFullName4).to.equal("84"); - expect(response.attributes.deedOwnerLastName).to.equal("85"); - expect(response.attributes.deedOwnerLastName2).to.equal("86"); - expect(response.attributes.deedOwnerLastName3).to.equal("87"); - expect(response.attributes.deedOwnerLastName4).to.equal("88"); - expect(response.attributes.deedOwnerMiddleName).to.equal("89"); - expect(response.attributes.deedOwnerMiddleName2).to.equal("90"); - expect(response.attributes.deedOwnerMiddleName3).to.equal("91"); - expect(response.attributes.deedOwnerMiddleName4).to.equal("92"); - expect(response.attributes.deedOwnerSuffix).to.equal("93"); - expect(response.attributes.deedOwnerSuffix2).to.equal("94"); - expect(response.attributes.deedOwnerSuffix3).to.equal("95"); - expect(response.attributes.deedOwnerSuffix4).to.equal("96"); - expect(response.attributes.deedSaleDate).to.equal("97"); - expect(response.attributes.deedSalePrice).to.equal("98"); - expect(response.attributes.deedTransactionId).to.equal("99"); - expect(response.attributes.depthLinearFootage).to.equal("100"); - expect(response.attributes.disabledTaxExemption).to.equal("101"); - expect(response.attributes.drivewaySqft).to.equal("102"); - expect(response.attributes.drivewayType).to.equal("103"); - expect(response.attributes.effectiveYearBuilt).to.equal("104"); - expect(response.attributes.elevationFeet).to.equal("105"); - expect(response.attributes.elevator).to.equal("106"); - expect(response.attributes.equestrianArena).to.equal("107"); - expect(response.attributes.escalator).to.equal("108"); - expect(response.attributes.exerciseRoom).to.equal("109"); - expect(response.attributes.exteriorWalls).to.equal("110"); - expect(response.attributes.familyRoom).to.equal("111"); - expect(response.attributes.fence).to.equal("112"); - expect(response.attributes.fenceArea).to.equal("113"); - expect(response.attributes.fipsCode).to.equal("114"); - expect(response.attributes.fireResistanceCode).to.equal("115"); - expect(response.attributes.fireSprinklersFlag).to.equal("116"); - expect(response.attributes.fireplace).to.equal("117"); - expect(response.attributes.fireplaceNumber).to.equal("118"); - expect(response.attributes.firstName).to.equal("119"); - expect(response.attributes.firstName2).to.equal("120"); - expect(response.attributes.firstName3).to.equal("121"); - expect(response.attributes.firstName4).to.equal("122"); - expect(response.attributes.flooring).to.equal("123"); - expect(response.attributes.foundation).to.equal("124"); - expect(response.attributes.gameRoom).to.equal("125"); - expect(response.attributes.garage).to.equal("126"); - expect(response.attributes.garageSqft).to.equal("127"); - expect(response.attributes.gazebo).to.equal("128"); - expect(response.attributes.gazeboSqft).to.equal("129"); - expect(response.attributes.golfCourse).to.equal("130"); - expect(response.attributes.grainery).to.equal("131"); - expect(response.attributes.grainerySqft).to.equal("132"); - expect(response.attributes.greatRoom).to.equal("133"); - expect(response.attributes.greenhouse).to.equal("134"); - expect(response.attributes.greenhouseSqft).to.equal("135"); - expect(response.attributes.grossSqft).to.equal("136"); - expect(response.attributes.guesthouse).to.equal("137"); - expect(response.attributes.guesthouseSqft).to.equal("138"); - expect(response.attributes.handicapAccessibility).to.equal("139"); - expect(response.attributes.heat).to.equal("140"); - expect(response.attributes.heatFuelType).to.equal("141"); - expect(response.attributes.hobbyRoom).to.equal("142"); - expect(response.attributes.homeownerTaxExemption).to.equal("143"); - expect(response.attributes.instrumentDate).to.equal("144"); - expect(response.attributes.intercomSystem).to.equal("145"); - expect(response.attributes.interestRateType2).to.equal("146"); - expect(response.attributes.interiorStructure).to.equal("147"); - expect(response.attributes.kennel).to.equal("148"); - expect(response.attributes.kennelSqft).to.equal("149"); - expect(response.attributes.landUseCode).to.equal("150"); - expect(response.attributes.landUseGroup).to.equal("151"); - expect(response.attributes.landUseStandard).to.equal("152"); - expect(response.attributes.lastName).to.equal("153"); - expect(response.attributes.lastName2).to.equal("154"); - expect(response.attributes.lastName3).to.equal("155"); - expect(response.attributes.lastName4).to.equal("156"); - expect(response.attributes.latitude).to.equal("157"); - expect(response.attributes.laundry).to.equal("158"); - expect(response.attributes.leanTo).to.equal("159"); - expect(response.attributes.leanToSqft).to.equal("160"); - expect(response.attributes.legalDescription).to.equal("161"); - expect(response.attributes.legalUnit).to.equal("162"); - expect(response.attributes.lenderAddress).to.equal("163"); - expect(response.attributes.lenderAddress2).to.equal("164"); - expect(response.attributes.lenderCity).to.equal("165"); - expect(response.attributes.lenderCity2).to.equal("166"); - expect(response.attributes.lenderCode).to.equal("167"); - expect(response.attributes.lenderCode2).to.equal("168"); - expect(response.attributes.lenderFirstName).to.equal("169"); - expect(response.attributes.lenderFirstName2).to.equal("170"); - expect(response.attributes.lenderLastName).to.equal("171"); - expect(response.attributes.lenderLastName2).to.equal("172"); - expect(response.attributes.lenderName).to.equal("173"); - expect(response.attributes.lenderName2).to.equal("174"); - expect(response.attributes.lenderSellerCarryBack).to.equal("175"); - expect(response.attributes.lenderSellerCarryBack2).to.equal("176"); - expect(response.attributes.lenderState).to.equal("177"); - expect(response.attributes.lenderState2).to.equal("178"); - expect(response.attributes.lenderZip).to.equal("179"); - expect(response.attributes.lenderZip2).to.equal("180"); - expect(response.attributes.lenderZipExtended).to.equal("181"); - expect(response.attributes.lenderZipExtended2).to.equal("182"); - expect(response.attributes.loadingPlatform).to.equal("183"); - expect(response.attributes.loadingPlatformSqft).to.equal("184"); - expect(response.attributes.longitude).to.equal("185"); - expect(response.attributes.lot1).to.equal("186"); - expect(response.attributes.lot2).to.equal("187"); - expect(response.attributes.lot3).to.equal("188"); - expect(response.attributes.lotSqft).to.equal("189"); - expect(response.attributes.marketImprovementPercent).to.equal("190"); - expect(response.attributes.marketImprovementValue).to.equal("191"); - expect(response.attributes.marketLandValue).to.equal("192"); - expect(response.attributes.marketValueYear).to.equal("193"); - expect(response.attributes.matchType).to.equal("194"); - expect(response.attributes.mediaRoom).to.equal("195"); - expect(response.attributes.metroDivision).to.equal("196"); - expect(response.attributes.middleName).to.equal("197"); - expect(response.attributes.middleName2).to.equal("198"); - expect(response.attributes.middleName3).to.equal("199"); - expect(response.attributes.middleName4).to.equal("200"); - expect(response.attributes.milkhouse).to.equal("201"); - expect(response.attributes.milkhouseSqft).to.equal("202"); - expect(response.attributes.minorCivilDivisionCode).to.equal("203"); - expect(response.attributes.minorCivilDivisionName).to.equal("204"); - expect(response.attributes.mobileHomeHookup).to.equal("205"); - expect(response.attributes.mortgageAmount).to.equal("206"); - expect(response.attributes.mortgageAmount2).to.equal("207"); - expect(response.attributes.mortgageDueDate).to.equal("208"); - expect(response.attributes.mortgageDueDate2).to.equal("209"); - expect(response.attributes.mortgageInterestRate).to.equal("210"); - expect(response.attributes.mortgageInterestRateType).to.equal("211"); - expect(response.attributes.mortgageLenderCode).to.equal("212"); - expect(response.attributes.mortgageRate2).to.equal("213"); - expect(response.attributes.mortgageRecordingDate).to.equal("214"); - expect(response.attributes.mortgageRecordingDate2).to.equal("215"); - expect(response.attributes.mortgageTerm).to.equal("216"); - expect(response.attributes.mortgageTerm2).to.equal("217"); - expect(response.attributes.mortgageTermType).to.equal("218"); - expect(response.attributes.mortgageTermType2).to.equal("219"); - expect(response.attributes.mortgageType).to.equal("220"); - expect(response.attributes.mortgageType2).to.equal("221"); - expect(response.attributes.msaCode).to.equal("222"); - expect(response.attributes.msaName).to.equal("223"); - expect(response.attributes.mudRoom).to.equal("224"); - expect(response.attributes.multiParcelFlag).to.equal("225"); - expect(response.attributes.nameTitleCompany).to.equal("226"); - expect(response.attributes.neighborhoodCode).to.equal("227"); - expect(response.attributes.numberOfBuildings).to.equal("228"); - expect(response.attributes.office).to.equal("229"); - expect(response.attributes.officeSqft).to.equal("230"); - expect(response.attributes.otherTaxExemption).to.equal("231"); - expect(response.attributes.outdoorKitchenFireplace).to.equal("232"); - expect(response.attributes.overheadDoor).to.equal("233"); - expect(response.attributes.ownerFullName).to.equal("234"); - expect(response.attributes.ownerFullName2).to.equal("235"); - expect(response.attributes.ownerFullName3).to.equal("236"); - expect(response.attributes.ownerFullName4).to.equal("237"); - expect(response.attributes.ownerOccupancyStatus).to.equal("238"); - expect(response.attributes.ownershipTransferDate).to.equal("239"); - expect(response.attributes.ownershipTransferDocNumber).to.equal("240"); - expect(response.attributes.ownershipTransferTransactionId).to.equal("241"); - expect(response.attributes.ownershipType).to.equal("242"); - expect(response.attributes.ownershipType2).to.equal("243"); - expect(response.attributes.ownershipVestingRelationCode).to.equal("244"); - expect(response.attributes.parcelAccountNumber).to.equal("245"); - expect(response.attributes.parcelMapBook).to.equal("246"); - expect(response.attributes.parcelMapPage).to.equal("247"); - expect(response.attributes.parcelNumberAlternate).to.equal("248"); - expect(response.attributes.parcelNumberFormatted).to.equal("249"); - expect(response.attributes.parcelNumberPrevious).to.equal("250"); - expect(response.attributes.parcelNumberYearAdded).to.equal("251"); - expect(response.attributes.parcelNumberYearChange).to.equal("252"); - expect(response.attributes.parcelRawNumber).to.equal("253"); - expect(response.attributes.parcelShellRecord).to.equal("254"); - expect(response.attributes.parkingSpaces).to.equal("255"); - expect(response.attributes.patioArea).to.equal("256"); - expect(response.attributes.phaseName).to.equal("257"); - expect(response.attributes.plumbingFixturesCount).to.equal("257"); - expect(response.attributes.poleStruct).to.equal("258"); - expect(response.attributes.poleStructSqft).to.equal("259"); - expect(response.attributes.pond).to.equal("260"); - expect(response.attributes.pool).to.equal("261"); - expect(response.attributes.poolArea).to.equal("262"); - expect(response.attributes.poolhouse).to.equal("263"); - expect(response.attributes.poolhouseSqft).to.equal("264"); - expect(response.attributes.porch).to.equal("265"); - expect(response.attributes.porchArea).to.equal("266"); - expect(response.attributes.poultryHouse).to.equal("267"); - expect(response.attributes.poultryHouseSqft).to.equal("268"); - expect(response.attributes.previousAssessedValue).to.equal("269"); - expect(response.attributes.priorSaleAmount).to.equal("270"); - expect(response.attributes.priorSaleDate).to.equal("271"); - expect(response.attributes.propertyAddressCarrierRouteCode).to.equal("272"); - expect(response.attributes.propertyAddressCity).to.equal("273"); - expect(response.attributes.propertyAddressFull).to.equal("274"); - expect(response.attributes.propertyAddressHouseNumber).to.equal("275"); - expect(response.attributes.propertyAddressPostDirection).to.equal("276"); - expect(response.attributes.propertyAddressPreDirection).to.equal("277"); - expect(response.attributes.propertyAddressState).to.equal("278"); - expect(response.attributes.propertyAddressStreetName).to.equal("279"); - expect(response.attributes.propertyAddressStreetSuffix).to.equal("280"); - expect(response.attributes.propertyAddressUnitDesignator).to.equal("281"); - expect(response.attributes.propertyAddressUnitValue).to.equal("282"); - expect(response.attributes.propertyAddressZip4).to.equal("283"); - expect(response.attributes.propertyAddressZipcode).to.equal("284"); - expect(response.attributes.publicationDate).to.equal("285"); - expect(response.attributes.quarter).to.equal("286"); - expect(response.attributes.quarterQuarter).to.equal("287"); - expect(response.attributes.quonset).to.equal("288"); - expect(response.attributes.quonsetSqft).to.equal("289"); - expect(response.attributes.range).to.equal("290"); - expect(response.attributes.recordingDate).to.equal("291"); - expect(response.attributes.roofCover).to.equal("292"); - expect(response.attributes.roofFrame).to.equal("293"); - expect(response.attributes.rooms).to.equal("294"); - expect(response.attributes.rvParking).to.equal("295"); - expect(response.attributes.safeRoom).to.equal("296"); - expect(response.attributes.saleAmount).to.equal("297"); - expect(response.attributes.saleDate).to.equal("298"); - expect(response.attributes.sauna).to.equal("299"); - expect(response.attributes.section).to.equal("300"); - expect(response.attributes.securityAlarm).to.equal("301"); - expect(response.attributes.seniorTaxExemption).to.equal("302"); - expect(response.attributes.sewerType).to.equal("303"); - expect(response.attributes.shed).to.equal("304"); - expect(response.attributes.shedSqft).to.equal("305"); - expect(response.attributes.silo).to.equal("306"); - expect(response.attributes.siloSqft).to.equal("307"); - expect(response.attributes.sittingRoom).to.equal("308"); - expect(response.attributes.situsCounty).to.equal("309"); - expect(response.attributes.situsState).to.equal("310"); - expect(response.attributes.soundSystem).to.equal("311"); - expect(response.attributes.sportsCourt).to.equal("312"); - expect(response.attributes.sprinklers).to.equal("313"); - expect(response.attributes.stable).to.equal("314"); - expect(response.attributes.stableSqft).to.equal("315"); - expect(response.attributes.storageBuilding).to.equal("316"); - expect(response.attributes.storageBuildingSqft).to.equal("317"); - expect(response.attributes.storiesNumber).to.equal("318"); - expect(response.attributes.stormShelter).to.equal("319"); - expect(response.attributes.stormShutter).to.equal("320"); - expect(response.attributes.structureStyle).to.equal("321"); - expect(response.attributes.study).to.equal("322"); - expect(response.attributes.subdivision).to.equal("323"); - expect(response.attributes.suffix).to.equal("324"); - expect(response.attributes.suffix2).to.equal("325"); - expect(response.attributes.suffix3).to.equal("326"); - expect(response.attributes.suffix4).to.equal("327"); - expect(response.attributes.sunroom).to.equal("328"); - expect(response.attributes.taxAssessYear).to.equal("329"); - expect(response.attributes.taxBilledAmount).to.equal("330"); - expect(response.attributes.taxDelinquentYear).to.equal("331"); - expect(response.attributes.taxFiscalYear).to.equal("332"); - expect(response.attributes.taxJurisdiction).to.equal("333"); - expect(response.attributes.taxRateArea).to.equal("334"); - expect(response.attributes.tennisCourt).to.equal("335"); - expect(response.attributes.topographyCode).to.equal("336"); - expect(response.attributes.totalMarketValue).to.equal("337"); - expect(response.attributes.township).to.equal("338"); - expect(response.attributes.tractNumber).to.equal("339"); - expect(response.attributes.transferAmount).to.equal("340"); - expect(response.attributes.trustDescription).to.equal("341"); - expect(response.attributes.unitCount).to.equal("342"); - expect(response.attributes.upperFloorsSqft).to.equal("343"); - expect(response.attributes.utility).to.equal("344"); - expect(response.attributes.utilityBuilding).to.equal("345"); - expect(response.attributes.utilityBuildingSqft).to.equal("346"); - expect(response.attributes.utilitySqft).to.equal("347"); - expect(response.attributes.veteranTaxExemption).to.equal("348"); - expect(response.attributes.viewDescription).to.equal("349"); - expect(response.attributes.waterFeature).to.equal("350"); - expect(response.attributes.waterServiceType).to.equal("351"); - expect(response.attributes.wetBar).to.equal("352"); - expect(response.attributes.widowTaxExemption).to.equal("353"); - expect(response.attributes.widthLinearFootage).to.equal("354"); - expect(response.attributes.wineCellar).to.equal("355"); - expect(response.attributes.yearBuilt).to.equal("356"); - expect(response.attributes.zoning).to.equal("357"); - }); -}); \ No newline at end of file + expect(response.attributes.firstFloorSqft).to.equal("01"); + expect(response.attributes.secondFlootSqft).to.equal("02"); + expect(response.attributes.acres).to.equal("0"); + expect(response.attributes.addressInfoPrivacy).to.equal("1"); + expect(response.attributes.airConditioner).to.equal("2"); + expect(response.attributes.arborPergola).to.equal("3"); + expect(response.attributes.assessedImprovementPercent).to.equal("4"); + expect(response.attributes.assessedImprovementValue).to.equal("5"); + expect(response.attributes.assessedLandValue).to.equal("6"); + expect(response.attributes.assessedValue).to.equal("7"); + expect(response.attributes.assessorLastUpdate).to.equal("8"); + expect(response.attributes.assessorTaxrollUpdate).to.equal("9"); + expect(response.attributes.atticArea).to.equal("10"); + expect(response.attributes.atticFlag).to.equal("11"); + expect(response.attributes.balcony).to.equal("12"); + expect(response.attributes.balconyArea).to.equal("13"); + expect(response.attributes.basementSqft).to.equal("14"); + expect(response.attributes.basementSqftFinished).to.equal("15"); + expect(response.attributes.basementsqftUnfinished).to.equal("16"); + expect(response.attributes.bathHouse).to.equal("17"); + expect(response.attributes.bathHouseSqft).to.equal("18"); + expect(response.attributes.bathroomsPartial).to.equal("19"); + expect(response.attributes.bathroomsTotal).to.equal("20"); + expect(response.attributes.bedrooms).to.equal("21"); + expect(response.attributes.block1).to.equal("22"); + expect(response.attributes.block2).to.equal("23"); + expect(response.attributes.boatAccess).to.equal("24"); + expect(response.attributes.boatHouse).to.equal("25"); + expect(response.attributes.boatHouseSqft).to.equal("26"); + expect(response.attributes.boatLift).to.equal("27"); + expect(response.attributes.bonusRoom).to.equal("28"); + expect(response.attributes.breakfastNook).to.equal("29"); + expect(response.attributes.breezeway).to.equal("30"); + expect(response.attributes.buildingDefinitionCode).to.equal("31"); + expect(response.attributes.buildingSqft).to.equal("32"); + expect(response.attributes.cabin).to.equal("33"); + expect(response.attributes.cabinSqft).to.equal("34"); + expect(response.attributes.canopy).to.equal("35"); + expect(response.attributes.canopySqft).to.equal("36"); + expect(response.attributes.carport).to.equal("37"); + expect(response.attributes.carportSqft).to.equal("38"); + expect(response.attributes.cbsaCode).to.equal("39"); + expect(response.attributes.cbsaName).to.equal("40"); + expect(response.attributes.cellar).to.equal("41"); + expect(response.attributes.censusBlock).to.equal("42"); + expect(response.attributes.censusBlockGroup).to.equal("43"); + expect(response.attributes.censusFipsPlaceCode).to.equal("44"); + expect(response.attributes.censusTract).to.equal("45"); + expect(response.attributes.centralVacuum).to.equal("46"); + expect(response.attributes.codeTitleCompany).to.equal("47"); + expect(response.attributes.combinedStatisticalArea).to.equal("48"); + expect(response.attributes.communityRec).to.equal("49"); + expect(response.attributes.companyFlag).to.equal("50"); + expect(response.attributes.congressionalDistrict).to.equal("51"); + expect(response.attributes.constructionType).to.equal("52"); + expect(response.attributes.contactCity).to.equal("53"); + expect(response.attributes.contactCrrt).to.equal("54"); + expect(response.attributes.contactFullAddress).to.equal("55"); + expect(response.attributes.contactHouseNumber).to.equal("56"); + expect(response.attributes.contactMailInfoFormat).to.equal("57"); + expect(response.attributes.contactMailInfoPrivacy).to.equal("58"); + expect(response.attributes.contactMailingCounty).to.equal("59"); + expect(response.attributes.contactMailingFips).to.equal("60"); + expect(response.attributes.contactPostDirection).to.equal("61"); + expect(response.attributes.contactPreDirection).to.equal("62"); + expect(response.attributes.contactState).to.equal("63"); + expect(response.attributes.contactStreetName).to.equal("64"); + expect(response.attributes.contactSuffix).to.equal("65"); + expect(response.attributes.contactUnitDesignator).to.equal("66"); + expect(response.attributes.contactValue).to.equal("67"); + expect(response.attributes.contactZip).to.equal("68"); + expect(response.attributes.contactZip4).to.equal("69"); + expect(response.attributes.courtyard).to.equal("70"); + expect(response.attributes.courtyardArea).to.equal("71"); + expect(response.attributes.deck).to.equal("72"); + expect(response.attributes.deckArea).to.equal("73"); + expect(response.attributes.deedDocumentPage).to.equal("74"); + expect(response.attributes.deedDocumentBook).to.equal("75"); + expect(response.attributes.deedDocumentNumber).to.equal("76"); + expect(response.attributes.deedOwnerFirstName).to.equal("77"); + expect(response.attributes.deedOwnerFirstName2).to.equal("78"); + expect(response.attributes.deedOwnerFirstName3).to.equal("79"); + expect(response.attributes.deedOwnerFirstName4).to.equal("80"); + expect(response.attributes.deedOwnerFullName).to.equal("81"); + expect(response.attributes.deedOwnerFullName2).to.equal("82"); + expect(response.attributes.deedOwnerFullName3).to.equal("83"); + expect(response.attributes.deedOwnerFullName4).to.equal("84"); + expect(response.attributes.deedOwnerLastName).to.equal("85"); + expect(response.attributes.deedOwnerLastName2).to.equal("86"); + expect(response.attributes.deedOwnerLastName3).to.equal("87"); + expect(response.attributes.deedOwnerLastName4).to.equal("88"); + expect(response.attributes.deedOwnerMiddleName).to.equal("89"); + expect(response.attributes.deedOwnerMiddleName2).to.equal("90"); + expect(response.attributes.deedOwnerMiddleName3).to.equal("91"); + expect(response.attributes.deedOwnerMiddleName4).to.equal("92"); + expect(response.attributes.deedOwnerSuffix).to.equal("93"); + expect(response.attributes.deedOwnerSuffix2).to.equal("94"); + expect(response.attributes.deedOwnerSuffix3).to.equal("95"); + expect(response.attributes.deedOwnerSuffix4).to.equal("96"); + expect(response.attributes.deedSaleDate).to.equal("97"); + expect(response.attributes.deedSalePrice).to.equal("98"); + expect(response.attributes.deedTransactionId).to.equal("99"); + expect(response.attributes.depthLinearFootage).to.equal("100"); + expect(response.attributes.disabledTaxExemption).to.equal("101"); + expect(response.attributes.drivewaySqft).to.equal("102"); + expect(response.attributes.drivewayType).to.equal("103"); + expect(response.attributes.effectiveYearBuilt).to.equal("104"); + expect(response.attributes.elevationFeet).to.equal("105"); + expect(response.attributes.elevator).to.equal("106"); + expect(response.attributes.equestrianArena).to.equal("107"); + expect(response.attributes.escalator).to.equal("108"); + expect(response.attributes.exerciseRoom).to.equal("109"); + expect(response.attributes.exteriorWalls).to.equal("110"); + expect(response.attributes.familyRoom).to.equal("111"); + expect(response.attributes.fence).to.equal("112"); + expect(response.attributes.fenceArea).to.equal("113"); + expect(response.attributes.fipsCode).to.equal("114"); + expect(response.attributes.fireResistanceCode).to.equal("115"); + expect(response.attributes.fireSprinklersFlag).to.equal("116"); + expect(response.attributes.fireplace).to.equal("117"); + expect(response.attributes.fireplaceNumber).to.equal("118"); + expect(response.attributes.firstName).to.equal("119"); + expect(response.attributes.firstName2).to.equal("120"); + expect(response.attributes.firstName3).to.equal("121"); + expect(response.attributes.firstName4).to.equal("122"); + expect(response.attributes.flooring).to.equal("123"); + expect(response.attributes.foundation).to.equal("124"); + expect(response.attributes.gameRoom).to.equal("125"); + expect(response.attributes.garage).to.equal("126"); + expect(response.attributes.garageSqft).to.equal("127"); + expect(response.attributes.gazebo).to.equal("128"); + expect(response.attributes.gazeboSqft).to.equal("129"); + expect(response.attributes.golfCourse).to.equal("130"); + expect(response.attributes.grainery).to.equal("131"); + expect(response.attributes.grainerySqft).to.equal("132"); + expect(response.attributes.greatRoom).to.equal("133"); + expect(response.attributes.greenhouse).to.equal("134"); + expect(response.attributes.greenhouseSqft).to.equal("135"); + expect(response.attributes.grossSqft).to.equal("136"); + expect(response.attributes.guesthouse).to.equal("137"); + expect(response.attributes.guesthouseSqft).to.equal("138"); + expect(response.attributes.handicapAccessibility).to.equal("139"); + expect(response.attributes.heat).to.equal("140"); + expect(response.attributes.heatFuelType).to.equal("141"); + expect(response.attributes.hobbyRoom).to.equal("142"); + expect(response.attributes.homeownerTaxExemption).to.equal("143"); + expect(response.attributes.instrumentDate).to.equal("144"); + expect(response.attributes.intercomSystem).to.equal("145"); + expect(response.attributes.interestRateType2).to.equal("146"); + expect(response.attributes.interiorStructure).to.equal("147"); + expect(response.attributes.kennel).to.equal("148"); + expect(response.attributes.kennelSqft).to.equal("149"); + expect(response.attributes.landUseCode).to.equal("150"); + expect(response.attributes.landUseGroup).to.equal("151"); + expect(response.attributes.landUseStandard).to.equal("152"); + expect(response.attributes.lastName).to.equal("153"); + expect(response.attributes.lastName2).to.equal("154"); + expect(response.attributes.lastName3).to.equal("155"); + expect(response.attributes.lastName4).to.equal("156"); + expect(response.attributes.latitude).to.equal("157"); + expect(response.attributes.laundry).to.equal("158"); + expect(response.attributes.leanTo).to.equal("159"); + expect(response.attributes.leanToSqft).to.equal("160"); + expect(response.attributes.legalDescription).to.equal("161"); + expect(response.attributes.legalUnit).to.equal("162"); + expect(response.attributes.lenderAddress).to.equal("163"); + expect(response.attributes.lenderAddress2).to.equal("164"); + expect(response.attributes.lenderCity).to.equal("165"); + expect(response.attributes.lenderCity2).to.equal("166"); + expect(response.attributes.lenderCode).to.equal("167"); + expect(response.attributes.lenderCode2).to.equal("168"); + expect(response.attributes.lenderFirstName).to.equal("169"); + expect(response.attributes.lenderFirstName2).to.equal("170"); + expect(response.attributes.lenderLastName).to.equal("171"); + expect(response.attributes.lenderLastName2).to.equal("172"); + expect(response.attributes.lenderName).to.equal("173"); + expect(response.attributes.lenderName2).to.equal("174"); + expect(response.attributes.lenderSellerCarryBack).to.equal("175"); + expect(response.attributes.lenderSellerCarryBack2).to.equal("176"); + expect(response.attributes.lenderState).to.equal("177"); + expect(response.attributes.lenderState2).to.equal("178"); + expect(response.attributes.lenderZip).to.equal("179"); + expect(response.attributes.lenderZip2).to.equal("180"); + expect(response.attributes.lenderZipExtended).to.equal("181"); + expect(response.attributes.lenderZipExtended2).to.equal("182"); + expect(response.attributes.loadingPlatform).to.equal("183"); + expect(response.attributes.loadingPlatformSqft).to.equal("184"); + expect(response.attributes.longitude).to.equal("185"); + expect(response.attributes.lot1).to.equal("186"); + expect(response.attributes.lot2).to.equal("187"); + expect(response.attributes.lot3).to.equal("188"); + expect(response.attributes.lotSqft).to.equal("189"); + expect(response.attributes.marketImprovementPercent).to.equal("190"); + expect(response.attributes.marketImprovementValue).to.equal("191"); + expect(response.attributes.marketLandValue).to.equal("192"); + expect(response.attributes.marketValueYear).to.equal("193"); + expect(response.attributes.matchType).to.equal("194"); + expect(response.attributes.mediaRoom).to.equal("195"); + expect(response.attributes.metroDivision).to.equal("196"); + expect(response.attributes.middleName).to.equal("197"); + expect(response.attributes.middleName2).to.equal("198"); + expect(response.attributes.middleName3).to.equal("199"); + expect(response.attributes.middleName4).to.equal("200"); + expect(response.attributes.milkhouse).to.equal("201"); + expect(response.attributes.milkhouseSqft).to.equal("202"); + expect(response.attributes.minorCivilDivisionCode).to.equal("203"); + expect(response.attributes.minorCivilDivisionName).to.equal("204"); + expect(response.attributes.mobileHomeHookup).to.equal("205"); + expect(response.attributes.mortgageAmount).to.equal("206"); + expect(response.attributes.mortgageAmount2).to.equal("207"); + expect(response.attributes.mortgageDueDate).to.equal("208"); + expect(response.attributes.mortgageDueDate2).to.equal("209"); + expect(response.attributes.mortgageInterestRate).to.equal("210"); + expect(response.attributes.mortgageInterestRateType).to.equal("211"); + expect(response.attributes.mortgageLenderCode).to.equal("212"); + expect(response.attributes.mortgageRate2).to.equal("213"); + expect(response.attributes.mortgageRecordingDate).to.equal("214"); + expect(response.attributes.mortgageRecordingDate2).to.equal("215"); + expect(response.attributes.mortgageTerm).to.equal("216"); + expect(response.attributes.mortgageTerm2).to.equal("217"); + expect(response.attributes.mortgageTermType).to.equal("218"); + expect(response.attributes.mortgageTermType2).to.equal("219"); + expect(response.attributes.mortgageType).to.equal("220"); + expect(response.attributes.mortgageType2).to.equal("221"); + expect(response.attributes.msaCode).to.equal("222"); + expect(response.attributes.msaName).to.equal("223"); + expect(response.attributes.mudRoom).to.equal("224"); + expect(response.attributes.multiParcelFlag).to.equal("225"); + expect(response.attributes.nameTitleCompany).to.equal("226"); + expect(response.attributes.neighborhoodCode).to.equal("227"); + expect(response.attributes.numberOfBuildings).to.equal("228"); + expect(response.attributes.office).to.equal("229"); + expect(response.attributes.officeSqft).to.equal("230"); + expect(response.attributes.otherTaxExemption).to.equal("231"); + expect(response.attributes.outdoorKitchenFireplace).to.equal("232"); + expect(response.attributes.overheadDoor).to.equal("233"); + expect(response.attributes.ownerFullName).to.equal("234"); + expect(response.attributes.ownerFullName2).to.equal("235"); + expect(response.attributes.ownerFullName3).to.equal("236"); + expect(response.attributes.ownerFullName4).to.equal("237"); + expect(response.attributes.ownerOccupancyStatus).to.equal("238"); + expect(response.attributes.ownershipTransferDate).to.equal("239"); + expect(response.attributes.ownershipTransferDocNumber).to.equal("240"); + expect(response.attributes.ownershipTransferTransactionId).to.equal("241"); + expect(response.attributes.ownershipType).to.equal("242"); + expect(response.attributes.ownershipType2).to.equal("243"); + expect(response.attributes.ownershipVestingRelationCode).to.equal("244"); + expect(response.attributes.parcelAccountNumber).to.equal("245"); + expect(response.attributes.parcelMapBook).to.equal("246"); + expect(response.attributes.parcelMapPage).to.equal("247"); + expect(response.attributes.parcelNumberAlternate).to.equal("248"); + expect(response.attributes.parcelNumberFormatted).to.equal("249"); + expect(response.attributes.parcelNumberPrevious).to.equal("250"); + expect(response.attributes.parcelNumberYearAdded).to.equal("251"); + expect(response.attributes.parcelNumberYearChange).to.equal("252"); + expect(response.attributes.parcelRawNumber).to.equal("253"); + expect(response.attributes.parcelShellRecord).to.equal("254"); + expect(response.attributes.parkingSpaces).to.equal("255"); + expect(response.attributes.patioArea).to.equal("256"); + expect(response.attributes.phaseName).to.equal("257"); + expect(response.attributes.plumbingFixturesCount).to.equal("257"); + expect(response.attributes.poleStruct).to.equal("258"); + expect(response.attributes.poleStructSqft).to.equal("259"); + expect(response.attributes.pond).to.equal("260"); + expect(response.attributes.pool).to.equal("261"); + expect(response.attributes.poolArea).to.equal("262"); + expect(response.attributes.poolhouse).to.equal("263"); + expect(response.attributes.poolhouseSqft).to.equal("264"); + expect(response.attributes.porch).to.equal("265"); + expect(response.attributes.porchArea).to.equal("266"); + expect(response.attributes.poultryHouse).to.equal("267"); + expect(response.attributes.poultryHouseSqft).to.equal("268"); + expect(response.attributes.previousAssessedValue).to.equal("269"); + expect(response.attributes.priorSaleAmount).to.equal("270"); + expect(response.attributes.priorSaleDate).to.equal("271"); + expect(response.attributes.propertyAddressCarrierRouteCode).to.equal("272"); + expect(response.attributes.propertyAddressCity).to.equal("273"); + expect(response.attributes.propertyAddressFull).to.equal("274"); + expect(response.attributes.propertyAddressHouseNumber).to.equal("275"); + expect(response.attributes.propertyAddressPostDirection).to.equal("276"); + expect(response.attributes.propertyAddressPreDirection).to.equal("277"); + expect(response.attributes.propertyAddressState).to.equal("278"); + expect(response.attributes.propertyAddressStreetName).to.equal("279"); + expect(response.attributes.propertyAddressStreetSuffix).to.equal("280"); + expect(response.attributes.propertyAddressUnitDesignator).to.equal("281"); + expect(response.attributes.propertyAddressUnitValue).to.equal("282"); + expect(response.attributes.propertyAddressZip4).to.equal("283"); + expect(response.attributes.propertyAddressZipcode).to.equal("284"); + expect(response.attributes.publicationDate).to.equal("285"); + expect(response.attributes.quarter).to.equal("286"); + expect(response.attributes.quarterQuarter).to.equal("287"); + expect(response.attributes.quonset).to.equal("288"); + expect(response.attributes.quonsetSqft).to.equal("289"); + expect(response.attributes.range).to.equal("290"); + expect(response.attributes.recordingDate).to.equal("291"); + expect(response.attributes.roofCover).to.equal("292"); + expect(response.attributes.roofFrame).to.equal("293"); + expect(response.attributes.rooms).to.equal("294"); + expect(response.attributes.rvParking).to.equal("295"); + expect(response.attributes.safeRoom).to.equal("296"); + expect(response.attributes.saleAmount).to.equal("297"); + expect(response.attributes.saleDate).to.equal("298"); + expect(response.attributes.sauna).to.equal("299"); + expect(response.attributes.section).to.equal("300"); + expect(response.attributes.securityAlarm).to.equal("301"); + expect(response.attributes.seniorTaxExemption).to.equal("302"); + expect(response.attributes.sewerType).to.equal("303"); + expect(response.attributes.shed).to.equal("304"); + expect(response.attributes.shedSqft).to.equal("305"); + expect(response.attributes.silo).to.equal("306"); + expect(response.attributes.siloSqft).to.equal("307"); + expect(response.attributes.sittingRoom).to.equal("308"); + expect(response.attributes.situsCounty).to.equal("309"); + expect(response.attributes.situsState).to.equal("310"); + expect(response.attributes.soundSystem).to.equal("311"); + expect(response.attributes.sportsCourt).to.equal("312"); + expect(response.attributes.sprinklers).to.equal("313"); + expect(response.attributes.stable).to.equal("314"); + expect(response.attributes.stableSqft).to.equal("315"); + expect(response.attributes.storageBuilding).to.equal("316"); + expect(response.attributes.storageBuildingSqft).to.equal("317"); + expect(response.attributes.storiesNumber).to.equal("318"); + expect(response.attributes.stormShelter).to.equal("319"); + expect(response.attributes.stormShutter).to.equal("320"); + expect(response.attributes.structureStyle).to.equal("321"); + expect(response.attributes.study).to.equal("322"); + expect(response.attributes.subdivision).to.equal("323"); + expect(response.attributes.suffix).to.equal("324"); + expect(response.attributes.suffix2).to.equal("325"); + expect(response.attributes.suffix3).to.equal("326"); + expect(response.attributes.suffix4).to.equal("327"); + expect(response.attributes.sunroom).to.equal("328"); + expect(response.attributes.taxAssessYear).to.equal("329"); + expect(response.attributes.taxBilledAmount).to.equal("330"); + expect(response.attributes.taxDelinquentYear).to.equal("331"); + expect(response.attributes.taxFiscalYear).to.equal("332"); + expect(response.attributes.taxJurisdiction).to.equal("333"); + expect(response.attributes.taxRateArea).to.equal("334"); + expect(response.attributes.tennisCourt).to.equal("335"); + expect(response.attributes.topographyCode).to.equal("336"); + expect(response.attributes.totalMarketValue).to.equal("337"); + expect(response.attributes.township).to.equal("338"); + expect(response.attributes.tractNumber).to.equal("339"); + expect(response.attributes.transferAmount).to.equal("340"); + expect(response.attributes.trustDescription).to.equal("341"); + expect(response.attributes.unitCount).to.equal("342"); + expect(response.attributes.upperFloorsSqft).to.equal("343"); + expect(response.attributes.utility).to.equal("344"); + expect(response.attributes.utilityBuilding).to.equal("345"); + expect(response.attributes.utilityBuildingSqft).to.equal("346"); + expect(response.attributes.utilitySqft).to.equal("347"); + expect(response.attributes.veteranTaxExemption).to.equal("348"); + expect(response.attributes.viewDescription).to.equal("349"); + expect(response.attributes.waterFeature).to.equal("350"); + expect(response.attributes.waterServiceType).to.equal("351"); + expect(response.attributes.wetBar).to.equal("352"); + expect(response.attributes.widowTaxExemption).to.equal("353"); + expect(response.attributes.widthLinearFootage).to.equal("354"); + expect(response.attributes.wineCellar).to.equal("355"); + expect(response.attributes.yearBuilt).to.equal("356"); + expect(response.attributes.zoning).to.equal("357"); + }); +}); diff --git a/tests/us_extract/test_Address.js b/tests/us_extract/test_Address.js index 8aad9f2..0acaa0e 100644 --- a/tests/us_extract/test_Address.js +++ b/tests/us_extract/test_Address.js @@ -6,52 +6,52 @@ const Candidate = require("../../src/us_street/Candidate"); describe("A US Extract Address", function () { it("populates fields correctly.", function () { let mockResponseAddress = { - "text": "5732 Lincoln Drive Minneapolis MN", - "verified": true, - "line": 4, - "start": 16, - "end": 49, - "api_output": [ + text: "5732 Lincoln Drive Minneapolis MN", + verified: true, + line: 4, + start: 16, + end: 49, + api_output: [ { - "candidate_index": 0, - "delivery_line_1": "5732 Lincoln Dr", - "last_line": "Minneapolis MN 55436-1608", - "delivery_point_barcode": "554361608327", - "components": { - "primary_number": "5732", - "street_name": "Lincoln", - "street_suffix": "Dr", - "city_name": "Minneapolis", - "state_abbreviation": "MN", - "zipcode": "55436", - "plus4_code": "1608", - "delivery_point": "32", - "delivery_point_check_digit": "7" + candidate_index: 0, + delivery_line_1: "5732 Lincoln Dr", + last_line: "Minneapolis MN 55436-1608", + delivery_point_barcode: "554361608327", + components: { + primary_number: "5732", + street_name: "Lincoln", + street_suffix: "Dr", + city_name: "Minneapolis", + state_abbreviation: "MN", + zipcode: "55436", + plus4_code: "1608", + delivery_point: "32", + delivery_point_check_digit: "7", }, - "metadata": { - "record_type": "S", - "zip_type": "Standard", - "county_fips": "27053", - "county_name": "Hennepin", - "carrier_route": "C009", - "congressional_district": "03", - "rdi": "Commercial", - "elot_sequence": "0035", - "elot_sort": "A", - "latitude": 44.90127, - "longitude": -93.40045, - "precision": "Zip9", - "time_zone": "Central", - "utc_offset": -6, - "dst": true + metadata: { + record_type: "S", + zip_type: "Standard", + county_fips: "27053", + county_name: "Hennepin", + carrier_route: "C009", + congressional_district: "03", + rdi: "Commercial", + elot_sequence: "0035", + elot_sort: "A", + latitude: 44.90127, + longitude: -93.40045, + precision: "Zip9", + time_zone: "Central", + utc_offset: -6, + dst: true, }, - "analysis": { - "dpv_match_code": "Y", - "dpv_footnotes": "AABB", - "dpv_cmra": "N", - "dpv_vacant": "N", - "active": "Y", - "footnotes": "N#" + analysis: { + dpv_match_code: "Y", + dpv_footnotes: "AABB", + dpv_cmra: "N", + dpv_vacant: "N", + active: "Y", + footnotes: "N#", }, }, ], diff --git a/tests/us_extract/test_Client.js b/tests/us_extract/test_Client.js index 2acc73d..045bdfc 100644 --- a/tests/us_extract/test_Client.js +++ b/tests/us_extract/test_Client.js @@ -67,73 +67,75 @@ describe("A US Extract Client", function () { let client = new Client(mockSender); let lookup = new Lookup("Shine on you crazy diamond."); - return client.send(lookup).catch((e) => {expect(e).to.equal(expectedError);}); + return client.send(lookup).catch((e) => { + expect(e).to.equal(expectedError); + }); }); it("attaches result from a response to a lookup.", function () { const responseData = { - "meta": { - "lines": 6, - "unicode": false, - "address_count": 1, - "verified_count": 1, - "bytes": 53, - "character_count": 53 + meta: { + lines: 6, + unicode: false, + address_count: 1, + verified_count: 1, + bytes: 53, + character_count: 53, }, - "addresses": [ + addresses: [ { - "text": "5732 Lincoln Drive Minneapolis MN", - "verified": true, - "line": 4, - "start": 16, - "end": 49, - "api_output": [ + text: "5732 Lincoln Drive Minneapolis MN", + verified: true, + line: 4, + start: 16, + end: 49, + api_output: [ { - "candidate_index": 0, - "delivery_line_1": "5732 Lincoln Dr", - "last_line": "Minneapolis MN 55436-1608", - "delivery_point_barcode": "554361608327", - "components": { - "primary_number": "5732", - "street_name": "Lincoln", - "street_suffix": "Dr", - "city_name": "Minneapolis", - "state_abbreviation": "MN", - "zipcode": "55436", - "plus4_code": "1608", - "delivery_point": "32", - "delivery_point_check_digit": "7" + candidate_index: 0, + delivery_line_1: "5732 Lincoln Dr", + last_line: "Minneapolis MN 55436-1608", + delivery_point_barcode: "554361608327", + components: { + primary_number: "5732", + street_name: "Lincoln", + street_suffix: "Dr", + city_name: "Minneapolis", + state_abbreviation: "MN", + zipcode: "55436", + plus4_code: "1608", + delivery_point: "32", + delivery_point_check_digit: "7", + }, + metadata: { + record_type: "S", + zip_type: "Standard", + county_fips: "27053", + county_name: "Hennepin", + carrier_route: "C009", + congressional_district: "03", + rdi: "Commercial", + elot_sequence: "0035", + elot_sort: "A", + latitude: 44.90127, + longitude: -93.40045, + precision: "Zip9", + time_zone: "Central", + utc_offset: -6, + dst: true, }, - "metadata": { - "record_type": "S", - "zip_type": "Standard", - "county_fips": "27053", - "county_name": "Hennepin", - "carrier_route": "C009", - "congressional_district": "03", - "rdi": "Commercial", - "elot_sequence": "0035", - "elot_sort": "A", - "latitude": 44.90127, - "longitude": -93.40045, - "precision": "Zip9", - "time_zone": "Central", - "utc_offset": -6, - "dst": true + analysis: { + dpv_match_code: "Y", + dpv_footnotes: "AABB", + dpv_cmra: "N", + dpv_vacant: "N", + dpv_no_stat: "N", + active: "Y", + footnotes: "N#", }, - "analysis": { - "dpv_match_code": "Y", - "dpv_footnotes": "AABB", - "dpv_cmra": "N", - "dpv_vacant": "N", - "dpv_no_stat": "N", - "active": "Y", - "footnotes": "N#" - } - } - ] - } - ] + }, + ], + }, + ], }; let mockSender = new MockSenderWithResponse(responseData); @@ -141,8 +143,8 @@ describe("A US Extract Client", function () { let lookup = new Lookup("Sometimes when you're testing this field doesn't matter too much."); let expectedResult = new Result(responseData); - return client.send(lookup).then(response => { + return client.send(lookup).then((response) => { expect(lookup.result).to.deep.equal(expectedResult); }); - }) -}); \ No newline at end of file + }); +}); diff --git a/tests/us_extract/test_Lookup.js b/tests/us_extract/test_Lookup.js index ac65b0d..2078f8b 100644 --- a/tests/us_extract/test_Lookup.js +++ b/tests/us_extract/test_Lookup.js @@ -16,4 +16,4 @@ describe("A US Extract Lookup", function () { expect(lookup.addressesHaveLineBreaks).to.equal(true); expect(lookup.addressesPerLine).to.equal(10); }); -}); \ No newline at end of file +}); diff --git a/tests/us_extract/test_Result.js b/tests/us_extract/test_Result.js index 562e604..ee543fa 100644 --- a/tests/us_extract/test_Result.js +++ b/tests/us_extract/test_Result.js @@ -6,24 +6,24 @@ const Address = require("../../src/us_extract/Address"); describe("A US Extract Result", function () { it("correctly populates fields.", function () { const mockResponseData = { - "meta": { - "lines": 6, - "unicode": false, - "address_count": 1, - "verified_count": 1, - "bytes": 53, - "character_count": 53, + meta: { + lines: 6, + unicode: false, + address_count: 1, + verified_count: 1, + bytes: 53, + character_count: 53, }, - "addresses": [ + addresses: [ { - "text": "5732 Lincoln Drive Minneapolis MN", - "verified": true, - "line": 4, - "start": 16, - "end": 49, - "api_output": [{}] - } - ] + text: "5732 Lincoln Drive Minneapolis MN", + verified: true, + line: 4, + start: 16, + end: 49, + api_output: [{}], + }, + ], }; let result = new Result(mockResponseData); diff --git a/tests/us_reverse_geo/test_Client.js b/tests/us_reverse_geo/test_Client.js index e720e29..f7bfb63 100644 --- a/tests/us_reverse_geo/test_Client.js +++ b/tests/us_reverse_geo/test_Client.js @@ -14,27 +14,26 @@ describe("A US Reverse Geo client", function () { expect(client.sender).to.deep.equal(mockSender); }); - it("attaches a result from a response to a lookup.", function () { const expectedMockPayload = { - "results": [ + results: [ { - "coordinate": { - "latitude": 40.111111, - "longitude": -111.111111, - "accuracy": "Rooftop", - "license": "SmartyStreets" + coordinate: { + latitude: 40.111111, + longitude: -111.111111, + accuracy: "Rooftop", + license: "SmartyStreets", + }, + distance: 2.7207432, + address: { + street: "2335 S State St", + city: "Provo", + state_abbreviation: "UT", + zipcode: "84606", + source: "postal", }, - "distance": 2.7207432, - "address": { - "street": "2335 S State St", - "city": "Provo", - "state_abbreviation": "UT", - "zipcode": "84606", - "source": "postal" - } }, - ] + ], }; let mockSender = new MockSenderWithResponse(expectedMockPayload); const client = new Client(mockSender); diff --git a/tests/us_reverse_geo/test_Lookup.js b/tests/us_reverse_geo/test_Lookup.js index 0787306..e60d512 100644 --- a/tests/us_reverse_geo/test_Lookup.js +++ b/tests/us_reverse_geo/test_Lookup.js @@ -6,9 +6,9 @@ describe("A US Reverse Geo lookup", function () { it("correctly populates fields.", function () { let lookup = new Lookup(44.888888888, -111.111111111, "postal"); - expect(lookup.source).to.equal("postal") + expect(lookup.source).to.equal("postal"); expect(lookup.latitude).to.equal("44.88888889"); expect(lookup.longitude).to.equal("-111.11111111"); expect(lookup.response.results).to.deep.equal([]); }); -}); \ No newline at end of file +}); diff --git a/tests/us_reverse_geo/test_Response.js b/tests/us_reverse_geo/test_Response.js index 4068632..dce5f1d 100644 --- a/tests/us_reverse_geo/test_Response.js +++ b/tests/us_reverse_geo/test_Response.js @@ -11,7 +11,7 @@ describe("A US Reverse Geo match response", function () { latitude: 1.1, longitude: 2.2, accuracy: "3", - license: 1 + license: 1, }, distance: 4.4, address: { @@ -19,10 +19,10 @@ describe("A US Reverse Geo match response", function () { city: "6", state_abbreviation: "7", zipcode: "8", - source: "postal" - } + source: "postal", + }, }, - ] + ], }; const response = new Response(sampleResponse); diff --git a/tests/us_street/test_Client.js b/tests/us_street/test_Client.js index 703000c..38ab011 100644 --- a/tests/us_street/test_Client.js +++ b/tests/us_street/test_Client.js @@ -14,7 +14,7 @@ describe("A US Street client", function () { send: function (request) { sentFlag = true; mockSenderRequest = request; - } + }, }; const client = new Client(mockSender); let lookup = new Lookup(); @@ -217,23 +217,23 @@ describe("A US Street client", function () { }); it("attaches a match candidate from a response to a lookup.", function () { - const expectedMockPayload = [{delivery_line_1: "An address", input_index: 0}]; + const expectedMockPayload = [{ delivery_line_1: "An address", input_index: 0 }]; let mockSender = new MockSenderWithResponse(expectedMockPayload); const client = new Client(mockSender); let lookup = new Lookup(); - let expectedResult = new Candidate({delivery_line_1: "An address", input_index: 0}); + let expectedResult = new Candidate({ delivery_line_1: "An address", input_index: 0 }); - return client.send(lookup).then(response => { + return client.send(lookup).then((response) => { expect(lookup.result[0]).to.deep.equal(expectedResult); }); }); it("attaches match candidates to their corresponding lookups.", function () { const expectedMockPayload = JSON.stringify([ - {delivery_line_1: "Address 0", input_index: 0}, - {delivery_line_1: "Alternate address 0", input_index: 0}, - {delivery_line_1: "Address 1", input_index: 1}, - {delivery_line_1: "Address 3", input_index: 3}, + { delivery_line_1: "Address 0", input_index: 0 }, + { delivery_line_1: "Alternate address 0", input_index: 0 }, + { delivery_line_1: "Address 1", input_index: 1 }, + { delivery_line_1: "Address 3", input_index: 3 }, ]); let mockSender = new MockSenderWithResponse(expectedMockPayload); let client = new Client(mockSender); @@ -248,7 +248,7 @@ describe("A US Street client", function () { batch.add(lookup2); batch.add(lookup3); - client.send(batch).then(response => { + client.send(batch).then((response) => { expect(batch.getByIndex(0).result[0].deliveryLine1).to.equal("Address 0"); expect(batch.getByIndex(0).result[1].deliveryLine1).to.equal("Alternate address 0"); expect(batch.getByIndex(1).result[0].deliveryLine1).to.equal("Address 1"); @@ -263,7 +263,9 @@ describe("A US Street client", function () { let client = new Client(mockSender); let lookup = new Lookup(); - return client.send(lookup).catch((e) => {expect(e).to.equal(expectedMockError);}); + return client.send(lookup).catch((e) => { + expect(e).to.equal(expectedMockError); + }); }); it("throws an exception if a lookup is undefined.", function () { diff --git a/tests/us_street/test_Lookup.js b/tests/us_street/test_Lookup.js index 08c3a3f..bcc28ed 100644 --- a/tests/us_street/test_Lookup.js +++ b/tests/us_street/test_Lookup.js @@ -2,8 +2,8 @@ const chai = require("chai"); const expect = chai.expect; const Lookup = require("../../src/us_street/Lookup"); -describe ("A US Street lookup", function () { - it ("correctly populates fields.", function () { +describe("A US Street lookup", function () { + it("correctly populates fields.", function () { const lookup = new Lookup("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m"); expect(lookup.street).to.equal("a"); @@ -21,9 +21,9 @@ describe ("A US Street lookup", function () { expect(lookup.format).to.equal("m"); }); - it ("has a result array.", function () { + it("has a result array.", function () { const lookup = new Lookup(); expect(Array.isArray(lookup.result)).to.equal(true); }); -}); \ No newline at end of file +}); diff --git a/tests/us_zipcode/test_Client.js b/tests/us_zipcode/test_Client.js index e1e74a9..b00f8d7 100644 --- a/tests/us_zipcode/test_Client.js +++ b/tests/us_zipcode/test_Client.js @@ -14,9 +14,8 @@ describe("A US Zipcode client", function () { send: function (request) { sentFlag = true; mockSenderRequest = request; - return new Promise((resolve, reject) => { - }); - } + return new Promise((resolve, reject) => {}); + }, }; const client = new Client(mockSender); let lookup = new Lookup(); @@ -43,11 +42,7 @@ describe("A US Zipcode client", function () { let lookup1 = new Lookup("lookup1"); let lookup2 = new Lookup("lookup2"); let batch = new Batch(); - const expectedPayload = [ - {"city": "lookup0"}, - {"city": "lookup1"}, - {"city": "lookup2"} - ]; + const expectedPayload = [{ city: "lookup0" }, { city: "lookup1" }, { city: "lookup2" }]; batch.add(lookup0); batch.add(lookup1); @@ -59,23 +54,23 @@ describe("A US Zipcode client", function () { }); it("attaches a match candidate from a response to a lookup.", function () { - const expectedMockPayload = [{input_index: 0}]; + const expectedMockPayload = [{ input_index: 0 }]; let mockSender = new MockSenderWithResponse(expectedMockPayload); const client = new Client(mockSender); let lookup = new Lookup(); - let expectedResult = new Result({input_index: 0}); + let expectedResult = new Result({ input_index: 0 }); - return client.send(lookup).then(response => { + return client.send(lookup).then((response) => { expect(lookup.result[0]).to.deep.equal(expectedResult); }); }); it("attaches match candidates to their corresponding lookups.", function () { const expectedMockPayload = JSON.stringify([ - {city: "City 0", input_index: 0}, - {city: "Alternate city 0", input_index: 0}, - {city: "City 1", input_index: 1}, - {city: "City 3", input_index: 3}, + { city: "City 0", input_index: 0 }, + { city: "Alternate city 0", input_index: 0 }, + { city: "City 1", input_index: 1 }, + { city: "City 3", input_index: 3 }, ]); let mockSender = new MockSenderWithResponse(expectedMockPayload); let client = new Client(mockSender); @@ -90,7 +85,7 @@ describe("A US Zipcode client", function () { batch.add(lookup2); batch.add(lookup3); - client.send(batch).then(response => { + client.send(batch).then((response) => { expect(batch.getByIndex(0).result[0].city).to.equal("City 0"); expect(batch.getByIndex(0).result[1].city).to.equal("Alternate city 0"); expect(batch.getByIndex(1).result[0].city).to.equal("City 1"); @@ -123,7 +118,9 @@ describe("A US Zipcode client", function () { let client = new Client(mockSender); let lookup = new Lookup(); - return client.send(lookup).catch((e) => {expect(e).to.equal(expectedMockError);}); + return client.send(lookup).catch((e) => { + expect(e).to.equal(expectedMockError); + }); }); it("throws an exception if a lookup is undefined.", function () { diff --git a/tests/us_zipcode/test_Result.js b/tests/us_zipcode/test_Result.js index 08fbb7a..8f20c65 100644 --- a/tests/us_zipcode/test_Result.js +++ b/tests/us_zipcode/test_Result.js @@ -5,37 +5,37 @@ const Result = require("../../src/us_zipcode/Result"); describe("A US Zipcode result", function () { it("populates accurately on a valid lookup.", function () { let sampleResponse = { - "input_index": 0, - "city_states": [ + input_index: 0, + city_states: [ { - "city": "1", - "state_abbreviation": "2", - "state": "3", - "mailable_city": "4" - } + city: "1", + state_abbreviation: "2", + state: "3", + mailable_city: "4", + }, ], - "zipcodes": [ + zipcodes: [ { - "zipcode": "5", - "zipcode_type": "6", - "default_city": "7", - "county_fips": "8", - "county_name": "9", - "latitude": 10, - "longitude": 11, - "precision": "12", - "alternate_counties": [ + zipcode: "5", + zipcode_type: "6", + default_city: "7", + county_fips: "8", + county_name: "9", + latitude: 10, + longitude: 11, + precision: "12", + alternate_counties: [ { - "county_fips": "13", - "county_name": "14", - "state_abbreviation": "15", - "state": "16" - } + county_fips: "13", + county_name: "14", + state_abbreviation: "15", + state: "16", + }, ], - "state_abbreviation": "17", - "state": "18" - } - ] + state_abbreviation: "17", + state: "18", + }, + ], }; let result = new Result(sampleResponse); @@ -43,39 +43,38 @@ describe("A US Zipcode result", function () { expect(result.status).to.equal(undefined); expect(result.reason).to.equal(undefined); - expect(result.cities[0].city).to.equal('1'); - expect(result.cities[0].stateAbbreviation).to.equal('2'); - expect(result.cities[0].state).to.equal('3'); - expect(result.cities[0].mailableCity).to.equal('4'); + expect(result.cities[0].city).to.equal("1"); + expect(result.cities[0].stateAbbreviation).to.equal("2"); + expect(result.cities[0].state).to.equal("3"); + expect(result.cities[0].mailableCity).to.equal("4"); - expect(result.zipcodes[0].zipcode).to.equal('5'); - expect(result.zipcodes[0].zipcodeType).to.equal('6'); - expect(result.zipcodes[0].defaultCity).to.equal('7'); - expect(result.zipcodes[0].countyFips).to.equal('8'); - expect(result.zipcodes[0].countyName).to.equal('9'); + expect(result.zipcodes[0].zipcode).to.equal("5"); + expect(result.zipcodes[0].zipcodeType).to.equal("6"); + expect(result.zipcodes[0].defaultCity).to.equal("7"); + expect(result.zipcodes[0].countyFips).to.equal("8"); + expect(result.zipcodes[0].countyName).to.equal("9"); expect(result.zipcodes[0].latitude).to.equal(10); expect(result.zipcodes[0].longitude).to.equal(11); - expect(result.zipcodes[0].precision).to.equal('12'); - expect(result.zipcodes[0].alternateCounties[0].countyFips).to.equal('13'); - expect(result.zipcodes[0].alternateCounties[0].countyName).to.equal('14'); - expect(result.zipcodes[0].alternateCounties[0].stateAbbreviation).to.equal('15'); - expect(result.zipcodes[0].alternateCounties[0].state).to.equal('16'); - expect(result.zipcodes[0].stateAbbreviation).to.equal('17'); - expect(result.zipcodes[0].state).to.equal('18'); + expect(result.zipcodes[0].precision).to.equal("12"); + expect(result.zipcodes[0].alternateCounties[0].countyFips).to.equal("13"); + expect(result.zipcodes[0].alternateCounties[0].countyName).to.equal("14"); + expect(result.zipcodes[0].alternateCounties[0].stateAbbreviation).to.equal("15"); + expect(result.zipcodes[0].alternateCounties[0].state).to.equal("16"); + expect(result.zipcodes[0].stateAbbreviation).to.equal("17"); + expect(result.zipcodes[0].state).to.equal("18"); expect(result.valid).to.equal(true); }); it("populates accurately on an invalid lookup", function () { let sampleResponse = { - "status": "testing_status", - "reason": "We are testing." + status: "testing_status", + reason: "We are testing.", }; let result = new Result(sampleResponse); expect(result.status).to.equal("testing_status"); expect(result.reason).to.equal("We are testing."); - }); -}); \ No newline at end of file +}); From 729ca7be0c73d331fbdd528efbc78f47766e4c2b Mon Sep 17 00:00:00 2001 From: Ryan Cox Date: Mon, 2 Mar 2026 11:35:25 -0700 Subject: [PATCH 03/29] Add return after reject() in all Client Promise handlers Without the return, code continued executing after reject() and could crash on a null payload. Affects all API Client classes and sendBatch. --- .../Client.js | 42 ------ .../Client.ts | 48 +++++++ src/international_postal_code/Client.js | 49 ------- src/international_postal_code/Client.ts | 44 +++++++ src/international_street/Client.js | 43 ------- src/international_street/Client.ts | 43 +++++++ src/us_autocomplete_pro/Client.js | 42 ------ src/us_autocomplete_pro/Client.ts | 44 +++++++ src/us_enrichment/Client.js | 117 ----------------- src/us_enrichment/Client.ts | 121 ++++++++++++++++++ src/us_extract/Client.js | 36 ------ src/us_extract/Client.ts | 36 ++++++ src/us_reverse_geo/Client.js | 41 ------ src/us_reverse_geo/Client.ts | 41 ++++++ src/util/sendBatch.js | 43 ------- src/util/sendBatch.ts | 51 ++++++++ 16 files changed, 428 insertions(+), 413 deletions(-) delete mode 100644 src/international_address_autocomplete/Client.js create mode 100644 src/international_address_autocomplete/Client.ts delete mode 100644 src/international_postal_code/Client.js create mode 100644 src/international_postal_code/Client.ts delete mode 100644 src/international_street/Client.js create mode 100644 src/international_street/Client.ts delete mode 100644 src/us_autocomplete_pro/Client.js create mode 100644 src/us_autocomplete_pro/Client.ts delete mode 100644 src/us_enrichment/Client.js create mode 100644 src/us_enrichment/Client.ts delete mode 100644 src/us_extract/Client.js create mode 100644 src/us_extract/Client.ts delete mode 100644 src/us_reverse_geo/Client.js create mode 100644 src/us_reverse_geo/Client.ts delete mode 100644 src/util/sendBatch.js create mode 100644 src/util/sendBatch.ts diff --git a/src/international_address_autocomplete/Client.js b/src/international_address_autocomplete/Client.js deleted file mode 100644 index b5ec358..0000000 --- a/src/international_address_autocomplete/Client.js +++ /dev/null @@ -1,42 +0,0 @@ -const Errors = require("../Errors"); -const Request = require("../Request"); -const Suggestion = require("./Suggestion"); -const buildInputData = require("../util/buildInputData"); -const keyTranslationFormat = require("../util/apiToSDKKeyMap").internationalAddressAutocomplete; - -class Client { - constructor(sender) { - this.sender = sender; - } - - send(lookup) { - if (typeof lookup === "undefined") throw new Errors.UndefinedLookupError(); - - let request = new Request(); - request.parameters = buildInputData(lookup, keyTranslationFormat); - - if (lookup.addressId) { - request.baseUrlParam = lookup.addressId; - } - - return new Promise((resolve, reject) => { - this.sender - .send(request) - .then((response) => { - if (response.error) reject(response.error); - - lookup.result = buildSuggestionsFromResponse(response.payload); - resolve(lookup); - }) - .catch(reject); - }); - - function buildSuggestionsFromResponse(payload) { - if (payload && payload.candidates === null) return []; - - return payload.candidates.map((suggestion) => new Suggestion(suggestion)); - } - } -} - -module.exports = Client; diff --git a/src/international_address_autocomplete/Client.ts b/src/international_address_autocomplete/Client.ts new file mode 100644 index 0000000..6a312f0 --- /dev/null +++ b/src/international_address_autocomplete/Client.ts @@ -0,0 +1,48 @@ +import { UndefinedLookupError } from "../Errors.js"; +import Request from "../Request.js"; +import Suggestion from "./Suggestion.js"; +import buildInputData from "../util/buildInputData.js"; +import apiToSDKKeyMap from "../util/apiToSDKKeyMap.js"; +import { Sender } from "../types.js"; +import Lookup from "./Lookup.js"; + +const keyTranslationFormat = apiToSDKKeyMap.internationalAddressAutocomplete; + +export default class Client { + private sender: Sender; + + constructor(sender: Sender) { + this.sender = sender; + } + + send(lookup: Lookup): Promise { + if (typeof lookup === "undefined") throw new UndefinedLookupError(); + + const request = new Request(); + request.parameters = buildInputData(lookup, keyTranslationFormat); + + if (lookup.addressId) { + request.baseUrlParam = lookup.addressId; + } + + return new Promise((resolve, reject) => { + this.sender + .send(request) + .then((response) => { + if (response.error) return reject(response.error); + + lookup.result = buildSuggestionsFromResponse(response.payload as any); + resolve(lookup); + }) + .catch(reject); + }); + + function buildSuggestionsFromResponse(payload: any): Suggestion[] { + if (payload && payload.candidates === null) return []; + + return payload.candidates.map( + (suggestion: Record) => new Suggestion(suggestion), + ); + } + } +} diff --git a/src/international_postal_code/Client.js b/src/international_postal_code/Client.js deleted file mode 100644 index 22ed7c3..0000000 --- a/src/international_postal_code/Client.js +++ /dev/null @@ -1,49 +0,0 @@ -const Request = require("../Request"); -const Result = require("./Result"); -const buildInputData = require("../util/buildInputData"); -const keyTranslationFormat = require("../util/apiToSDKKeyMap").internationalPostalCode; -const { UndefinedLookupError } = require("../Errors"); - -/** - * This client sends lookups to the Smarty International Postal Code API,
- * and attaches the results to the appropriate Lookup objects. - */ -class Client { - constructor(sender) { - this.sender = sender; - } - - /** - * Sends a single lookup for validation. - * @param data A Lookup object - * @throws SmartyException - */ - send(lookup) { - if (typeof lookup === "undefined") throw new UndefinedLookupError(); - - let request = new Request(); - request.parameters = buildInputData(lookup, keyTranslationFormat); - - return new Promise((resolve, reject) => { - this.sender - .send(request) - .then((response) => { - if (response.error) reject(response.error); - - resolve(attachLookupResults(response, lookup)); - }) - .catch(reject); - }); - - function attachLookupResults(response, lookup) { - if (response.payload && Array.isArray(response.payload)) { - lookup.result = response.payload.map((r) => new Result(r)); - } else { - lookup.result = []; - } - return lookup; - } - } -} - -module.exports = Client; diff --git a/src/international_postal_code/Client.ts b/src/international_postal_code/Client.ts new file mode 100644 index 0000000..3ac9e79 --- /dev/null +++ b/src/international_postal_code/Client.ts @@ -0,0 +1,44 @@ +import Request from "../Request.js"; +import Result from "./Result.js"; +import buildInputData from "../util/buildInputData.js"; +import apiToSDKKeyMap from "../util/apiToSDKKeyMap.js"; +import { UndefinedLookupError } from "../Errors.js"; +import { Sender } from "../types.js"; +import Lookup from "./Lookup.js"; + +const keyTranslationFormat = apiToSDKKeyMap.internationalPostalCode; + +export default class Client { + sender: Sender; + + constructor(sender: Sender) { + this.sender = sender; + } + + send(lookup: Lookup): Promise { + if (typeof lookup === "undefined") throw new UndefinedLookupError(); + + const request = new Request(); + request.parameters = buildInputData(lookup, keyTranslationFormat); + + return new Promise((resolve, reject) => { + this.sender + .send(request) + .then((response) => { + if (response.error) return reject(response.error); + + resolve(attachLookupResults(response, lookup)); + }) + .catch(reject); + }); + + function attachLookupResults(response: any, lookup: Lookup): Lookup { + if (response.payload && Array.isArray(response.payload)) { + lookup.result = response.payload.map((r: Record) => new Result(r)); + } else { + lookup.result = []; + } + return lookup; + } + } +} diff --git a/src/international_street/Client.js b/src/international_street/Client.js deleted file mode 100644 index 4bbfeb3..0000000 --- a/src/international_street/Client.js +++ /dev/null @@ -1,43 +0,0 @@ -const Request = require("../Request"); -const Errors = require("../Errors"); -const Candidate = require("./Candidate"); -const buildInputData = require("../util/buildInputData"); -const keyTranslationFormat = require("../util/apiToSDKKeyMap").internationalStreet; - -/** - * This client sends lookups to the Smarty International Street API,
- * and attaches the results to the appropriate Lookup objects. - */ -class Client { - constructor(sender) { - this.sender = sender; - } - - send(lookup) { - if (typeof lookup === "undefined") throw new Errors.UndefinedLookupError(); - - let request = new Request(); - request.parameters = buildInputData(lookup, keyTranslationFormat); - - return new Promise((resolve, reject) => { - this.sender - .send(request) - .then((response) => { - if (response.error) reject(response.error); - - resolve(attachLookupCandidates(response, lookup)); - }) - .catch(reject); - }); - - function attachLookupCandidates(response, lookup) { - response.payload.map((rawCandidate) => { - lookup.result.push(new Candidate(rawCandidate)); - }); - - return lookup; - } - } -} - -module.exports = Client; diff --git a/src/international_street/Client.ts b/src/international_street/Client.ts new file mode 100644 index 0000000..83ea774 --- /dev/null +++ b/src/international_street/Client.ts @@ -0,0 +1,43 @@ +import Request from "../Request.js"; +import { UndefinedLookupError } from "../Errors.js"; +import Candidate from "./Candidate.js"; +import buildInputData from "../util/buildInputData.js"; +import apiToSDKKeyMap from "../util/apiToSDKKeyMap.js"; +import { Sender } from "../types.js"; +import Lookup from "./Lookup.js"; + +const keyTranslationFormat = apiToSDKKeyMap.internationalStreet; + +export default class Client { + sender: Sender; + + constructor(sender: Sender) { + this.sender = sender; + } + + send(lookup: Lookup): Promise { + if (typeof lookup === "undefined") throw new UndefinedLookupError(); + + const request = new Request(); + request.parameters = buildInputData(lookup, keyTranslationFormat); + + return new Promise((resolve, reject) => { + this.sender + .send(request) + .then((response) => { + if (response.error) return reject(response.error); + + resolve(attachLookupCandidates(response, lookup)); + }) + .catch(reject); + }); + + function attachLookupCandidates(response: any, lookup: Lookup): Lookup { + response.payload.map((rawCandidate: Record) => { + lookup.result.push(new Candidate(rawCandidate)); + }); + + return lookup; + } + } +} diff --git a/src/us_autocomplete_pro/Client.js b/src/us_autocomplete_pro/Client.js deleted file mode 100644 index 3b027d5..0000000 --- a/src/us_autocomplete_pro/Client.js +++ /dev/null @@ -1,42 +0,0 @@ -const Errors = require("../Errors"); -const Request = require("../Request"); -const Suggestion = require("./Suggestion"); -const buildInputData = require("../util/buildInputData"); -const keyTranslationFormat = require("../util/apiToSDKKeyMap").usAutocompletePro; - -/** - * This client sends lookups to the Smarty US Autocomplete Pro API,
- * and attaches the suggestions to the appropriate Lookup objects. - */ -class Client { - constructor(sender) { - this.sender = sender; - } - - send(lookup) { - if (typeof lookup === "undefined") throw new Errors.UndefinedLookupError(); - - let request = new Request(); - request.parameters = buildInputData(lookup, keyTranslationFormat); - - return new Promise((resolve, reject) => { - this.sender - .send(request) - .then((response) => { - if (response.error) reject(response.error); - - lookup.result = buildSuggestionsFromResponse(response.payload); - resolve(lookup); - }) - .catch(reject); - }); - - function buildSuggestionsFromResponse(payload) { - if (payload.suggestions === null) return []; - - return payload.suggestions.map((suggestion) => new Suggestion(suggestion)); - } - } -} - -module.exports = Client; diff --git a/src/us_autocomplete_pro/Client.ts b/src/us_autocomplete_pro/Client.ts new file mode 100644 index 0000000..4ba0f5d --- /dev/null +++ b/src/us_autocomplete_pro/Client.ts @@ -0,0 +1,44 @@ +import { UndefinedLookupError } from "../Errors.js"; +import Request from "../Request.js"; +import Suggestion from "./Suggestion.js"; +import buildInputData from "../util/buildInputData.js"; +import apiToSDKKeyMap from "../util/apiToSDKKeyMap.js"; +import { Sender } from "../types.js"; +import Lookup from "./Lookup.js"; + +const keyTranslationFormat = apiToSDKKeyMap.usAutocompletePro; + +export default class Client { + private sender: Sender; + + constructor(sender: Sender) { + this.sender = sender; + } + + send(lookup: Lookup): Promise { + if (typeof lookup === "undefined") throw new UndefinedLookupError(); + + const request = new Request(); + request.parameters = buildInputData(lookup, keyTranslationFormat); + + return new Promise((resolve, reject) => { + this.sender + .send(request) + .then((response) => { + if (response.error) return reject(response.error); + + lookup.result = buildSuggestionsFromResponse(response.payload as any); + resolve(lookup); + }) + .catch(reject); + }); + + function buildSuggestionsFromResponse(payload: any): Suggestion[] { + if (payload.suggestions === null) return []; + + return payload.suggestions.map( + (suggestion: Record) => new Suggestion(suggestion), + ); + } + } +} diff --git a/src/us_enrichment/Client.js b/src/us_enrichment/Client.js deleted file mode 100644 index 5b869d0..0000000 --- a/src/us_enrichment/Client.js +++ /dev/null @@ -1,117 +0,0 @@ -const Errors = require("../Errors"); -const Request = require("../Request"); -const buildInputData = require("../util/buildInputData"); -const { usEnrichment: keyTranslationFormat } = require("../util/apiToSDKKeyMap"); - -class Client { - constructor(sender) { - this.sender = sender; - } - - sendPrincipal(lookup) { - if (typeof lookup === "undefined") throw new Errors.UndefinedLookupError(); - - let request = new Request(); - request.parameters = buildInputData(lookup, keyTranslationFormat); - - request.baseUrlParam = lookup.smartyKey + "/property/principal"; - - return new Promise((resolve, reject) => { - this.sender - .send(request) - .then((response) => { - if (response.error) reject(response.error); - - lookup.response = response.payload; - resolve(lookup); - }) - .catch(reject); - }); - } - - sendFinancial(lookup) { - if (typeof lookup === "undefined") throw new Errors.UndefinedLookupError(); - - let request = new Request(); - request.parameters = buildInputData(lookup, keyTranslationFormat); - - request.baseUrlParam = lookup.smartyKey + "/property/financial"; - - return new Promise((resolve, reject) => { - this.sender - .send(request) - .then((response) => { - if (response.error) reject(response.error); - - lookup.response = response.payload; - resolve(lookup); - }) - .catch(reject); - }); - } - - sendGeo(lookup) { - if (typeof lookup === "undefined") throw new Errors.UndefinedLookupError(); - - let request = new Request(); - request.parameters = buildInputData(lookup, keyTranslationFormat); - - request.baseUrlParam = lookup.smartyKey + "/geo-reference"; - - return new Promise((resolve, reject) => { - this.sender - .send(request) - .then((response) => { - if (response.error) reject(response.error); - - lookup.response = response.payload; - resolve(lookup); - }) - .catch(reject); - }); - } - - sendSecondary(lookup) { - if (typeof lookup === "undefined") throw new Errors.UndefinedLookupError(); - - let request = new Request(); - request.parameters = buildInputData(lookup, keyTranslationFormat); - - request.baseUrlParam = lookup.smartyKey + "/secondary"; - - return new Promise((resolve, reject) => { - this.sender - .send(request) - .then((response) => { - if (response.error) reject(response.error); - - lookup.response = response.payload; - resolve(lookup); - }) - .catch(reject); - }); - } - - sendSecondaryCount(lookup) { - if (typeof lookup === "undefined") throw new Errors.UndefinedLookupError(); - - let request = new Request(); - request.parameters = buildInputData(lookup, keyTranslationFormat); - - request.baseUrlParam = lookup.smartyKey + "/secondary/count"; - - return new Promise((resolve, reject) => { - this.sender - .send(request) - .then((response) => { - if (response.error) reject(response.error); - - lookup.response = response.payload; - resolve(lookup); - }) - .catch(reject); - }); - } -} - -module.exports = Client; diff --git a/src/us_enrichment/Client.ts b/src/us_enrichment/Client.ts new file mode 100644 index 0000000..55b9823 --- /dev/null +++ b/src/us_enrichment/Client.ts @@ -0,0 +1,121 @@ +import { UndefinedLookupError } from "../Errors.js"; +import Request from "../Request.js"; +import buildInputData from "../util/buildInputData.js"; +import apiToSDKKeyMap from "../util/apiToSDKKeyMap.js"; +import { Sender } from "../types.js"; +import Lookup from "./Lookup.js"; + +const keyTranslationFormat = apiToSDKKeyMap.usEnrichment; + +export default class Client { + private sender: Sender; + + constructor(sender: Sender) { + this.sender = sender; + } + + sendPrincipal(lookup: Lookup): Promise { + if (typeof lookup === "undefined") throw new UndefinedLookupError(); + + const request = new Request(); + request.parameters = buildInputData(lookup, keyTranslationFormat); + + request.baseUrlParam = lookup.smartyKey + "/property/principal"; + + return new Promise((resolve, reject) => { + this.sender + .send(request) + .then((response) => { + if (response.error) return reject(response.error); + + lookup.response = response.payload as Record; + resolve(lookup); + }) + .catch(reject); + }); + } + + sendFinancial(lookup: Lookup): Promise { + if (typeof lookup === "undefined") throw new UndefinedLookupError(); + + const request = new Request(); + request.parameters = buildInputData(lookup, keyTranslationFormat); + + request.baseUrlParam = lookup.smartyKey + "/property/financial"; + + return new Promise((resolve, reject) => { + this.sender + .send(request) + .then((response) => { + if (response.error) return reject(response.error); + + lookup.response = response.payload as Record; + resolve(lookup); + }) + .catch(reject); + }); + } + + sendGeo(lookup: Lookup): Promise { + if (typeof lookup === "undefined") throw new UndefinedLookupError(); + + const request = new Request(); + request.parameters = buildInputData(lookup, keyTranslationFormat); + + request.baseUrlParam = lookup.smartyKey + "/geo-reference"; + + return new Promise((resolve, reject) => { + this.sender + .send(request) + .then((response) => { + if (response.error) return reject(response.error); + + lookup.response = response.payload as Record; + resolve(lookup); + }) + .catch(reject); + }); + } + + sendSecondary(lookup: Lookup): Promise { + if (typeof lookup === "undefined") throw new UndefinedLookupError(); + + const request = new Request(); + request.parameters = buildInputData(lookup, keyTranslationFormat); + + request.baseUrlParam = lookup.smartyKey + "/secondary"; + + return new Promise((resolve, reject) => { + this.sender + .send(request) + .then((response) => { + if (response.error) return reject(response.error); + + lookup.response = response.payload as Record; + resolve(lookup); + }) + .catch(reject); + }); + } + + sendSecondaryCount(lookup: Lookup): Promise { + if (typeof lookup === "undefined") throw new UndefinedLookupError(); + + const request = new Request(); + request.parameters = buildInputData(lookup, keyTranslationFormat); + + request.baseUrlParam = lookup.smartyKey + "/secondary/count"; + + return new Promise((resolve, reject) => { + this.sender + .send(request) + .then((response) => { + if (response.error) return reject(response.error); + + lookup.response = response.payload as Record; + resolve(lookup); + }) + .catch(reject); + }); + } +} diff --git a/src/us_extract/Client.js b/src/us_extract/Client.js deleted file mode 100644 index dfc73bf..0000000 --- a/src/us_extract/Client.js +++ /dev/null @@ -1,36 +0,0 @@ -const Errors = require("../Errors"); -const Request = require("../Request"); -const Result = require("./Result"); -const buildInputData = require("../util/buildInputData"); -const keyTranslationFormat = require("../util/apiToSDKKeyMap").usExtract; - -/** - * This client sends lookups to the Smarty US Extract API,
- * and attaches the results to the Lookup objects. - */ -class Client { - constructor(sender) { - this.sender = sender; - } - - send(lookup) { - if (typeof lookup === "undefined") throw new Errors.UndefinedLookupError(); - - let request = new Request(lookup.text, { "Content-Type": "text/plain; charset=utf-8" }); - request.parameters = buildInputData(lookup, keyTranslationFormat); - - return new Promise((resolve, reject) => { - this.sender - .send(request) - .then((response) => { - if (response.error) reject(response.error); - - lookup.result = new Result(response.payload); - resolve(lookup); - }) - .catch(reject); - }); - } -} - -module.exports = Client; diff --git a/src/us_extract/Client.ts b/src/us_extract/Client.ts new file mode 100644 index 0000000..d8a26b4 --- /dev/null +++ b/src/us_extract/Client.ts @@ -0,0 +1,36 @@ +import { UndefinedLookupError } from "../Errors.js"; +import Request from "../Request.js"; +import Result from "./Result.js"; +import buildInputData from "../util/buildInputData.js"; +import apiToSDKKeyMap from "../util/apiToSDKKeyMap.js"; +import { Sender } from "../types.js"; +import Lookup from "./Lookup.js"; + +const keyTranslationFormat = apiToSDKKeyMap.usExtract; + +export default class Client { + private sender: Sender; + + constructor(sender: Sender) { + this.sender = sender; + } + + send(lookup: Lookup): Promise { + if (typeof lookup === "undefined") throw new UndefinedLookupError(); + + const request = new Request(lookup.text, { "Content-Type": "text/plain; charset=utf-8" }); + request.parameters = buildInputData(lookup, keyTranslationFormat); + + return new Promise((resolve, reject) => { + this.sender + .send(request) + .then((response) => { + if (response.error) return reject(response.error); + + lookup.result = new Result(response.payload as any); + resolve(lookup); + }) + .catch(reject); + }); + } +} diff --git a/src/us_reverse_geo/Client.js b/src/us_reverse_geo/Client.js deleted file mode 100644 index c5fcdca..0000000 --- a/src/us_reverse_geo/Client.js +++ /dev/null @@ -1,41 +0,0 @@ -const Request = require("../Request"); -const Response = require("./Response"); -const buildInputData = require("../util/buildInputData"); -const keyTranslationFormat = require("../util/apiToSDKKeyMap").usReverseGeo; -const { UndefinedLookupError } = require("../Errors.js"); - -/** - * This client sends lookups to the Smarty US Reverse Geo API,
- * and attaches the results to the appropriate Lookup objects. - */ -class Client { - constructor(sender) { - this.sender = sender; - } - - send(lookup) { - if (typeof lookup === "undefined") throw new UndefinedLookupError(); - - let request = new Request(); - request.parameters = buildInputData(lookup, keyTranslationFormat); - - return new Promise((resolve, reject) => { - this.sender - .send(request) - .then((response) => { - if (response.error) reject(response.error); - - resolve(attachLookupResults(response, lookup)); - }) - .catch(reject); - }); - - function attachLookupResults(response, lookup) { - lookup.response = new Response(response.payload); - - return lookup; - } - } -} - -module.exports = Client; diff --git a/src/us_reverse_geo/Client.ts b/src/us_reverse_geo/Client.ts new file mode 100644 index 0000000..1ffc4f3 --- /dev/null +++ b/src/us_reverse_geo/Client.ts @@ -0,0 +1,41 @@ +import Request from "../Request.js"; +import Response from "./Response.js"; +import buildInputData from "../util/buildInputData.js"; +import apiToSDKKeyMap from "../util/apiToSDKKeyMap.js"; +import { UndefinedLookupError } from "../Errors.js"; +import { Sender } from "../types.js"; +import Lookup from "./Lookup.js"; + +const keyTranslationFormat = apiToSDKKeyMap.usReverseGeo; + +export default class Client { + sender: Sender; + + constructor(sender: Sender) { + this.sender = sender; + } + + send(lookup: Lookup): Promise { + if (typeof lookup === "undefined") throw new UndefinedLookupError(); + + const request = new Request(); + request.parameters = buildInputData(lookup, keyTranslationFormat); + + return new Promise((resolve, reject) => { + this.sender + .send(request) + .then((response) => { + if (response.error) return reject(response.error); + + resolve(attachLookupResults(response, lookup)); + }) + .catch(reject); + }); + + function attachLookupResults(response: any, lookup: Lookup): Lookup { + lookup.response = new Response(response.payload); + + return lookup; + } + } +} diff --git a/src/util/sendBatch.js b/src/util/sendBatch.js deleted file mode 100644 index 9165f73..0000000 --- a/src/util/sendBatch.js +++ /dev/null @@ -1,43 +0,0 @@ -const Request = require("../Request"); -const Errors = require("../Errors"); -const buildInputData = require("../util/buildInputData"); - -module.exports = (batch, sender, Result, keyTranslationFormat, customBuildInputData) => { - if (batch.isEmpty()) throw new Errors.BatchEmptyError(); - - let request = new Request(); - - if (batch.length() === 1) request.parameters = generateRequestPayload(batch)[0]; - else request.payload = generateRequestPayload(batch); - - return new Promise((resolve, reject) => { - sender - .send(request) - .then((response) => { - if (response.error) reject(response.error); - - resolve(assignResultsToLookups(batch, response)); - }) - .catch(reject); - }); - - function generateRequestPayload(batch) { - return batch.lookups.map((lookup) => { - if (customBuildInputData) { - return customBuildInputData(lookup); - } - return buildInputData(lookup, keyTranslationFormat); - }); - } - - function assignResultsToLookups(batch, response) { - response.payload.map((rawResult) => { - let result = new Result(rawResult); - let lookup = batch.getByIndex(result.inputIndex); - - lookup.result.push(result); - }); - - return batch; - } -}; diff --git a/src/util/sendBatch.ts b/src/util/sendBatch.ts new file mode 100644 index 0000000..19d4965 --- /dev/null +++ b/src/util/sendBatch.ts @@ -0,0 +1,51 @@ +import Request from "../Request.js"; +import { BatchEmptyError } from "../Errors.js"; +import buildInputData from "./buildInputData.js"; +import Batch from "../Batch.js"; +import { Sender } from "../types.js"; + +export default function sendBatch( + batch: Batch, + sender: Sender, + Result: new (data: Record) => any, + keyTranslationFormat: Record | null, + customBuildInputData?: (lookup: Record) => Record, +): Promise { + if (batch.isEmpty()) throw new BatchEmptyError(); + + const request = new Request(); + + if (batch.length() === 1) request.parameters = generateRequestPayload(batch)[0]; + else request.payload = generateRequestPayload(batch); + + return new Promise((resolve, reject) => { + sender + .send(request) + .then((response) => { + if (response.error) return reject(response.error); + + resolve(assignResultsToLookups(batch, response)); + }) + .catch(reject); + }); + + function generateRequestPayload(batch: Batch): Record[] { + return batch.lookups.map((lookup: Record) => { + if (customBuildInputData) { + return customBuildInputData(lookup); + } + return buildInputData(lookup, keyTranslationFormat!); + }); + } + + function assignResultsToLookups(batch: Batch, response: any): Batch { + response.payload.map((rawResult: Record) => { + const result = new Result(rawResult); + const lookup = batch.getByIndex(result.inputIndex); + + lookup.result.push(result); + }); + + return batch; + } +} From 44c6dcd96420623207ba23527c2d763396a4e91b Mon Sep 17 00:00:00 2001 From: Ryan Cox Date: Mon, 2 Mar 2026 11:35:40 -0700 Subject: [PATCH 04/29] Fix withCustomCommaSeperatedQuery undefined bug and HttpSender missing return ClientBuilder: check for undefined instead of "" when building comma-separated query values, preventing "undefined,value" strings. HttpSender: add return after reject() so resolve() doesn't also run on 400+ status responses. --- src/ClientBuilder.js | 306 ------------------------------------------- src/ClientBuilder.ts | 245 ++++++++++++++++++++++++++++++++++ src/HttpSender.js | 66 ---------- src/HttpSender.ts | 69 ++++++++++ 4 files changed, 314 insertions(+), 372 deletions(-) delete mode 100644 src/ClientBuilder.js create mode 100644 src/ClientBuilder.ts delete mode 100644 src/HttpSender.js create mode 100644 src/HttpSender.ts diff --git a/src/ClientBuilder.js b/src/ClientBuilder.js deleted file mode 100644 index 3078f8b..0000000 --- a/src/ClientBuilder.js +++ /dev/null @@ -1,306 +0,0 @@ -const HttpSender = require("./HttpSender"); -const SigningSender = require("./SigningSender"); -const BaseUrlSender = require("./BaseUrlSender"); -const AgentSender = require("./AgentSender"); -const StaticCredentials = require("./StaticCredentials"); -const SharedCredentials = require("./SharedCredentials"); -const BasicAuthCredentials = require("./BasicAuthCredentials"); -const CustomHeaderSender = require("./CustomHeaderSender"); -const StatusCodeSender = require("./StatusCodeSender"); -const LicenseSender = require("./LicenseSender"); -const CustomQuerySender = require("@/src/CustomQuerySender"); -const BadCredentialsError = require("./Errors").BadCredentialsError; -const RetrySender = require("./RetrySender"); -const Sleeper = require("./util/Sleeper.ts"); - -//TODO: refactor this to work more cleanly with a bundler. -const UsStreetClient = require("./us_street/Client"); -const UsZipcodeClient = require("./us_zipcode/Client"); -const UsAutocompleteProClient = require("./us_autocomplete_pro/Client"); -const UsExtractClient = require("./us_extract/Client"); -const InternationalStreetClient = require("./international_street/Client"); -const UsReverseGeoClient = require("./us_reverse_geo/Client"); -const InternationalAddressAutocompleteClient = require("./international_address_autocomplete/Client"); -const UsEnrichmentClient = require("./us_enrichment/Client"); -const InternationalPostalCodeClient = require("./international_postal_code/Client"); - -const INTERNATIONAL_STREET_API_URI = "https://international-street.api.smarty.com/verify"; -const US_AUTOCOMPLETE_PRO_API_URL = "https://us-autocomplete-pro.api.smarty.com/lookup"; -const US_EXTRACT_API_URL = "https://us-extract.api.smarty.com/"; -const US_STREET_API_URL = "https://us-street.api.smarty.com/street-address"; -const US_ZIP_CODE_API_URL = "https://us-zipcode.api.smarty.com/lookup"; -const US_REVERSE_GEO_API_URL = "https://us-reverse-geo.api.smarty.com/lookup"; -const INTERNATIONAL_ADDRESS_AUTOCOMPLETE_API_URL = - "https://international-autocomplete.api.smarty.com/v2/lookup"; -const US_ENRICHMENT_API_URL = "https://us-enrichment.api.smarty.com/lookup"; -const INTERNATIONAL_POSTAL_CODE_API_URL = "https://international-postal-code.api.smarty.com/lookup"; -/** - * The ClientBuilder class helps you build a client object for one of the supported Smarty APIs.
- * You can use ClientBuilder's methods to customize settings like maximum retries or timeout duration. These methods
- * are chainable, so you can usually get set up with one line of code. - */ -class ClientBuilder { - constructor(signer) { - if (!credentialsProvided()) throw new BadCredentialsError(); - - this.signer = signer; - this.httpSender = undefined; - this.maxRetries = 5; - this.maxTimeout = 10000; - this.baseUrl = undefined; - this.proxy = undefined; - this.customHeaders = {}; - this.appendHeaders = {}; - this.debug = undefined; - this.licenses = []; - this.customQueries = new Map(); - - function credentialsProvided() { - return ( - signer instanceof StaticCredentials || - signer instanceof SharedCredentials || - signer instanceof BasicAuthCredentials - ); - } - } - - /** - * @param retries The maximum number of times to retry sending the request to the API. (Default is 5) - * @return ClientBuilder this to accommodate method chaining. - */ - withMaxRetries(retries) { - this.maxRetries = retries; - return this; - } - - /** - * @param timeout The maximum time (in milliseconds) to wait for a connection, and also to wait for
- * the response to be read. (Default is 10000) - * @return ClientBuilder this to accommodate method chaining. - */ - withMaxTimeout(timeout) { - this.maxTimeout = timeout; - return this; - } - - /** - * @param sender Default is a series of nested senders. See buildSender(). - * @return ClientBuilder this to accommodate method chaining. - */ - withSender(sender) { - this.httpSender = sender; - return this; - } - - /** - * This may be useful when using a local installation of the Smarty APIs. - * @param url Defaults to the URL for the API corresponding to the Client object being built. - * @return ClientBuilder this to accommodate method chaining. - */ - withBaseUrl(url) { - this.baseUrl = url; - return this; - } - - /** - * Use this to specify a proxy through which to send all lookups. - * @param host The host of the proxy server (do not include the port). - * @param port The port on the proxy server to which you wish to connect. - * @param protocol The protocol on the proxy server to which you wish to connect. If the proxy server uses HTTPS, then you must set the protocol to 'https'. - * @param username The username to login to the proxy. - * @param password The password to login to the proxy. - * @return ClientBuilder this to accommodate method chaining. - */ - withProxy(host, port, protocol, username, password) { - this.proxy = { - host: host, - port: port, - protocol: protocol, - }; - - if (username && password) { - this.proxy.auth = { - username: username, - password: password, - }; - } - - return this; - } - - /** - * Use this to add any additional headers you need. - * @param customHeaders A String to Object Map of header name/value pairs. - * @return ClientBuilder this to accommodate method chaining. - */ - withCustomHeaders(customHeaders) { - this.customHeaders = customHeaders; - return this; - } - - /** - * Appends the provided value to the existing header value using the specified separator, - * rather than replacing it. This is useful for single-value headers like User-Agent. - * @param key The header name. - * @param value The value to append. - * @param separator The separator to use when joining values. - * @return ClientBuilder this to accommodate method chaining. - */ - withAppendedHeader(key, value, separator) { - if (this.appendHeaders[key]) { - if (this.appendHeaders[key].separator !== separator) { - throw new Error( - `Conflicting separators for appended header "${key}": ` + - `existing "${this.appendHeaders[key].separator}" vs new "${separator}"`, - ); - } - this.appendHeaders[key].values.push(value); - } else { - this.appendHeaders[key] = { values: [value], separator }; - } - return this; - } - - /** - * Enables debug mode, which will print information about the HTTP request and response to console.log - * @return ClientBuilder this to accommodate method chaining. - */ - withDebug() { - this.debug = true; - return this; - } - - /** - * Allows the caller to specify the subscription license (aka "track") they wish to use. - * @param licenses A String Array of licenses. - * @returns ClientBuilder this to accommodate method chaining. - */ - withLicenses(licenses) { - this.licenses = licenses; - return this; - } - - /** - * Allows the caller to specify key and value pair that is added to the request - * @param {string} key - The query parameter key - * @param {string} value - The query parameter value - * @return ClientBuilder this to accommodate method chaining. - */ - withCustomQuery(key, value) { - this.customQueries.set(key, value); - return this; - } - - /** - * Allows the caller to specify key and value pair and appends the value associated with the key, seperated by a comma. - * @param {string} key - The query parameter key - * @param {string} value - The query parameter value - * @return ClientBuilder this to accommodate method chaining. - */ - withCustomCommaSeperatedQuery(key, value) { - let values = this.customQueries.get(key); - if (values === "") { - values = value; - } else { - values += "," + value; - } - this.customQueries.set(key, values); - return this; - } - - /** - * Adds to the request query to use the component analysis feature. - * @return ClientBuilder this to accommodate method chaining. - */ - withFeatureComponentAnalysis() { - return this.withCustomCommaSeperatedQuery("features", "component-analysis"); - } - - /** - * Adds to the request query to use the financial history feature. - * @return ClientBuilder this to accommodate method chaining. - */ - withFinancialHistory() { - return this.withCustomCommaSeperatedQuery("features", "financial"); - } - - /** - * Adds to the request query to use the occupant use feature. - * @return ClientBuilder this to accommodate method chaining. - */ - withOccupantUse() { - return this.withCustomCommaSeperatedQuery("features", "occupant-use"); - } - - buildSender() { - if (this.httpSender) return this.httpSender; - - const httpSender = new HttpSender(this.maxTimeout, this.proxy, this.debug); - const statusCodeSender = new StatusCodeSender(httpSender); - const signingSender = new SigningSender(statusCodeSender, this.signer); - let agentSender = new AgentSender(signingSender); - if (this.maxRetries > 0) { - const retrySender = new RetrySender(this.maxRetries, signingSender, new Sleeper()); - agentSender = new AgentSender(retrySender); - } - const customHeaderSender = new CustomHeaderSender( - agentSender, - this.customHeaders, - this.appendHeaders, - ); - const baseUrlSender = new BaseUrlSender(customHeaderSender, this.baseUrl); - const licenseSender = new LicenseSender(baseUrlSender, this.licenses); - const customQuerySender = new CustomQuerySender(licenseSender, this.customQueries); - - return customQuerySender; - } - - buildClient(baseUrl, Client) { - if (!this.baseUrl) { - this.baseUrl = baseUrl; - } - - return new Client(this.buildSender()); - } - - buildUsStreetApiClient() { - return this.buildClient(US_STREET_API_URL, UsStreetClient); - } - - buildUsZipcodeClient() { - return this.buildClient(US_ZIP_CODE_API_URL, UsZipcodeClient); - } - - buildInternationalPostalCodeClient() { - return this.buildClient(INTERNATIONAL_POSTAL_CODE_API_URL, InternationalPostalCodeClient); - } - - buildUsAutocompleteProClient() { - return this.buildClient(US_AUTOCOMPLETE_PRO_API_URL, UsAutocompleteProClient); - } - - buildUsExtractClient() { - return this.buildClient(US_EXTRACT_API_URL, UsExtractClient); - } - - buildInternationalStreetClient() { - return this.buildClient(INTERNATIONAL_STREET_API_URI, InternationalStreetClient); - } - - buildUsReverseGeoClient() { - return this.buildClient(US_REVERSE_GEO_API_URL, UsReverseGeoClient); - } - - buildInternationalAddressAutocompleteClient() { - return this.buildClient( - INTERNATIONAL_ADDRESS_AUTOCOMPLETE_API_URL, - InternationalAddressAutocompleteClient, - ); - } - - buildUsEnrichmentClient() { - return this.buildClient(US_ENRICHMENT_API_URL, UsEnrichmentClient); - } -} - -module.exports = ClientBuilder; diff --git a/src/ClientBuilder.ts b/src/ClientBuilder.ts new file mode 100644 index 0000000..4140fd7 --- /dev/null +++ b/src/ClientBuilder.ts @@ -0,0 +1,245 @@ +import HttpSender from "./HttpSender.js"; +import SigningSender from "./SigningSender.js"; +import BaseUrlSender from "./BaseUrlSender.js"; +import AgentSender from "./AgentSender.js"; +import StaticCredentials from "./StaticCredentials.js"; +import SharedCredentials from "./SharedCredentials.js"; +import BasicAuthCredentials from "./BasicAuthCredentials.js"; +import CustomHeaderSender, { AppendHeader } from "./CustomHeaderSender.js"; +import StatusCodeSender from "./StatusCodeSender.js"; +import LicenseSender from "./LicenseSender.js"; +import CustomQuerySender from "./CustomQuerySender.js"; +import { BadCredentialsError } from "./Errors.js"; +import RetrySender from "./RetrySender.js"; +import Sleeper from "./util/Sleeper.js"; + +import UsStreetClient from "./us_street/Client.js"; +import UsZipcodeClient from "./us_zipcode/Client.js"; +import UsAutocompleteProClient from "./us_autocomplete_pro/Client.js"; +import UsExtractClient from "./us_extract/Client.js"; +import InternationalStreetClient from "./international_street/Client.js"; +import UsReverseGeoClient from "./us_reverse_geo/Client.js"; +import InternationalAddressAutocompleteClient from "./international_address_autocomplete/Client.js"; +import UsEnrichmentClient from "./us_enrichment/Client.js"; +import InternationalPostalCodeClient from "./international_postal_code/Client.js"; +import { Sender } from "./types.js"; + +const INTERNATIONAL_STREET_API_URI = "https://international-street.api.smarty.com/verify"; +const US_AUTOCOMPLETE_PRO_API_URL = "https://us-autocomplete-pro.api.smarty.com/lookup"; +const US_EXTRACT_API_URL = "https://us-extract.api.smarty.com/"; +const US_STREET_API_URL = "https://us-street.api.smarty.com/street-address"; +const US_ZIP_CODE_API_URL = "https://us-zipcode.api.smarty.com/lookup"; +const US_REVERSE_GEO_API_URL = "https://us-reverse-geo.api.smarty.com/lookup"; +const INTERNATIONAL_ADDRESS_AUTOCOMPLETE_API_URL = + "https://international-autocomplete.api.smarty.com/v2/lookup"; +const US_ENRICHMENT_API_URL = "https://us-enrichment.api.smarty.com/lookup"; +const INTERNATIONAL_POSTAL_CODE_API_URL = "https://international-postal-code.api.smarty.com/lookup"; + +type Signer = StaticCredentials | SharedCredentials | BasicAuthCredentials; + +export default class ClientBuilder { + private signer: Signer; + private httpSender: Sender | undefined; + private maxRetries: number; + private maxTimeout: number; + private baseUrl: string | undefined; + private proxy: any; + private customHeaders: Record; + private appendHeaders: Record; + private debug: boolean | undefined; + private licenses: string[]; + private customQueries: Map; + + constructor(signer: Signer) { + if ( + !( + signer instanceof StaticCredentials || + signer instanceof SharedCredentials || + signer instanceof BasicAuthCredentials + ) + ) + throw new BadCredentialsError(); + + this.signer = signer; + this.httpSender = undefined; + this.maxRetries = 5; + this.maxTimeout = 10000; + this.baseUrl = undefined; + this.proxy = undefined; + this.customHeaders = {}; + this.appendHeaders = {}; + this.debug = undefined; + this.licenses = []; + this.customQueries = new Map(); + } + + withMaxRetries(retries: number): ClientBuilder { + this.maxRetries = retries; + return this; + } + + withMaxTimeout(timeout: number): ClientBuilder { + this.maxTimeout = timeout; + return this; + } + + withSender(sender: Sender): ClientBuilder { + this.httpSender = sender; + return this; + } + + withBaseUrl(url: string): ClientBuilder { + this.baseUrl = url; + return this; + } + + withProxy( + host: string, + port: number, + protocol: string, + username?: string, + password?: string, + ): ClientBuilder { + this.proxy = { + host: host, + port: port, + protocol: protocol, + }; + + if (username && password) { + this.proxy.auth = { + username: username, + password: password, + }; + } + + return this; + } + + withCustomHeaders(customHeaders: Record): ClientBuilder { + this.customHeaders = customHeaders; + return this; + } + + withAppendedHeader(key: string, value: string, separator: string): ClientBuilder { + if (this.appendHeaders[key]) { + if (this.appendHeaders[key].separator !== separator) { + throw new Error( + `Conflicting separators for appended header "${key}": ` + + `existing "${this.appendHeaders[key].separator}" vs new "${separator}"`, + ); + } + this.appendHeaders[key].values.push(value); + } else { + this.appendHeaders[key] = { values: [value], separator }; + } + return this; + } + + withDebug(): ClientBuilder { + this.debug = true; + return this; + } + + withLicenses(licenses: string[]): ClientBuilder { + this.licenses = licenses; + return this; + } + + withCustomQuery(key: string, value: string): ClientBuilder { + this.customQueries.set(key, value); + return this; + } + + withCustomCommaSeperatedQuery(key: string, value: string): ClientBuilder { + const values = this.customQueries.get(key); + if (values === undefined) { + this.customQueries.set(key, value); + } else { + this.customQueries.set(key, values + "," + value); + } + return this; + } + + withFeatureComponentAnalysis(): ClientBuilder { + return this.withCustomCommaSeperatedQuery("features", "component-analysis"); + } + + withFinancialHistory(): ClientBuilder { + return this.withCustomCommaSeperatedQuery("features", "financial"); + } + + withOccupantUse(): ClientBuilder { + return this.withCustomCommaSeperatedQuery("features", "occupant-use"); + } + + buildSender(): Sender { + if (this.httpSender) return this.httpSender; + + const httpSender = new HttpSender(this.maxTimeout, this.proxy, this.debug); + const statusCodeSender = new StatusCodeSender(httpSender); + const signingSender = new SigningSender(statusCodeSender, this.signer); + let agentSender = new AgentSender(signingSender); + if (this.maxRetries > 0) { + const retrySender = new RetrySender(this.maxRetries, signingSender, new Sleeper()); + agentSender = new AgentSender(retrySender); + } + const customHeaderSender = new CustomHeaderSender( + agentSender, + this.customHeaders, + this.appendHeaders, + ); + const baseUrlSender = new BaseUrlSender(customHeaderSender, this.baseUrl!); + const licenseSender = new LicenseSender(baseUrlSender, this.licenses); + const customQuerySender = new CustomQuerySender(licenseSender, this.customQueries); + + return customQuerySender; + } + + buildClient(baseUrl: string, ClientClass: new (sender: Sender) => any): any { + if (!this.baseUrl) { + this.baseUrl = baseUrl; + } + + return new ClientClass(this.buildSender()); + } + + buildUsStreetApiClient(): UsStreetClient { + return this.buildClient(US_STREET_API_URL, UsStreetClient); + } + + buildUsZipcodeClient(): UsZipcodeClient { + return this.buildClient(US_ZIP_CODE_API_URL, UsZipcodeClient); + } + + buildInternationalPostalCodeClient(): InternationalPostalCodeClient { + return this.buildClient(INTERNATIONAL_POSTAL_CODE_API_URL, InternationalPostalCodeClient); + } + + buildUsAutocompleteProClient(): UsAutocompleteProClient { + return this.buildClient(US_AUTOCOMPLETE_PRO_API_URL, UsAutocompleteProClient); + } + + buildUsExtractClient(): UsExtractClient { + return this.buildClient(US_EXTRACT_API_URL, UsExtractClient); + } + + buildInternationalStreetClient(): InternationalStreetClient { + return this.buildClient(INTERNATIONAL_STREET_API_URI, InternationalStreetClient); + } + + buildUsReverseGeoClient(): UsReverseGeoClient { + return this.buildClient(US_REVERSE_GEO_API_URL, UsReverseGeoClient); + } + + buildInternationalAddressAutocompleteClient(): InternationalAddressAutocompleteClient { + return this.buildClient( + INTERNATIONAL_ADDRESS_AUTOCOMPLETE_API_URL, + InternationalAddressAutocompleteClient, + ); + } + + buildUsEnrichmentClient(): UsEnrichmentClient { + return this.buildClient(US_ENRICHMENT_API_URL, UsEnrichmentClient); + } +} diff --git a/src/HttpSender.js b/src/HttpSender.js deleted file mode 100644 index 6bc9f96..0000000 --- a/src/HttpSender.js +++ /dev/null @@ -1,66 +0,0 @@ -const Axios = require("axios"); -const { buildSmartyResponse } = require("../src/util/buildSmartyResponse"); - -class HttpSender { - constructor(timeout = 10000, proxyConfig, debug = false) { - this.axiosInstance = Axios.create(); - this.timeout = timeout; - this.proxyConfig = proxyConfig; - if (debug) this.enableDebug(); - } - - buildRequestConfig({ payload, parameters, headers, baseUrl }) { - let config = { - method: "GET", - timeout: this.timeout, - params: parameters, - headers: headers, - baseURL: baseUrl, - validateStatus: function (status) { - return status < 500; - }, - }; - - if (payload) { - config.method = "POST"; - config.data = payload; - } - - if (this.proxyConfig) config.proxy = this.proxyConfig; - return config; - } - - send(request) { - return new Promise((resolve, reject) => { - let requestConfig = this.buildRequestConfig(request); - - this.axiosInstance(requestConfig) - .then((response) => { - let smartyResponse = buildSmartyResponse(response); - - if (smartyResponse.statusCode >= 400) reject(smartyResponse); - - resolve(smartyResponse); - }) - .catch((error) => reject(buildSmartyResponse(undefined, error))); - }); - } - - enableDebug() { - this.axiosInstance.interceptors.request.use((request) => { - console.log("Request:\r\n", request); - console.log("\r\n*******************************************\r\n"); - return request; - }); - - this.axiosInstance.interceptors.response.use((response) => { - console.log("Response:\r\n"); - console.log("Status:", response.status, response.statusText); - console.log("Headers:", response.headers); - console.log("Data:", response.data); - return response; - }); - } -} - -module.exports = HttpSender; diff --git a/src/HttpSender.ts b/src/HttpSender.ts new file mode 100644 index 0000000..901e8dd --- /dev/null +++ b/src/HttpSender.ts @@ -0,0 +1,69 @@ +import Axios, { AxiosInstance, AxiosProxyConfig, AxiosRequestConfig } from "axios"; +import { buildSmartyResponse } from "./util/buildSmartyResponse.js"; +import { Request as SmartyRequest, Response as SmartyResponse } from "./types.js"; + +export default class HttpSender { + private axiosInstance: AxiosInstance; + private timeout: number; + private proxyConfig: AxiosProxyConfig | undefined; + + constructor(timeout: number = 10000, proxyConfig?: AxiosProxyConfig, debug: boolean = false) { + this.axiosInstance = Axios.create(); + this.timeout = timeout; + this.proxyConfig = proxyConfig; + if (debug) this.enableDebug(); + } + + buildRequestConfig(request: SmartyRequest): AxiosRequestConfig { + const config: AxiosRequestConfig = { + method: "GET", + timeout: this.timeout, + params: request.parameters, + headers: request.headers, + baseURL: request.baseUrl, + validateStatus: function (status: number) { + return status < 500; + }, + }; + + if (request.payload) { + config.method = "POST"; + config.data = request.payload; + } + + if (this.proxyConfig) config.proxy = this.proxyConfig; + return config; + } + + send(request: SmartyRequest): Promise { + return new Promise((resolve, reject) => { + const requestConfig = this.buildRequestConfig(request); + + this.axiosInstance(requestConfig) + .then((response) => { + const smartyResponse = buildSmartyResponse(response); + + if (smartyResponse.statusCode >= 400) return reject(smartyResponse); + + resolve(smartyResponse); + }) + .catch((error) => reject(buildSmartyResponse(undefined, error))); + }); + } + + private enableDebug(): void { + this.axiosInstance.interceptors.request.use((request) => { + console.log("Request:\r\n", request); + console.log("\r\n*******************************************\r\n"); + return request; + }); + + this.axiosInstance.interceptors.response.use((response) => { + console.log("Response:\r\n"); + console.log("Status:", response.status, response.statusText); + console.log("Headers:", response.headers); + console.log("Data:", response.data); + return response; + }); + } +} From 7ea448728e460ae2ebc4fb3f1b8fa63853120213 Mon Sep 17 00:00:00 2001 From: Ryan Cox Date: Mon, 2 Mar 2026 11:35:52 -0700 Subject: [PATCH 05/29] Fix async test assertions that were silently passing Add missing return before client.send().then() so Mocha awaits the assertions. Remove erroneous JSON.stringify() on mock payloads, and fix us_zipcode test to assert on an actual Result field (status) instead of a nonexistent city property. --- .../{test_Client.js => test_Client.ts} | 35 ++++++------- .../{test_Client.js => test_Client.ts} | 50 +++++++++---------- 2 files changed, 38 insertions(+), 47 deletions(-) rename tests/us_street/{test_Client.js => test_Client.ts} (89%) rename tests/us_zipcode/{test_Client.js => test_Client.ts} (72%) diff --git a/tests/us_street/test_Client.js b/tests/us_street/test_Client.ts similarity index 89% rename from tests/us_street/test_Client.js rename to tests/us_street/test_Client.ts index 38ab011..d627cd3 100644 --- a/tests/us_street/test_Client.js +++ b/tests/us_street/test_Client.ts @@ -1,25 +1,21 @@ -const chai = require("chai"); -const expect = chai.expect; -const Client = require("../../src/us_street/Client"); -const Lookup = require("../../src/us_street/Lookup"); -const Candidate = require("../../src/us_street/Candidate"); -const Batch = require("../../src/Batch"); -const errors = require("../../src/Errors"); -const MockSender = require("../fixtures/mock_senders").MockSender; -const MockSenderWithResponse = require("../fixtures/mock_senders").MockSenderWithResponse; +import { expect } from "chai"; +import Client from "../../src/us_street/Client.js"; +import Lookup from "../../src/us_street/Lookup.js"; +import Candidate from "../../src/us_street/Candidate.js"; +import Batch from "../../src/Batch.js"; +import errors from "../../src/Errors.js"; +import { MockSender, MockSenderWithResponse } from "../fixtures/mock_senders.js"; describe("A US Street client", function () { it("calls its inner sender's send function.", function () { const mockSender = { - send: function (request) { + send: function (_request: any) { sentFlag = true; - mockSenderRequest = request; }, }; - const client = new Client(mockSender); + const client = new Client(mockSender as any); let lookup = new Lookup(); let sentFlag = false; - let mockSenderRequest = {}; client.send(lookup); @@ -29,7 +25,7 @@ describe("A US Street client", function () { it("builds a request for a single lookup with the correct request parameters.", function () { let mockSender = new MockSender(); const client = new Client(mockSender); - let lookup = new Lookup("1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"); + let lookup = new Lookup("1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11" as any, "12"); let expectedParameters = { street: "1", street2: "2", @@ -181,7 +177,6 @@ describe("A US Street client", function () { let lookup = new Lookup(); lookup.street = "123 Main St"; lookup.match = "invalid"; - // maxCandidates left undefined - should NOT default to 5 for non-enhanced let expectedParameters = { street: "123 Main St", match: "invalid", @@ -223,18 +218,18 @@ describe("A US Street client", function () { let lookup = new Lookup(); let expectedResult = new Candidate({ delivery_line_1: "An address", input_index: 0 }); - return client.send(lookup).then((response) => { + return client.send(lookup).then((_response) => { expect(lookup.result[0]).to.deep.equal(expectedResult); }); }); it("attaches match candidates to their corresponding lookups.", function () { - const expectedMockPayload = JSON.stringify([ + const expectedMockPayload = [ { delivery_line_1: "Address 0", input_index: 0 }, { delivery_line_1: "Alternate address 0", input_index: 0 }, { delivery_line_1: "Address 1", input_index: 1 }, { delivery_line_1: "Address 3", input_index: 3 }, - ]); + ]; let mockSender = new MockSenderWithResponse(expectedMockPayload); let client = new Client(mockSender); let lookup0 = new Lookup(); @@ -248,7 +243,7 @@ describe("A US Street client", function () { batch.add(lookup2); batch.add(lookup3); - client.send(batch).then((response) => { + return client.send(batch).then((_response) => { expect(batch.getByIndex(0).result[0].deliveryLine1).to.equal("Address 0"); expect(batch.getByIndex(0).result[1].deliveryLine1).to.equal("Alternate address 0"); expect(batch.getByIndex(1).result[0].deliveryLine1).to.equal("Address 1"); @@ -272,7 +267,7 @@ describe("A US Street client", function () { let mockSender = new MockSender(); let client = new Client(mockSender); - expect(() => client.send()).to.throw(errors.UndefinedLookupError); + expect(() => (client.send as any)()).to.throw(errors.UndefinedLookupError); }); it("attaches request parameters for batches with a single lookup and a request payload for batches with more than 1 lookup.", function () { diff --git a/tests/us_zipcode/test_Client.js b/tests/us_zipcode/test_Client.ts similarity index 72% rename from tests/us_zipcode/test_Client.js rename to tests/us_zipcode/test_Client.ts index b00f8d7..2875818 100644 --- a/tests/us_zipcode/test_Client.js +++ b/tests/us_zipcode/test_Client.ts @@ -1,26 +1,22 @@ -let chai = require("chai"); -const expect = chai.expect; -const Client = require("../../src/us_zipcode/Client"); -const Lookup = require("../../src/us_zipcode/Lookup"); -const Result = require("../../src/us_zipcode/Result"); -const Batch = require("../../src/Batch"); -const errors = require("../../src/Errors"); -const MockSender = require("../fixtures/mock_senders").MockSender; -const MockSenderWithResponse = require("../fixtures/mock_senders").MockSenderWithResponse; +import { expect } from "chai"; +import Client from "../../src/us_zipcode/Client.js"; +import Lookup from "../../src/us_zipcode/Lookup.js"; +import Result from "../../src/us_zipcode/Result.js"; +import Batch from "../../src/Batch.js"; +import errors from "../../src/Errors.js"; +import { MockSender, MockSenderWithResponse } from "../fixtures/mock_senders.js"; describe("A US Zipcode client", function () { it("calls its inner sender's send function.", function () { const mockSender = { - send: function (request) { + send: function (_request: any) { sentFlag = true; - mockSenderRequest = request; - return new Promise((resolve, reject) => {}); + return new Promise((_resolve) => {}); }, }; - const client = new Client(mockSender); + const client = new Client(mockSender as any); let lookup = new Lookup(); let sentFlag = false; - let mockSenderRequest = {}; client.send(lookup); @@ -60,18 +56,18 @@ describe("A US Zipcode client", function () { let lookup = new Lookup(); let expectedResult = new Result({ input_index: 0 }); - return client.send(lookup).then((response) => { + return client.send(lookup).then((_response) => { expect(lookup.result[0]).to.deep.equal(expectedResult); }); }); it("attaches match candidates to their corresponding lookups.", function () { - const expectedMockPayload = JSON.stringify([ - { city: "City 0", input_index: 0 }, - { city: "Alternate city 0", input_index: 0 }, - { city: "City 1", input_index: 1 }, - { city: "City 3", input_index: 3 }, - ]); + const expectedMockPayload = [ + { status: "Status 0", input_index: 0 }, + { status: "Alternate status 0", input_index: 0 }, + { status: "Status 1", input_index: 1 }, + { status: "Status 3", input_index: 3 }, + ]; let mockSender = new MockSenderWithResponse(expectedMockPayload); let client = new Client(mockSender); let lookup0 = new Lookup(); @@ -85,12 +81,12 @@ describe("A US Zipcode client", function () { batch.add(lookup2); batch.add(lookup3); - client.send(batch).then((response) => { - expect(batch.getByIndex(0).result[0].city).to.equal("City 0"); - expect(batch.getByIndex(0).result[1].city).to.equal("Alternate city 0"); - expect(batch.getByIndex(1).result[0].city).to.equal("City 1"); + return client.send(batch).then((_response) => { + expect(batch.getByIndex(0).result[0].status).to.equal("Status 0"); + expect(batch.getByIndex(0).result[1].status).to.equal("Alternate status 0"); + expect(batch.getByIndex(1).result[0].status).to.equal("Status 1"); expect(batch.getByIndex(2).result).to.deep.equal([]); - expect(batch.getByIndex(3).result[0].city).to.equal("City 3"); + expect(batch.getByIndex(3).result[0].status).to.equal("Status 3"); }); }); @@ -127,7 +123,7 @@ describe("A US Zipcode client", function () { let mockSender = new MockSender(); let client = new Client(mockSender); - expect(() => client.send()).to.throw(errors.UndefinedLookupError); + expect(() => (client.send as any)()).to.throw(errors.UndefinedLookupError); }); it("builds a request for a single lookup with the correct request parameters.", function () { From 5bc1e4382e0c6a22d49faa5c95bcb28b5f4a62a8 Mon Sep 17 00:00:00 2001 From: Ryan Cox Date: Mon, 2 Mar 2026 11:42:55 -0700 Subject: [PATCH 06/29] Replace type-unsafe statusCode values with 0 sentinel buildSmartyResponse: use 0 instead of double-casting undefined to bypass the type system for error responses with no HTTP status. MockSenderWithResponse: use 0 instead of "" as any for statusCode. --- src/util/buildSmartyResponse.js | 11 ------ src/util/buildSmartyResponse.ts | 7 ++++ tests/fixtures/mock_senders.js | 47 ------------------------ tests/fixtures/mock_senders.ts | 65 +++++++++++++++++++++++++++++++++ 4 files changed, 72 insertions(+), 58 deletions(-) delete mode 100644 src/util/buildSmartyResponse.js create mode 100644 src/util/buildSmartyResponse.ts delete mode 100644 tests/fixtures/mock_senders.js create mode 100644 tests/fixtures/mock_senders.ts diff --git a/src/util/buildSmartyResponse.js b/src/util/buildSmartyResponse.js deleted file mode 100644 index 86dc0d5..0000000 --- a/src/util/buildSmartyResponse.js +++ /dev/null @@ -1,11 +0,0 @@ -const Response = require("../Response.js"); - -function buildSmartyResponse(response, error) { - if (response) - return new Response(response.status, response.data, response.error, response.headers); - return new Response(undefined, undefined, error); -} - -module.exports = { - buildSmartyResponse, -}; diff --git a/src/util/buildSmartyResponse.ts b/src/util/buildSmartyResponse.ts new file mode 100644 index 0000000..3078096 --- /dev/null +++ b/src/util/buildSmartyResponse.ts @@ -0,0 +1,7 @@ +import Response from "../Response.js"; + +export function buildSmartyResponse(response?: Record, error?: Error): Response { + if (response) + return new Response(response.status, response.data, response.error, response.headers); + return new Response(0, null, error); +} diff --git a/tests/fixtures/mock_senders.js b/tests/fixtures/mock_senders.js deleted file mode 100644 index f8af607..0000000 --- a/tests/fixtures/mock_senders.js +++ /dev/null @@ -1,47 +0,0 @@ -const { buildSmartyResponse } = require("../../src/util/buildSmartyResponse.js"); -const Response = require("../../src/Response"); - -module.exports = { - MockSender: function () { - let request = { - payload: undefined, - parameters: undefined, - baseUrlParam: undefined, - }; - this.request = request; - - this.send = function (clientRequest) { - request.payload = clientRequest.payload; - request.parameters = clientRequest.parameters; - request.baseUrlParam = clientRequest.baseUrlParam; - }; - }, - MockSenderWithResponse: function (expectedPayload, expectedError) { - this.send = function () { - return new Promise((resolve, reject) => { - resolve(new Response("", expectedPayload, expectedError)); - }); - }; - }, - MockSenderWithStatusCodesAndHeaders: function ( - statusCodes, - headers = undefined, - error = undefined, - ) { - this.statusCodes = statusCodes; - this.headers = headers; - this.error = error; - this.currentStatusCodeIndex = 0; - - this.send = function (request) { - let mockResponse = { - status: this.statusCodes[this.currentStatusCodeIndex], - headers: this.headers, - error: this.error, - }; - const response = buildSmartyResponse(mockResponse); - this.currentStatusCodeIndex += 1; - return response; - }; - }, -}; diff --git a/tests/fixtures/mock_senders.ts b/tests/fixtures/mock_senders.ts new file mode 100644 index 0000000..a9c7c52 --- /dev/null +++ b/tests/fixtures/mock_senders.ts @@ -0,0 +1,65 @@ +import { buildSmartyResponse } from "../../src/util/buildSmartyResponse.js"; +import Response from "../../src/Response.js"; + +export class MockSender { + request: { + payload: any; + parameters: any; + baseUrlParam: any; + }; + + constructor() { + this.request = { + payload: undefined, + parameters: undefined, + baseUrlParam: undefined, + }; + } + + send(clientRequest: any): any { + this.request.payload = clientRequest.payload; + this.request.parameters = clientRequest.parameters; + this.request.baseUrlParam = clientRequest.baseUrlParam; + } +} + +export class MockSenderWithResponse { + private expectedPayload: any; + private expectedError: any; + + constructor(expectedPayload: any, expectedError?: any) { + this.expectedPayload = expectedPayload; + this.expectedError = expectedError; + } + + send(): Promise { + return new Promise((resolve) => { + resolve(new Response(0, this.expectedPayload, this.expectedError)); + }); + } +} + +export class MockSenderWithStatusCodesAndHeaders { + statusCodes: any[]; + headers: any; + error: any; + currentStatusCodeIndex: number; + + constructor(statusCodes: any[], headers?: any, error?: any) { + this.statusCodes = statusCodes; + this.headers = headers; + this.error = error; + this.currentStatusCodeIndex = 0; + } + + send(_request: any) { + const mockResponse = { + status: this.statusCodes[this.currentStatusCodeIndex], + headers: this.headers, + error: this.error, + }; + const response = buildSmartyResponse(mockResponse); + this.currentStatusCodeIndex += 1; + return response; + } +} From adb13691a9d5d3ac07de6ed88b51dca73f6312a7 Mon Sep 17 00:00:00 2001 From: Ryan Cox Date: Mon, 2 Mar 2026 11:43:06 -0700 Subject: [PATCH 07/29] Make sender private in remaining Client classes Add private visibility to sender field in us_reverse_geo, international_street, and international_postal_code Clients for consistency with all other Clients. Remove trivial "has an inner sender" tests that accessed the now-private field. --- src/international_postal_code/Client.ts | 2 +- src/international_street/Client.ts | 2 +- src/us_reverse_geo/Client.ts | 2 +- .../{test_Client.js => test_Client.ts} | 19 ++++----------- .../{test_Client.js => test_Client.ts} | 23 ++++++------------- .../{test_Client.js => test_Client.ts} | 19 ++++----------- 6 files changed, 20 insertions(+), 47 deletions(-) rename tests/international_postal_code/{test_Client.js => test_Client.ts} (75%) rename tests/international_street/{test_Client.js => test_Client.ts} (68%) rename tests/us_reverse_geo/{test_Client.js => test_Client.ts} (60%) diff --git a/src/international_postal_code/Client.ts b/src/international_postal_code/Client.ts index 3ac9e79..85c9aa7 100644 --- a/src/international_postal_code/Client.ts +++ b/src/international_postal_code/Client.ts @@ -9,7 +9,7 @@ import Lookup from "./Lookup.js"; const keyTranslationFormat = apiToSDKKeyMap.internationalPostalCode; export default class Client { - sender: Sender; + private sender: Sender; constructor(sender: Sender) { this.sender = sender; diff --git a/src/international_street/Client.ts b/src/international_street/Client.ts index 83ea774..b9b401f 100644 --- a/src/international_street/Client.ts +++ b/src/international_street/Client.ts @@ -9,7 +9,7 @@ import Lookup from "./Lookup.js"; const keyTranslationFormat = apiToSDKKeyMap.internationalStreet; export default class Client { - sender: Sender; + private sender: Sender; constructor(sender: Sender) { this.sender = sender; diff --git a/src/us_reverse_geo/Client.ts b/src/us_reverse_geo/Client.ts index 1ffc4f3..541c9ca 100644 --- a/src/us_reverse_geo/Client.ts +++ b/src/us_reverse_geo/Client.ts @@ -9,7 +9,7 @@ import Lookup from "./Lookup.js"; const keyTranslationFormat = apiToSDKKeyMap.usReverseGeo; export default class Client { - sender: Sender; + private sender: Sender; constructor(sender: Sender) { this.sender = sender; diff --git a/tests/international_postal_code/test_Client.js b/tests/international_postal_code/test_Client.ts similarity index 75% rename from tests/international_postal_code/test_Client.js rename to tests/international_postal_code/test_Client.ts index 0d79d67..6137dfa 100644 --- a/tests/international_postal_code/test_Client.js +++ b/tests/international_postal_code/test_Client.ts @@ -1,23 +1,14 @@ -const chai = require("chai"); -const expect = chai.expect; -const Client = require("../../src/international_postal_code/Client"); -const Lookup = require("../../src/international_postal_code/Lookup"); -const MockSender = require("../fixtures/mock_senders").MockSender; -const MockSenderWithResponse = require("../fixtures/mock_senders").MockSenderWithResponse; +import { expect } from "chai"; +import Client from "../../src/international_postal_code/Client.js"; +import Lookup from "../../src/international_postal_code/Lookup.js"; +import { MockSender, MockSenderWithResponse } from "../fixtures/mock_senders.js"; describe("An International Postal Code client", function () { - it("has an inner sender.", function () { - let mockSender = new MockSender(); - let client = new Client(mockSender); - - expect(client.sender).to.deep.equal(mockSender); - }); - it("throws an error if sending without a lookup.", function () { let mockSender = new MockSender(); let client = new Client(mockSender); - expect(() => client.send()).to.throw(); + expect(() => (client.send as any)()).to.throw(); }); it("attaches a result from a response to a lookup.", function () { diff --git a/tests/international_street/test_Client.js b/tests/international_street/test_Client.ts similarity index 68% rename from tests/international_street/test_Client.js rename to tests/international_street/test_Client.ts index f5158b9..96a51fc 100644 --- a/tests/international_street/test_Client.js +++ b/tests/international_street/test_Client.ts @@ -1,20 +1,11 @@ -const chai = require("chai"); -const expect = chai.expect; -const Client = require("../../src/international_street/Client"); -const Lookup = require("../../src/international_street/Lookup"); -const Candidate = require("../../src/international_street/Candidate"); -const errors = require("../../src/Errors"); -const MockSender = require("../fixtures/mock_senders").MockSender; -const MockSenderWithResponse = require("../fixtures/mock_senders").MockSenderWithResponse; +import { expect } from "chai"; +import Client from "../../src/international_street/Client.js"; +import Lookup from "../../src/international_street/Lookup.js"; +import Candidate from "../../src/international_street/Candidate.js"; +import errors from "../../src/Errors.js"; +import { MockSender, MockSenderWithResponse } from "../fixtures/mock_senders.js"; describe("An International Street client", function () { - it("has an inner sender.", function () { - let mockSender = new MockSender(); - let client = new Client(mockSender); - - expect(client.sender).to.deep.equal(mockSender); - }); - it("throws an error if sending without a lookup.", function () { let mockSender = new MockSender(); let client = new Client(mockSender); @@ -63,7 +54,7 @@ describe("An International Street client", function () { let lookup = new Lookup(); let expectedResult = new Candidate({ address1: "A" }); - return client.send(lookup).then((response) => { + return client.send(lookup).then((_response) => { expect(lookup.result[0]).to.deep.equal(expectedResult); }); }); diff --git a/tests/us_reverse_geo/test_Client.js b/tests/us_reverse_geo/test_Client.ts similarity index 60% rename from tests/us_reverse_geo/test_Client.js rename to tests/us_reverse_geo/test_Client.ts index f7bfb63..2ae1e49 100644 --- a/tests/us_reverse_geo/test_Client.js +++ b/tests/us_reverse_geo/test_Client.ts @@ -1,19 +1,10 @@ -const chai = require("chai"); -const expect = chai.expect; -const Client = require("../../src/us_reverse_geo/Client"); -const Lookup = require("../../src/us_reverse_geo/Lookup"); -const MockSender = require("../fixtures/mock_senders").MockSender; -const MockSenderWithResponse = require("../fixtures/mock_senders").MockSenderWithResponse; -const Response = require("../../src/us_reverse_geo/Response"); +import { expect } from "chai"; +import Client from "../../src/us_reverse_geo/Client.js"; +import Lookup from "../../src/us_reverse_geo/Lookup.js"; +import { MockSenderWithResponse } from "../fixtures/mock_senders.js"; +import Response from "../../src/us_reverse_geo/Response.js"; describe("A US Reverse Geo client", function () { - it("has an inner sender.", function () { - let mockSender = new MockSender(); - let client = new Client(mockSender); - - expect(client.sender).to.deep.equal(mockSender); - }); - it("attaches a result from a response to a lookup.", function () { const expectedMockPayload = { results: [ From d5a9474a34e841c054e53ce13dca767a6632ace0 Mon Sep 17 00:00:00 2001 From: Ryan Cox Date: Mon, 2 Mar 2026 11:43:24 -0700 Subject: [PATCH 08/29] Replace as any payload casts with specific types Use narrowed payload type assertions instead of as any in us_autocomplete_pro, international_address_autocomplete, and us_extract Clients. Type StatusCodeSender catch handler as Response with a specific error payload shape. --- src/StatusCodeSender.js | 41 ---------------- src/StatusCodeSender.ts | 48 +++++++++++++++++++ .../Client.ts | 18 +++---- src/us_autocomplete_pro/Client.ts | 18 +++---- src/us_extract/Client.ts | 7 ++- 5 files changed, 72 insertions(+), 60 deletions(-) delete mode 100644 src/StatusCodeSender.js create mode 100644 src/StatusCodeSender.ts diff --git a/src/StatusCodeSender.js b/src/StatusCodeSender.js deleted file mode 100644 index 16dcdc2..0000000 --- a/src/StatusCodeSender.js +++ /dev/null @@ -1,41 +0,0 @@ -const Errors = require("./Errors"); - -class StatusCodeSender { - constructor(innerSender) { - this.sender = innerSender; - } - - send(request) { - return new Promise((resolve, reject) => { - this.sender - .send(request) - .then(resolve) - .catch((error) => { - switch (error.statusCode) { - case 500: - error.error = new Errors.InternalServerError(); - break; - - case 503: - error.error = new Errors.ServiceUnavailableError(); - break; - - case 504: - error.error = new Errors.GatewayTimeoutError(); - break; - - default: - error.error = new Errors.DefaultError( - error && - error.payload && - error.payload.errors[0] && - error.payload.errors[0].message, - ); - } - reject(error); - }); - }); - } -} - -module.exports = StatusCodeSender; diff --git a/src/StatusCodeSender.ts b/src/StatusCodeSender.ts new file mode 100644 index 0000000..c1c1dca --- /dev/null +++ b/src/StatusCodeSender.ts @@ -0,0 +1,48 @@ +import { + InternalServerError, + ServiceUnavailableError, + GatewayTimeoutError, + DefaultError, +} from "./Errors.js"; +import { Request, Response, Sender } from "./types.js"; + +export default class StatusCodeSender { + private sender: Sender; + + constructor(innerSender: Sender) { + this.sender = innerSender; + } + + send(request: Request): Promise { + return new Promise((resolve, reject) => { + this.sender + .send(request) + .then(resolve) + .catch((error: Response) => { + switch (error.statusCode) { + case 500: + error.error = new InternalServerError(); + break; + + case 503: + error.error = new ServiceUnavailableError(); + break; + + case 504: + error.error = new GatewayTimeoutError(); + break; + + default: { + const payload = error.payload as { + errors?: { message?: string }[]; + } | null; + error.error = new DefaultError( + payload?.errors?.[0]?.message, + ); + } + } + reject(error); + }); + }); + } +} diff --git a/src/international_address_autocomplete/Client.ts b/src/international_address_autocomplete/Client.ts index 6a312f0..6dd28da 100644 --- a/src/international_address_autocomplete/Client.ts +++ b/src/international_address_autocomplete/Client.ts @@ -31,18 +31,18 @@ export default class Client { .then((response) => { if (response.error) return reject(response.error); - lookup.result = buildSuggestionsFromResponse(response.payload as any); + const payload = response.payload as { + candidates: Record[] | null; + }; + lookup.result = + !payload || payload.candidates === null + ? [] + : payload.candidates.map( + (suggestion) => new Suggestion(suggestion), + ); resolve(lookup); }) .catch(reject); }); - - function buildSuggestionsFromResponse(payload: any): Suggestion[] { - if (payload && payload.candidates === null) return []; - - return payload.candidates.map( - (suggestion: Record) => new Suggestion(suggestion), - ); - } } } diff --git a/src/us_autocomplete_pro/Client.ts b/src/us_autocomplete_pro/Client.ts index 4ba0f5d..a4fc66f 100644 --- a/src/us_autocomplete_pro/Client.ts +++ b/src/us_autocomplete_pro/Client.ts @@ -27,18 +27,18 @@ export default class Client { .then((response) => { if (response.error) return reject(response.error); - lookup.result = buildSuggestionsFromResponse(response.payload as any); + const payload = response.payload as { + suggestions: Record[] | null; + }; + lookup.result = + payload.suggestions === null + ? [] + : payload.suggestions.map( + (suggestion) => new Suggestion(suggestion), + ); resolve(lookup); }) .catch(reject); }); - - function buildSuggestionsFromResponse(payload: any): Suggestion[] { - if (payload.suggestions === null) return []; - - return payload.suggestions.map( - (suggestion: Record) => new Suggestion(suggestion), - ); - } } } diff --git a/src/us_extract/Client.ts b/src/us_extract/Client.ts index d8a26b4..602d276 100644 --- a/src/us_extract/Client.ts +++ b/src/us_extract/Client.ts @@ -27,7 +27,12 @@ export default class Client { .then((response) => { if (response.error) return reject(response.error); - lookup.result = new Result(response.payload as any); + lookup.result = new Result( + response.payload as { + meta: Record; + addresses: Record[]; + }, + ); resolve(lookup); }) .catch(reject); From 0fe766a01b6c9b12ebaa5b23aa656969543658c2 Mon Sep 17 00:00:00 2001 From: Ryan Cox Date: Mon, 2 Mar 2026 11:50:02 -0700 Subject: [PATCH 09/29] Fix typos and inconsistencies in us_enrichment Response - Rename secondFlootSqft to secondFloorSqft (typo) - Remove duplicate censusTract assignment - Fix widow_tax_exemption to widowTaxExemption in FinancialResponse for consistency with the camelCase convention used everywhere else --- .../{Response.js => Response.ts} | 37 +++++++++++++------ .../{test_Response.js => test_Response.ts} | 7 ++-- 2 files changed, 28 insertions(+), 16 deletions(-) rename src/us_enrichment/{Response.js => Response.ts} (97%) rename tests/us_enrichment/{test_Response.js => test_Response.ts} (99%) diff --git a/src/us_enrichment/Response.js b/src/us_enrichment/Response.ts similarity index 97% rename from src/us_enrichment/Response.js rename to src/us_enrichment/Response.ts index 77acade..780326e 100644 --- a/src/us_enrichment/Response.js +++ b/src/us_enrichment/Response.ts @@ -1,5 +1,10 @@ -class Response { - constructor(responseData) { +export class Response { + smartyKey: string; + dataSetName: string; + dataSubsetName: string; + attributes: Record; + + constructor(responseData: Record) { this.smartyKey = responseData.smarty_key; this.dataSetName = responseData.data_set_name; this.dataSubsetName = responseData.data_subset_name; @@ -7,7 +12,7 @@ class Response { this.attributes = {}; if (responseData.attributes) { this.attributes.firstFloorSqft = responseData.attributes["1st_floor_sqft"]; - this.attributes.secondFlootSqft = responseData.attributes["2nd_floor_sqft"]; + this.attributes.secondFloorSqft = responseData.attributes["2nd_floor_sqft"]; this.attributes.acres = responseData.attributes.acres; this.attributes.addressInfoPrivacy = responseData.attributes.address_info_privacy; this.attributes.airConditioner = responseData.attributes.air_conditioner; @@ -55,7 +60,6 @@ class Response { this.attributes.censusTract = responseData.attributes.census_tract; this.attributes.censusBlockGroup = responseData.attributes.census_block_group; this.attributes.censusFipsPlaceCode = responseData.attributes.census_fips_place_code; - this.attributes.censusTract = responseData.attributes.census_tract; this.attributes.centralVacuum = responseData.attributes.central_vacuum; this.attributes.codeTitleCompany = responseData.attributes.code_title_company; this.attributes.combinedStatisticalArea = responseData.attributes.combined_statistical_area; @@ -124,7 +128,7 @@ class Response { this.attributes.familyRoom = responseData.attributes.family_room; this.attributes.financialHistory = !responseData.attributes.financial_history ? [] - : responseData.attributes.financial_history.map((history) => { + : responseData.attributes.financial_history.map((history: Record) => { return { codeTitleCompany: history.code_title_company, instrumentDate: history.instrument_date, @@ -435,8 +439,13 @@ class Response { } } -class FinancialResponse { - constructor(responseData) { +export class FinancialResponse { + smartyKey: string; + dataSetName: string; + dataSubsetName: string; + attributes: Record; + + constructor(responseData: Record) { this.smartyKey = responseData.smarty_key; this.dataSetName = responseData.data_set_name; this.dataSubsetName = responseData.data_subset_name; @@ -497,7 +506,7 @@ class FinancialResponse { this.attributes.financialHistory = !responseData.attributes.financial_history ? [] - : responseData.attributes.financial_history.map((history) => { + : responseData.attributes.financial_history.map((history: Record) => { return { codeTitleCompany: history.code_title_company, instrumentDate: history.instrument_date, @@ -573,13 +582,17 @@ class FinancialResponse { this.attributes.totalMarketValue = responseData.attributes.total_market_value; this.attributes.trustDescription = responseData.attributes.trust_description; this.attributes.veteranTaxExemption = responseData.attributes.veteran_tax_exemption; - this.attributes.widow_tax_exemption = responseData.attributes.widow_tax_exemption; + this.attributes.widowTaxExemption = responseData.attributes.widow_tax_exemption; } } } -class GeoResponse { - constructor(responseData) { +export class GeoResponse { + smartyKey: string; + dataSetName: string; + attributes: Record; + + constructor(responseData: Record) { this.smartyKey = responseData.smarty_key; this.dataSetName = responseData.data_set_name; @@ -623,7 +636,7 @@ class GeoResponse { } } -module.exports = { +export default { Response, FinancialResponse, GeoResponse, diff --git a/tests/us_enrichment/test_Response.js b/tests/us_enrichment/test_Response.ts similarity index 99% rename from tests/us_enrichment/test_Response.js rename to tests/us_enrichment/test_Response.ts index b665a7a..970c45f 100644 --- a/tests/us_enrichment/test_Response.js +++ b/tests/us_enrichment/test_Response.ts @@ -1,6 +1,5 @@ -const chai = require("chai"); -const expect = chai.expect; -const { Response } = require("../../src/us_enrichment/Response.js"); +import { expect } from "chai"; +import { Response } from "../../src/us_enrichment/Response.js"; describe("A US Enrichment Response", function () { it("is initialized correctly with API response data.", function () { @@ -375,7 +374,7 @@ describe("A US Enrichment Response", function () { let response = new Response(mockResponse); expect(response.attributes.firstFloorSqft).to.equal("01"); - expect(response.attributes.secondFlootSqft).to.equal("02"); + expect(response.attributes.secondFloorSqft).to.equal("02"); expect(response.attributes.acres).to.equal("0"); expect(response.attributes.addressInfoPrivacy).to.equal("1"); expect(response.attributes.airConditioner).to.equal("2"); From afe7d46ec59235eeaf67ffcfc6ace772501c1ad5 Mon Sep 17 00:00:00 2001 From: Ryan Cox Date: Mon, 2 Mar 2026 11:50:24 -0700 Subject: [PATCH 10/29] Map state_abbreviation to stateAbbreviation in us_reverse_geo Result This was the only place in the SDK where a mapped property retained snake_case. Consistent with us_zipcode/Result which already maps to stateAbbreviation. Updated tests to use API-format input and SDK-format expected output separately. --- src/us_reverse_geo/{Result.js => Result.ts} | 18 +++++------- tests/us_reverse_geo/test_Client.ts | 28 ++++++++++++++++--- .../{test_Response.js => test_Response.ts} | 7 ++--- 3 files changed, 34 insertions(+), 19 deletions(-) rename src/us_reverse_geo/{Result.js => Result.ts} (67%) rename tests/us_reverse_geo/{test_Response.js => test_Response.ts} (85%) diff --git a/src/us_reverse_geo/Result.js b/src/us_reverse_geo/Result.ts similarity index 67% rename from src/us_reverse_geo/Result.js rename to src/us_reverse_geo/Result.ts index f1f0a56..9367d21 100644 --- a/src/us_reverse_geo/Result.js +++ b/src/us_reverse_geo/Result.ts @@ -1,18 +1,16 @@ -/** - * A candidate is a possible match for an address that was submitted.
- * A lookup can have multiple candidates if the address was ambiguous. - * - * @see "https://www.smarty.com/docs/cloud/us-reverse-geo-api#result" - */ -class Result { - constructor(responseData) { +export default class Result { + distance: number; + address: Record; + coordinate: Record; + + constructor(responseData: Record) { this.distance = responseData.distance; this.address = {}; if (responseData.address) { this.address.street = responseData.address.street; this.address.city = responseData.address.city; - this.address.state_abbreviation = responseData.address.state_abbreviation; + this.address.stateAbbreviation = responseData.address.state_abbreviation; this.address.zipcode = responseData.address.zipcode; this.address.source = responseData.address.source; } @@ -32,5 +30,3 @@ class Result { } } } - -module.exports = Result; diff --git a/tests/us_reverse_geo/test_Client.ts b/tests/us_reverse_geo/test_Client.ts index 2ae1e49..ad45d49 100644 --- a/tests/us_reverse_geo/test_Client.ts +++ b/tests/us_reverse_geo/test_Client.ts @@ -6,14 +6,14 @@ import Response from "../../src/us_reverse_geo/Response.js"; describe("A US Reverse Geo client", function () { it("attaches a result from a response to a lookup.", function () { - const expectedMockPayload = { + const mockPayload = { results: [ { coordinate: { latitude: 40.111111, longitude: -111.111111, accuracy: "Rooftop", - license: "SmartyStreets", + license: 1, }, distance: 2.7207432, address: { @@ -26,12 +26,32 @@ describe("A US Reverse Geo client", function () { }, ], }; - let mockSender = new MockSenderWithResponse(expectedMockPayload); + const expectedResult = { + results: [ + { + coordinate: { + latitude: 40.111111, + longitude: -111.111111, + accuracy: "Rooftop", + license: "SmartyStreets Proprietary", + }, + distance: 2.7207432, + address: { + street: "2335 S State St", + city: "Provo", + stateAbbreviation: "UT", + zipcode: "84606", + source: "postal", + }, + }, + ], + }; + let mockSender = new MockSenderWithResponse(mockPayload); const client = new Client(mockSender); let lookup = new Lookup(44.888888888, -111.111111111, "postal"); return client.send(lookup).then(() => { - expect(lookup.response).to.deep.equal(expectedMockPayload); + expect(lookup.response).to.deep.equal(expectedResult); expect(lookup.response).to.be.an.instanceOf(Response); }); }); diff --git a/tests/us_reverse_geo/test_Response.js b/tests/us_reverse_geo/test_Response.ts similarity index 85% rename from tests/us_reverse_geo/test_Response.js rename to tests/us_reverse_geo/test_Response.ts index dce5f1d..51cc5a5 100644 --- a/tests/us_reverse_geo/test_Response.js +++ b/tests/us_reverse_geo/test_Response.ts @@ -1,6 +1,5 @@ -const chai = require("chai"); -const expect = chai.expect; -const Response = require("../../src/us_reverse_geo/Response"); +import { expect } from "chai"; +import Response from "../../src/us_reverse_geo/Response.js"; describe("A US Reverse Geo match response", function () { it("populates with the appropriate fields.", function () { @@ -32,7 +31,7 @@ describe("A US Reverse Geo match response", function () { let address = result.address; expect(address.street).to.equal("5"); expect(address.city).to.equal("6"); - expect(address.state_abbreviation).to.equal("7"); + expect(address.stateAbbreviation).to.equal("7"); expect(address.zipcode).to.equal("8"); expect(address.source).to.equal("postal"); let coordinate = result.coordinate; From abb7e465a5e92a8d3590f8d5960365f6be9f157f Mon Sep 17 00:00:00 2001 From: Ryan Cox Date: Mon, 2 Mar 2026 11:50:37 -0700 Subject: [PATCH 11/29] Add null guards for payload access in Client and Address Guard against null payload in international_street Client before calling forEach, and guard against missing api_output in us_extract Address before calling map. --- src/international_street/Client.ts | 8 +++++--- src/us_extract/Address.js | 17 ----------------- src/us_extract/Address.ts | 23 +++++++++++++++++++++++ 3 files changed, 28 insertions(+), 20 deletions(-) delete mode 100644 src/us_extract/Address.js create mode 100644 src/us_extract/Address.ts diff --git a/src/international_street/Client.ts b/src/international_street/Client.ts index b9b401f..726f758 100644 --- a/src/international_street/Client.ts +++ b/src/international_street/Client.ts @@ -33,9 +33,11 @@ export default class Client { }); function attachLookupCandidates(response: any, lookup: Lookup): Lookup { - response.payload.map((rawCandidate: Record) => { - lookup.result.push(new Candidate(rawCandidate)); - }); + if (response.payload) { + response.payload.forEach((rawCandidate: Record) => { + lookup.result.push(new Candidate(rawCandidate)); + }); + } return lookup; } diff --git a/src/us_extract/Address.js b/src/us_extract/Address.js deleted file mode 100644 index 817f178..0000000 --- a/src/us_extract/Address.js +++ /dev/null @@ -1,17 +0,0 @@ -const Candidate = require("../us_street/Candidate"); - -/** - * @see Smarty US Extract API docs - */ -class Address { - constructor(responseData) { - this.text = responseData.text; - this.verified = responseData.verified; - this.line = responseData.line; - this.start = responseData.start; - this.end = responseData.end; - this.candidates = responseData.api_output.map((rawAddress) => new Candidate(rawAddress)); - } -} - -module.exports = Address; diff --git a/src/us_extract/Address.ts b/src/us_extract/Address.ts new file mode 100644 index 0000000..43b978e --- /dev/null +++ b/src/us_extract/Address.ts @@ -0,0 +1,23 @@ +import Candidate from "../us_street/Candidate.js"; + +export default class Address { + text: string; + verified: boolean; + line: number; + start: number; + end: number; + candidates: Candidate[]; + + constructor(responseData: Record) { + this.text = responseData.text; + this.verified = responseData.verified; + this.line = responseData.line; + this.start = responseData.start; + this.end = responseData.end; + this.candidates = responseData.api_output + ? responseData.api_output.map( + (rawAddress: Record) => new Candidate(rawAddress), + ) + : []; + } +} From 216939ace05a35aca0ef4ed01ecff36ccec88252 Mon Sep 17 00:00:00 2001 From: Ryan Cox Date: Mon, 2 Mar 2026 11:59:21 -0700 Subject: [PATCH 12/29] Remove unnecessary Promise constructor wrapping in senders LicenseSender, BaseUrlSender, AgentSender, CustomHeaderSender, and SigningSender all wrapped this.sender.send(request) in a redundant new Promise(). Since the inner send already returns a Promise, just return it directly after doing synchronous work. --- src/AgentSender.ts | 4 +--- src/BaseUrlSender.ts | 10 ++++------ src/CustomHeaderSender.ts | 4 +--- src/LicenseSender.js | 18 ------------------ src/LicenseSender.ts | 19 +++++++++++++++++++ src/SigningSender.ts | 6 ++---- ...LicenseSender.js => test_LicenseSender.ts} | 17 ++++++++--------- 7 files changed, 35 insertions(+), 43 deletions(-) delete mode 100644 src/LicenseSender.js create mode 100644 src/LicenseSender.ts rename tests/{test_LicenseSender.js => test_LicenseSender.ts} (76%) diff --git a/src/AgentSender.ts b/src/AgentSender.ts index 57358c1..4b223a4 100644 --- a/src/AgentSender.ts +++ b/src/AgentSender.ts @@ -10,8 +10,6 @@ export default class AgentSender { send(request: Request): Promise { request.parameters["agent"] = "smarty (sdk:javascript@" + packageJson.version + ")"; - return new Promise((resolve, reject) => { - this.sender.send(request).then(resolve).catch(reject); - }); + return this.sender.send(request); } } diff --git a/src/BaseUrlSender.ts b/src/BaseUrlSender.ts index d17ebc1..ccf10b4 100644 --- a/src/BaseUrlSender.ts +++ b/src/BaseUrlSender.ts @@ -10,12 +10,10 @@ export default class BaseUrlSender { } send(request: Request): Promise { - return new Promise((resolve, reject) => { - request.baseUrl = `${this.urlOverride}${ - request.baseUrlParam ? `/${request.baseUrlParam}` : "" - }`; + request.baseUrl = `${this.urlOverride}${ + request.baseUrlParam ? `/${request.baseUrlParam}` : "" + }`; - this.sender.send(request).then(resolve).catch(reject); - }); + return this.sender.send(request); } } diff --git a/src/CustomHeaderSender.ts b/src/CustomHeaderSender.ts index 5609740..7894ade 100644 --- a/src/CustomHeaderSender.ts +++ b/src/CustomHeaderSender.ts @@ -37,8 +37,6 @@ export default class CustomHeaderSender { } } - return new Promise((resolve, reject) => { - this.sender.send(request).then(resolve).catch(reject); - }); + return this.sender.send(request); } } diff --git a/src/LicenseSender.js b/src/LicenseSender.js deleted file mode 100644 index 813e0a5..0000000 --- a/src/LicenseSender.js +++ /dev/null @@ -1,18 +0,0 @@ -class LicenseSender { - constructor(innerSender, licenses) { - this.sender = innerSender; - this.licenses = licenses; - } - - send(request) { - if (this.licenses.length !== 0) { - request.parameters["license"] = this.licenses.join(","); - } - - return new Promise((resolve, reject) => { - this.sender.send(request).then(resolve).catch(reject); - }); - } -} - -module.exports = LicenseSender; diff --git a/src/LicenseSender.ts b/src/LicenseSender.ts new file mode 100644 index 0000000..37e3212 --- /dev/null +++ b/src/LicenseSender.ts @@ -0,0 +1,19 @@ +import { Request, Response, Sender } from "./types.js"; + +export default class LicenseSender { + private sender: Sender; + private licenses: string[]; + + constructor(innerSender: Sender, licenses: string[]) { + this.sender = innerSender; + this.licenses = licenses; + } + + send(request: Request): Promise { + if (this.licenses.length !== 0) { + request.parameters["license"] = this.licenses.join(","); + } + + return this.sender.send(request); + } +} diff --git a/src/SigningSender.ts b/src/SigningSender.ts index b9afcc2..3152bc7 100644 --- a/src/SigningSender.ts +++ b/src/SigningSender.ts @@ -24,9 +24,7 @@ export default class SigningSender { throw new UnprocessableEntityError(message); } - return new Promise((resolve, reject) => { - this.signer.sign(request); - this.sender.send(request).then(resolve).catch(reject); - }); + this.signer.sign(request); + return this.sender.send(request); } } diff --git a/tests/test_LicenseSender.js b/tests/test_LicenseSender.ts similarity index 76% rename from tests/test_LicenseSender.js rename to tests/test_LicenseSender.ts index 152b3ae..0494950 100644 --- a/tests/test_LicenseSender.js +++ b/tests/test_LicenseSender.ts @@ -1,17 +1,16 @@ -const chai = require("chai"); -const expect = chai.expect; -const LicenseSender = require("../src/LicenseSender"); -const Request = require("../src/Request"); +import { expect } from "chai"; +import LicenseSender from "../src/LicenseSender.js"; +import Request from "../src/Request.js"; describe("A license sender", function () { - let innerSender; - let request; - let licenses; - let licenseSender; + let innerSender: any; + let request: any; + let licenses: any; + let licenseSender: any; beforeEach(() => { innerSender = { - send: () => true, + send: () => Promise.resolve(), }; request = new Request(); }); From 7ec944dfd69b18e80f6994c6782102333bb01c4c Mon Sep 17 00:00:00 2001 From: Ryan Cox Date: Mon, 2 Mar 2026 11:59:31 -0700 Subject: [PATCH 13/29] Replace .map() with .forEach() where return value is discarded us_reverse_geo/Response.ts and util/sendBatch.ts were using .map() purely for side effects. Use .forEach() to express intent clearly. --- src/us_reverse_geo/Response.js | 17 ----------------- src/us_reverse_geo/Response.ts | 14 ++++++++++++++ src/util/sendBatch.ts | 2 +- 3 files changed, 15 insertions(+), 18 deletions(-) delete mode 100644 src/us_reverse_geo/Response.js create mode 100644 src/us_reverse_geo/Response.ts diff --git a/src/us_reverse_geo/Response.js b/src/us_reverse_geo/Response.js deleted file mode 100644 index ea9b0e2..0000000 --- a/src/us_reverse_geo/Response.js +++ /dev/null @@ -1,17 +0,0 @@ -const Result = require("./Result"); - -/** - * The SmartyResponse contains the response from a call to the US Reverse Geo API. - */ -class Response { - constructor(responseData) { - this.results = []; - - if (responseData) - responseData.results.map((rawResult) => { - this.results.push(new Result(rawResult)); - }); - } -} - -module.exports = Response; diff --git a/src/us_reverse_geo/Response.ts b/src/us_reverse_geo/Response.ts new file mode 100644 index 0000000..dbe01e1 --- /dev/null +++ b/src/us_reverse_geo/Response.ts @@ -0,0 +1,14 @@ +import Result from "./Result.js"; + +export default class Response { + results: Result[]; + + constructor(responseData?: Record) { + this.results = []; + + if (responseData) + responseData.results.forEach((rawResult: Record) => { + this.results.push(new Result(rawResult)); + }); + } +} diff --git a/src/util/sendBatch.ts b/src/util/sendBatch.ts index 19d4965..1b1ef1a 100644 --- a/src/util/sendBatch.ts +++ b/src/util/sendBatch.ts @@ -39,7 +39,7 @@ export default function sendBatch( } function assignResultsToLookups(batch: Batch, response: any): Batch { - response.payload.map((rawResult: Record) => { + response.payload.forEach((rawResult: Record) => { const result = new Result(rawResult); const lookup = batch.getByIndex(result.inputIndex); From b109f7a3ca1637501faf636a4ec6c25fb0ba9866 Mon Sep 17 00:00:00 2001 From: Ryan Cox Date: Mon, 2 Mar 2026 13:29:59 -0700 Subject: [PATCH 14/29] Add implements to Request/Response classes and simplify error type to Error | null --- src/Request.ts | 21 ++++++++ src/Response.ts | 20 +++++++ src/types.ts | 6 ++- tests/test_StatusCodeSender.ts | 98 ++++++++++++++++++++++++++++++++++ 4 files changed, 144 insertions(+), 1 deletion(-) create mode 100644 src/Request.ts create mode 100644 src/Response.ts create mode 100644 tests/test_StatusCodeSender.ts diff --git a/src/Request.ts b/src/Request.ts new file mode 100644 index 0000000..0cc10f2 --- /dev/null +++ b/src/Request.ts @@ -0,0 +1,21 @@ +import { Request as IRequest } from "./types.js"; + +export default class Request implements IRequest { + baseUrl: string; + baseUrlParam: string; + payload: string | object | null; + headers: Record; + parameters: Record; + + constructor( + payload: string | object | null = null, + headers: Record = { "Content-Type": "application/json; charset=utf-8" }, + ) { + this.baseUrl = ""; + this.baseUrlParam = ""; + this.payload = payload; + this.headers = headers; + + this.parameters = {}; + } +} diff --git a/src/Response.ts b/src/Response.ts new file mode 100644 index 0000000..b893a92 --- /dev/null +++ b/src/Response.ts @@ -0,0 +1,20 @@ +import { Response as IResponse } from "./types.js"; + +export default class Response implements IResponse { + statusCode: number; + payload: object[] | object | string | null; + error: Error | null; + headers: Record; + + constructor( + statusCode: number, + payload: object[] | object | string | null = null, + error: Error | null = null, + headers: Record = {}, + ) { + this.statusCode = statusCode; + this.payload = payload; + this.error = error; + this.headers = headers; + } +} diff --git a/src/types.ts b/src/types.ts index ca372d5..98dabcf 100644 --- a/src/types.ts +++ b/src/types.ts @@ -21,8 +21,12 @@ export interface Sleeper { sleep(seconds: number): Promise; } +export interface Signer { + sign(request: Request): void; +} + export interface MockSenderInstance extends Sender { - statusCodes: string[]; + statusCodes: number[]; headers?: Record | undefined; error?: string | undefined; currentStatusCodeIndex: number; diff --git a/tests/test_StatusCodeSender.ts b/tests/test_StatusCodeSender.ts new file mode 100644 index 0000000..d272a7e --- /dev/null +++ b/tests/test_StatusCodeSender.ts @@ -0,0 +1,98 @@ +import { expect } from "chai"; +import StatusCodeSender from "../src/StatusCodeSender.js"; +import Response from "../src/Response.js"; +import Request from "../src/Request.js"; +import errors from "../src/Errors.js"; + +describe("A status code sender", function () { + it("doesn't attach an error on a 200.", function () { + let mockSender = { + send: () => { + return new Promise((resolve, _reject) => { + resolve(new Response(200)); + }); + }, + }; + + let statusCodeSender = new StatusCodeSender(mockSender as any); + let request = new Request(); + + return statusCodeSender.send(request).then((response) => { + expect(response.error === null).to.equal(true); + }); + }); + + it("gives a custom message for 400", function () { + const payload = { + errors: [{ message: "custom message" }], + }; + return expectedErrorWithPayloadMessage(400, payload); + }); + + it("returns an error message if payload is undefined", function () { + return expectedDefaultError(); + }); + + it("gives an Internal Server Error on a 500.", function () { + return expectedErrorForStatusCode(errors.InternalServerError, 500); + }); + + it("gives an Service Unavailable error on a 503.", function () { + return expectedErrorForStatusCode(errors.ServiceUnavailableError, 503); + }); + + it("gives an Gateway Timeout error on a 504.", function () { + return expectedErrorForStatusCode(errors.GatewayTimeoutError, 504); + }); +}); + +const expectedErrorWithPayloadMessage = (errorCode: any, payload: any) => { + let mockSender = generateMockSender(errorCode, payload); + let statusCodeSender = new StatusCodeSender(mockSender as any); + let request = new Request(); + + return statusCodeSender.send(request).then( + () => {}, + (error) => { + expect(error.error).to.be.an.instanceOf(errors.DefaultError); + expect(error.error.message).to.be.equal(payload.errors[0].message); + }, + ); +}; + +const expectedDefaultError = () => { + let mockSender = generateMockSender(400); + let statusCodeSender = new StatusCodeSender(mockSender as any); + let request = new Request(); + + return statusCodeSender.send(request).then( + () => {}, + (error) => { + expect(error.error).to.be.an.instanceOf(errors.DefaultError); + expect(error.error.message).to.be.equal("unexpected error"); + }, + ); +}; + +function expectedErrorForStatusCode(expectedError: any, errorCode: any) { + let mockSender = generateMockSender(errorCode); + let statusCodeSender = new StatusCodeSender(mockSender as any); + let request = new Request(); + + return statusCodeSender.send(request).then( + () => {}, + (error) => { + expect(error.error).to.be.an.instanceOf(expectedError); + }, + ); +} + +function generateMockSender(errorCode: any, payload?: any) { + return { + send: () => { + return new Promise((_resolve, reject) => { + reject(new Response(errorCode, payload)); + }); + }, + }; +} From 06ef75ac9a95f0626b5bf2702f6d25cae41d2794 Mon Sep 17 00:00:00 2001 From: Ryan Cox Date: Mon, 2 Mar 2026 13:31:04 -0700 Subject: [PATCH 15/29] Move Signer interface to types.ts and fix statusCodes to number[] --- src/RetrySender.ts | 2 +- src/SigningSender.ts | 6 +----- tests/test_RetrySender.ts | 39 +++++++++++++-------------------------- 3 files changed, 15 insertions(+), 32 deletions(-) diff --git a/src/RetrySender.ts b/src/RetrySender.ts index 8c3f689..988874b 100644 --- a/src/RetrySender.ts +++ b/src/RetrySender.ts @@ -21,7 +21,7 @@ export default class RetrySender { let response = await this.inner.send(request); for (let i = 0; i < this.maxRetries; i++) { - const statusCode = parseInt(String(response.statusCode)); + const statusCode = response.statusCode; if (!this.statusToRetry.includes(statusCode)) { break; } diff --git a/src/SigningSender.ts b/src/SigningSender.ts index 3152bc7..8e9cf42 100644 --- a/src/SigningSender.ts +++ b/src/SigningSender.ts @@ -1,11 +1,7 @@ -import { Request, Response, Sender } from "./types.js"; +import { Request, Response, Sender, Signer } from "./types.js"; import SharedCredentials from "./SharedCredentials.js"; import { UnprocessableEntityError } from "./Errors.js"; -interface Signer { - sign(request: Request): void; -} - export default class SigningSender { private signer: Signer; private sender: Sender; diff --git a/tests/test_RetrySender.ts b/tests/test_RetrySender.ts index 731df8a..af93322 100644 --- a/tests/test_RetrySender.ts +++ b/tests/test_RetrySender.ts @@ -6,7 +6,7 @@ import Response from "../src/Response.js"; import type { Sender, Sleeper, MockSenderInstance, MockSleeperInstance } from "../src/types"; class CompatibleMockSender implements MockSenderInstance { - statusCodes: string[]; + statusCodes: number[]; headers?: Record | undefined; error?: string | undefined; currentStatusCodeIndex: number; @@ -15,13 +15,13 @@ class CompatibleMockSender implements MockSenderInstance { currentStatusCodeIndex: number; }; - constructor(statusCodes: string[], headers?: Record, error?: string) { + constructor(statusCodes: number[], headers?: Record, error?: string) { this.statusCodes = statusCodes; this.headers = headers; this.error = error; this.currentStatusCodeIndex = 0; this.mockSender = new (MockSenderWithStatusCodesAndHeaders as new ( - ...args: [string[], Record?, string?] + ...args: [number[], Record?, string?] ) => { send(request: Request): Response; currentStatusCodeIndex: number; @@ -52,53 +52,40 @@ async function sendWithRetry(retries: number, inner: Sender, sleeper: Sleeper) { describe("Retry Sender tests", function () { it("test success does not retry", async function () { - let inner = new CompatibleMockSender(["200"]); + let inner = new CompatibleMockSender([200]); await sendWithRetry(5, inner, new CompatibleMockSleeper()); expect(inner.currentStatusCodeIndex).to.equal(1); }); it("test client error does not retry", async function () { - let inner = new CompatibleMockSender(["422"]); + let inner = new CompatibleMockSender([422]); await sendWithRetry(5, inner, new CompatibleMockSleeper()); expect(inner.currentStatusCodeIndex).to.equal(1); }); it("test will retry until success", async function () { - let inner = new CompatibleMockSender(["500", "500", "500", "200", "500"]); + let inner = new CompatibleMockSender([500, 500, 500, 200, 500]); await sendWithRetry(10, inner, new CompatibleMockSleeper()); expect(inner.currentStatusCodeIndex).to.equal(4); }); it("test return response if retry limit exceeded", async function () { - let inner = new CompatibleMockSender(["500", "500", "500", "500", "500"]); + let inner = new CompatibleMockSender([500, 500, 500, 500, 500]); const sleeper = new CompatibleMockSleeper(); const response = await sendWithRetry(4, inner, sleeper); expect(response); expect(inner.currentStatusCodeIndex).to.equal(5); - expect(response.statusCode).to.equal("500"); + expect(response.statusCode).to.equal(500); expect(sleeper.sleepDurations).to.deep.equal([0, 1, 2, 3]); }); it("test backoff does not exceed max", async function () { let inner = new CompatibleMockSender([ - "500", - "500", - "500", - "500", - "500", - "500", - "500", - "500", - "500", - "500", - "500", - "500", - "500", - "200", + 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 200, ]); const sleeper = new CompatibleMockSleeper(); @@ -115,7 +102,7 @@ describe("Retry Sender tests", function () { }); it("test sleep on rate limit", async function () { - let inner = new CompatibleMockSender(["429", "200"]); + let inner = new CompatibleMockSender([429, 200]); const sleeper = new CompatibleMockSleeper(); await sendWithRetry(5, inner, sleeper); @@ -124,7 +111,7 @@ describe("Retry Sender tests", function () { }); it("test rate limit error return", async function () { - let inner = new CompatibleMockSender(["429"], { "Retry-After": 7 }); + let inner = new CompatibleMockSender([429], { "Retry-After": 7 }); const sleeper = new CompatibleMockSleeper(); await sendWithRetry(10, inner, sleeper); @@ -133,7 +120,7 @@ describe("Retry Sender tests", function () { }); it("test retry after invalid value", async function () { - let inner = new CompatibleMockSender(["429"], { "Retry-After": "a" }); + let inner = new CompatibleMockSender([429], { "Retry-After": "a" }); const sleeper = new CompatibleMockSleeper(); await sendWithRetry(10, inner, sleeper); @@ -142,7 +129,7 @@ describe("Retry Sender tests", function () { }); it("test retry error", async function () { - let inner = new CompatibleMockSender(["429"], undefined, "Big Bad"); + let inner = new CompatibleMockSender([429], undefined, "Big Bad"); const sleeper = new CompatibleMockSleeper(); const response = await sendWithRetry(10, inner, sleeper); From 76c3fad04d4a475abd8847b62223e3e7f3737287 Mon Sep 17 00:00:00 2001 From: Ryan Cox Date: Mon, 2 Mar 2026 13:31:10 -0700 Subject: [PATCH 16/29] Export SmartyError and Signer type from public API --- index.ts | 3 +- src/Errors.ts | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 src/Errors.ts diff --git a/index.ts b/index.ts index 5de054e..e44c95b 100644 --- a/index.ts +++ b/index.ts @@ -36,7 +36,8 @@ import ResponseUSEnrichment from "./src/us_enrichment/Response.js"; import LookupInternationalPostalCode from "./src/international_postal_code/Lookup.js"; import ResultInternationalPostalCode from "./src/international_postal_code/Result.js"; -export type { Request, Response, Sender, Sleeper } from "./src/types.js"; +export type { Request, Response, Sender, Sleeper, Signer } from "./src/types.js"; +export { SmartyError } from "./src/Errors.js"; export const core = { Batch, diff --git a/src/Errors.ts b/src/Errors.ts new file mode 100644 index 0000000..28cb045 --- /dev/null +++ b/src/Errors.ts @@ -0,0 +1,110 @@ +export class SmartyError extends Error { + constructor(message: string = "unexpected error") { + super(message); + } +} + +export class DefaultError extends SmartyError { + constructor(message?: string | null) { + super(message || "unexpected error"); + } +} + +export class BatchFullError extends SmartyError { + constructor() { + super("A batch can contain a max of 100 lookups."); + } +} + +export class BatchEmptyError extends SmartyError { + constructor() { + super("A batch must contain at least 1 lookup."); + } +} + +export class UndefinedLookupError extends SmartyError { + constructor() { + super("The lookup provided is missing or undefined. Make sure you're passing a Lookup object."); + } +} + +export class BadCredentialsError extends SmartyError { + constructor() { + super( + "Unauthorized: The credentials were provided incorrectly or did not match any existing active credentials.", + ); + } +} + +export class PaymentRequiredError extends SmartyError { + constructor() { + super( + "Payment Required: There is no active subscription for the account associated with the credentials submitted with the request.", + ); + } +} + +export class RequestEntityTooLargeError extends SmartyError { + constructor() { + super("Request Entity Too Large: The request body has exceeded the maximum size."); + } +} + +export class BadRequestError extends SmartyError { + constructor() { + super( + "Bad Request (Malformed Payload): A GET request lacked a street field or the request body of a POST request contained malformed JSON.", + ); + } +} + +export class UnprocessableEntityError extends SmartyError { + constructor(message: string) { + super(message); + } +} + +export class TooManyRequestsError extends SmartyError { + constructor() { + super( + "When using the public 'embedded key' authentication, we restrict the number of requests coming from a given source over too short of a time.", + ); + } +} + +export class InternalServerError extends SmartyError { + constructor() { + super("Internal Server Error."); + } +} + +export class ServiceUnavailableError extends SmartyError { + constructor() { + super("Service Unavailable. Try again later."); + } +} + +export class GatewayTimeoutError extends SmartyError { + constructor() { + super( + "The upstream data provider did not respond in a timely fashion and the request failed. A serious, yet rare occurrence indeed.", + ); + } +} + +export default { + SmartyError, + BatchFullError, + BatchEmptyError, + UndefinedLookupError, + BadCredentialsError, + PaymentRequiredError, + RequestEntityTooLargeError, + BadRequestError, + UnprocessableEntityError, + TooManyRequestsError, + InternalServerError, + ServiceUnavailableError, + GatewayTimeoutError, + DefaultError, +}; From 87fa47b9fcbbbb6c28e5f0c2cd8ec2ba56c12b78 Mon Sep 17 00:00:00 2001 From: Ryan Cox Date: Mon, 2 Mar 2026 14:20:13 -0700 Subject: [PATCH 17/29] Convert remaining source and test files from JavaScript to TypeScript --- CLAUDE.md | 32 +++-- package.json | 4 +- src/Batch.js | 49 -------- src/Batch.ts | 41 +++++++ src/Errors.js | 109 ------------------ src/{InputData.js => InputData.ts} | 17 +-- src/Request.js | 12 -- src/Response.js | 10 -- .../Lookup.js | 26 ----- .../Lookup.ts | 40 +++++++ .../{Suggestion.js => Suggestion.ts} | 17 ++- src/international_postal_code/Lookup.js | 22 ---- src/international_postal_code/Lookup.ts | 29 +++++ .../{Result.js => Result.ts} | 21 ++-- .../{Candidate.js => Candidate.ts} | 29 +++-- .../{Lookup.js => Lookup.ts} | 70 ++++++----- src/us_autocomplete_pro/Lookup.js | 34 ------ src/us_autocomplete_pro/Lookup.ts | 40 +++++++ .../{Suggestion.js => Suggestion.ts} | 17 +-- src/us_enrichment/Lookup.js | 19 --- src/us_enrichment/Lookup.ts | 32 +++++ src/us_extract/Lookup.js | 29 ----- src/us_extract/Lookup.ts | 26 +++++ src/us_extract/{Result.js => Result.ts} | 20 ++-- src/us_reverse_geo/Lookup.js | 22 ---- src/us_reverse_geo/Lookup.ts | 21 ++++ src/us_street/{Candidate.js => Candidate.ts} | 25 ++-- src/us_street/Client.js | 41 ------- src/us_street/Client.ts | 33 ++++++ src/us_street/Lookup.js | 46 -------- src/us_street/Lookup.ts | 56 +++++++++ src/us_zipcode/Client.js | 39 ------- src/us_zipcode/Client.ts | 33 ++++++ src/us_zipcode/Lookup.js | 21 ---- src/us_zipcode/Lookup.ts | 21 ++++ src/us_zipcode/{Result.js => Result.ts} | 22 ++-- .../{apiToSDKKeyMap.js => apiToSDKKeyMap.ts} | 4 +- src/util/{buildClients.js => buildClients.ts} | 29 +++-- src/util/buildInputData.js | 19 --- src/util/buildInputData.ts | 22 ++++ ...InputData.js => buildUsStreetInputData.ts} | 10 +- .../{MockSleeper.js => MockSleeper.ts} | 9 +- .../{test_Client.js => test_Client.ts} | 14 +-- .../{test_Lookup.js => test_Lookup.ts} | 5 +- .../{test_Lookup.js => test_Lookup.ts} | 5 +- .../{test_Result.js => test_Result.ts} | 5 +- .../{test_Candidate.js => test_Candidate.ts} | 5 +- .../{test_Lookup.js => test_Lookup.ts} | 11 +- tests/{test_Batch.js => test_Batch.ts} | 13 +-- ...{test_HttpSender.js => test_HttpSender.ts} | 14 +-- tests/test_StatusCodeSender.js | 99 ---------------- .../{test_Client.js => test_Client.ts} | 24 ++-- .../{test_Lookup.js => test_Lookup.ts} | 5 +- ...{test_Suggestion.js => test_Suggestion.ts} | 5 +- .../{test_Client.js => test_Client.ts} | 34 +++--- .../{test_Lookup.js => test_Lookup.ts} | 5 +- .../{test_Address.js => test_Address.ts} | 7 +- .../{test_Client.js => test_Client.ts} | 22 ++-- .../{test_Lookup.js => test_Lookup.ts} | 5 +- .../{test_Result.js => test_Result.ts} | 7 +- .../{test_Lookup.js => test_Lookup.ts} | 5 +- .../{test_Candidate.js => test_Candidate.ts} | 5 +- .../{test_Lookup.js => test_Lookup.ts} | 21 +++- .../{test_Result.js => test_Result.ts} | 5 +- tsconfig.json | 2 - 65 files changed, 687 insertions(+), 854 deletions(-) delete mode 100644 src/Batch.js create mode 100644 src/Batch.ts delete mode 100644 src/Errors.js rename src/{InputData.js => InputData.ts} (52%) delete mode 100644 src/Request.js delete mode 100644 src/Response.js delete mode 100644 src/international_address_autocomplete/Lookup.js create mode 100644 src/international_address_autocomplete/Lookup.ts rename src/international_address_autocomplete/{Suggestion.js => Suggestion.ts} (61%) delete mode 100644 src/international_postal_code/Lookup.js create mode 100644 src/international_postal_code/Lookup.ts rename src/international_postal_code/{Result.js => Result.ts} (63%) rename src/international_street/{Candidate.js => Candidate.ts} (96%) rename src/international_street/{Lookup.js => Lookup.ts} (65%) delete mode 100644 src/us_autocomplete_pro/Lookup.js create mode 100644 src/us_autocomplete_pro/Lookup.ts rename src/us_autocomplete_pro/{Suggestion.js => Suggestion.ts} (58%) delete mode 100644 src/us_enrichment/Lookup.js create mode 100644 src/us_enrichment/Lookup.ts delete mode 100644 src/us_extract/Lookup.js create mode 100644 src/us_extract/Lookup.ts rename src/us_extract/{Result.js => Result.ts} (54%) delete mode 100644 src/us_reverse_geo/Lookup.js create mode 100644 src/us_reverse_geo/Lookup.ts rename src/us_street/{Candidate.js => Candidate.ts} (94%) delete mode 100644 src/us_street/Client.js create mode 100644 src/us_street/Client.ts delete mode 100644 src/us_street/Lookup.js create mode 100644 src/us_street/Lookup.ts delete mode 100644 src/us_zipcode/Client.js create mode 100644 src/us_zipcode/Client.ts delete mode 100644 src/us_zipcode/Lookup.js create mode 100644 src/us_zipcode/Lookup.ts rename src/us_zipcode/{Result.js => Result.ts} (71%) rename src/util/{apiToSDKKeyMap.js => apiToSDKKeyMap.ts} (95%) rename src/util/{buildClients.js => buildClients.ts} (57%) delete mode 100644 src/util/buildInputData.js create mode 100644 src/util/buildInputData.ts rename src/util/{buildUsStreetInputData.js => buildUsStreetInputData.ts} (75%) rename tests/fixtures/{MockSleeper.js => MockSleeper.ts} (50%) rename tests/international_address_autocomplete/{test_Client.js => test_Client.ts} (80%) rename tests/international_address_autocomplete/{test_Lookup.js => test_Lookup.ts} (92%) rename tests/international_postal_code/{test_Lookup.js => test_Lookup.ts} (85%) rename tests/international_postal_code/{test_Result.js => test_Result.ts} (93%) rename tests/international_street/{test_Candidate.js => test_Candidate.ts} (98%) rename tests/international_street/{test_Lookup.js => test_Lookup.ts} (93%) rename tests/{test_Batch.js => test_Batch.ts} (87%) rename tests/{test_HttpSender.js => test_HttpSender.ts} (86%) delete mode 100644 tests/test_StatusCodeSender.js rename tests/us_autocomplete_pro/{test_Client.js => test_Client.ts} (83%) rename tests/us_autocomplete_pro/{test_Lookup.js => test_Lookup.ts} (66%) rename tests/us_autocomplete_pro/{test_Suggestion.js => test_Suggestion.ts} (81%) rename tests/us_enrichment/{test_Client.js => test_Client.ts} (92%) rename tests/us_enrichment/{test_Lookup.js => test_Lookup.ts} (87%) rename tests/us_extract/{test_Address.js => test_Address.ts} (90%) rename tests/us_extract/{test_Client.js => test_Client.ts} (87%) rename tests/us_extract/{test_Lookup.js => test_Lookup.ts} (81%) rename tests/us_extract/{test_Result.js => test_Result.ts} (83%) rename tests/us_reverse_geo/{test_Lookup.js => test_Lookup.ts} (76%) rename tests/us_street/{test_Candidate.js => test_Candidate.ts} (98%) rename tests/us_street/{test_Lookup.js => test_Lookup.ts} (77%) rename tests/us_zipcode/{test_Result.js => test_Result.ts} (95%) diff --git a/CLAUDE.md b/CLAUDE.md index 5b8f6cc..5eee38c 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -6,9 +6,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co ```bash npm install # Install dependencies -npm test # Run all tests (JS + TS) -npm run test:js # Run JavaScript tests only -npm run test:ts # Run TypeScript tests only +npm test # Run all tests npm run build # Build the library (outputs to dist/) npx tsc --noEmit # Type-check without emitting npx prettier --write src/ # Format source files @@ -17,15 +15,14 @@ npx prettier --write src/ # Format source files To run a single test file: ```bash -npx mocha tests/us_street/test_Client.js # JS test -npx mocha --require tsx/cjs tests/test_RetrySender.ts # TS test +npx mocha --require tsx/cjs tests/test_RetrySender.ts ``` Build outputs dual formats via Rollup: `dist/cjs/` (CommonJS), `dist/esm/` (ESM), and `dist/types/` (declarations). Axios and axios-retry are external dependencies (not bundled). ## Architecture -This is the official JavaScript SDK for Smarty address validation APIs. It supports both Node.js (CommonJS/ESM) and browser environments. +This is the official JavaScript SDK for Smarty address validation APIs. It supports both Node.js (CommonJS/ESM) and browser environments. The entire codebase is TypeScript. ### Sender Chain Pattern @@ -42,19 +39,19 @@ Each sender adds specific functionality (authentication, retries, headers, etc.) - **ClientBuilder**: Fluent API for configuring and building API-specific clients. Accepts either `StaticCredentials` (server-side: auth-id + auth-token) or `SharedCredentials` (client-side: embedded key). -- **Lookup classes**: Each API has a `Lookup` that holds both input parameters and results after the API call. Located in `src//Lookup.js`. +- **Lookup classes**: Each API has a `Lookup` that holds both input parameters and results after the API call. Located in `src//Lookup.ts`. - **Batch**: Container for up to 100 lookups. Single lookups use GET requests; batches with 2+ lookups use POST. -- **Client classes**: Each API has a `Client` in `src//Client.js` that handles domain-specific request building and response parsing. +- **Client classes**: Each API has a `Client` in `src//Client.ts` that handles domain-specific request building and response parsing. ### API Modules Each API follows the same structure in `src//`: -- `Lookup.js` - Input/output container -- `Client.js` - Request/response handling -- `Candidate.js`, `Result.js`, or `Suggestion.js` - Response data structures +- `Lookup.ts` - Input/output container +- `Client.ts` - Request/response handling +- `Candidate.ts`, `Result.ts`, or `Suggestion.ts` - Response data structures Supported APIs: `us_street`, `us_zipcode`, `us_autocomplete_pro`, `us_extract`, `us_enrichment`, `us_reverse_geo`, `international_street`, `international_address_autocomplete`, `international_postal_code` @@ -62,19 +59,19 @@ Supported APIs: `us_street`, `us_zipcode`, `us_autocomplete_pro`, `us_extract`, Three credential types, each implementing a `sign(request)` method used by `SigningSender`: -- **StaticCredentials** (TS) - Server-side: adds `auth-id` + `auth-token` query params -- **SharedCredentials** (TS) - Client-side/browser: adds embedded `key` param + `Referer` header. Cannot be used with POST (batch) requests. -- **BasicAuthCredentials** (TS) - Adds HTTP Basic Auth `Authorization` header +- **StaticCredentials** - Server-side: adds `auth-id` + `auth-token` query params +- **SharedCredentials** - Client-side/browser: adds embedded `key` param + `Referer` header. Cannot be used with POST (batch) requests. +- **BasicAuthCredentials** - Adds HTTP Basic Auth `Authorization` header ### Entry Point -`index.mjs` exports all public classes organized by API namespace (e.g., `core`, `usStreet`, `usZipcode`). +`index.ts` exports all public classes organized by API namespace (e.g., `core`, `usStreet`, `usZipcode`). ### Test Infrastructure Tests use Mocha + Chai (`expect` style). Test files are prefixed with `test_` and mirror the source structure under `tests/`. -`tests/fixtures/mock_senders.js` provides reusable mocks: +`tests/fixtures/mock_senders.ts` provides reusable mocks: - `MockSender` - Captures the request for inspection - `MockSenderWithResponse` - Returns a fixed payload/error @@ -83,6 +80,7 @@ Tests use Mocha + Chai (`expect` style). Test files are prefixed with `test_` an ## Code Style - Uses Prettier: tabs, double quotes, 100 char line width, trailing commas -- Mixed JS/TS: Business logic (clients, lookups, results) in JS; infrastructure (credentials, senders, types) in TS +- All source and test files are TypeScript with ES module syntax (`import`/`export`) +- Import paths use `.js` extensions (TypeScript resolves `.js` to `.ts`) - Tests use Mocha + Chai with `expect` style assertions - Test files are prefixed with `test_` and mirror the source structure diff --git a/package.json b/package.json index 53dd546..34a4391 100644 --- a/package.json +++ b/package.json @@ -42,9 +42,7 @@ }, "scripts": { "build": "rollup --config", - "test": "npm run test:js && npm run test:ts", - "test:js": "mocha 'tests/**/*.{mjs,js}'", - "test:ts": "mocha --require tsx/cjs 'tests/**/*.ts'" + "test": "mocha --require tsx/cjs 'tests/**/*.ts'" }, "author": "Smarty SDK Team (https://www.smarty.com)", "license": "Apache-2.0", diff --git a/src/Batch.js b/src/Batch.js deleted file mode 100644 index 725590d..0000000 --- a/src/Batch.js +++ /dev/null @@ -1,49 +0,0 @@ -const BatchFullError = require("./Errors").BatchFullError; - -/** - * This class contains a collection of up to 100 lookups to be sent to one of the Smarty APIs
- * all at once. This is more efficient than sending them one at a time. - */ -class Batch { - constructor() { - this.lookups = []; - } - - add(lookup) { - if (this.lookupsHasRoomForLookup()) this.lookups.push(lookup); - else throw new BatchFullError(); - } - - lookupsHasRoomForLookup() { - const maxNumberOfLookups = 100; - return this.lookups.length < maxNumberOfLookups; - } - - length() { - return this.lookups.length; - } - - getByIndex(index) { - return this.lookups[index]; - } - - getByInputId(inputId) { - return this.lookups.filter((lookup) => { - return lookup.inputId === inputId; - })[0]; - } - - /** - * Clears the lookups stored in the batch so it can be used again.
- * This helps avoid the overhead of building a new Batch object for each group of lookups. - */ - clear() { - this.lookups = []; - } - - isEmpty() { - return this.length() === 0; - } -} - -module.exports = Batch; diff --git a/src/Batch.ts b/src/Batch.ts new file mode 100644 index 0000000..7070dad --- /dev/null +++ b/src/Batch.ts @@ -0,0 +1,41 @@ +import { BatchFullError } from "./Errors.js"; + +export default class Batch { + lookups: any[]; + + constructor() { + this.lookups = []; + } + + add(lookup: any): void { + if (this.lookupsHasRoomForLookup()) this.lookups.push(lookup); + else throw new BatchFullError(); + } + + lookupsHasRoomForLookup(): boolean { + const maxNumberOfLookups = 100; + return this.lookups.length < maxNumberOfLookups; + } + + length(): number { + return this.lookups.length; + } + + getByIndex(index: number): any { + return this.lookups[index]; + } + + getByInputId(inputId: any): any { + return this.lookups.filter((lookup) => { + return lookup.inputId === inputId; + })[0]; + } + + clear(): void { + this.lookups = []; + } + + isEmpty(): boolean { + return this.length() === 0; + } +} diff --git a/src/Errors.js b/src/Errors.js deleted file mode 100644 index 57d8635..0000000 --- a/src/Errors.js +++ /dev/null @@ -1,109 +0,0 @@ -class SmartyError extends Error { - constructor(message = "unexpected error") { - super(message); - } -} - -class DefaultError extends SmartyError { - constructor(message) { - super(message); - } -} - -class BatchFullError extends SmartyError { - constructor() { - super("A batch can contain a max of 100 lookups."); - } -} - -class BatchEmptyError extends SmartyError { - constructor() { - super("A batch must contain at least 1 lookup."); - } -} - -class UndefinedLookupError extends SmartyError { - constructor() { - super("The lookup provided is missing or undefined. Make sure you're passing a Lookup object."); - } -} - -class BadCredentialsError extends SmartyError { - constructor() { - super( - "Unauthorized: The credentials were provided incorrectly or did not match any existing active credentials.", - ); - } -} - -class PaymentRequiredError extends SmartyError { - constructor() { - super( - "Payment Required: There is no active subscription for the account associated with the credentials submitted with the request.", - ); - } -} - -class RequestEntityTooLargeError extends SmartyError { - constructor() { - super("Request Entity Too Large: The request body has exceeded the maximum size."); - } -} - -class BadRequestError extends SmartyError { - constructor() { - super( - "Bad Request (Malformed Payload): A GET request lacked a street field or the request body of a POST request contained malformed JSON.", - ); - } -} - -class UnprocessableEntityError extends SmartyError { - constructor(message) { - super(message); - } -} - -class TooManyRequestsError extends SmartyError { - constructor() { - super( - "When using the public 'embedded key' authentication, we restrict the number of requests coming from a given source over too short of a time.", - ); - } -} - -class InternalServerError extends SmartyError { - constructor() { - super("Internal Server Error."); - } -} - -class ServiceUnavailableError extends SmartyError { - constructor() { - super("Service Unavailable. Try again later."); - } -} - -class GatewayTimeoutError extends SmartyError { - constructor() { - super( - "The upstream data provider did not respond in a timely fashion and the request failed. A serious, yet rare occurrence indeed.", - ); - } -} - -module.exports = { - BatchFullError: BatchFullError, - BatchEmptyError: BatchEmptyError, - UndefinedLookupError: UndefinedLookupError, - BadCredentialsError: BadCredentialsError, - PaymentRequiredError: PaymentRequiredError, - RequestEntityTooLargeError: RequestEntityTooLargeError, - BadRequestError: BadRequestError, - UnprocessableEntityError: UnprocessableEntityError, - TooManyRequestsError: TooManyRequestsError, - InternalServerError: InternalServerError, - ServiceUnavailableError: ServiceUnavailableError, - GatewayTimeoutError: GatewayTimeoutError, - DefaultError: DefaultError, -}; diff --git a/src/InputData.js b/src/InputData.ts similarity index 52% rename from src/InputData.js rename to src/InputData.ts index c3d866b..666cbc9 100644 --- a/src/InputData.js +++ b/src/InputData.ts @@ -1,26 +1,27 @@ -class InputData { - constructor(lookup) { +export default class InputData { + lookup: Record; + data: Record; + + constructor(lookup: Record) { this.lookup = lookup; this.data = {}; } - add(apiField, lookupField) { + add(apiField: string, lookupField: string): void { if (this.lookupFieldIsPopulated(lookupField)) this.data[apiField] = this.formatData(this.lookup[lookupField]); } - addCustomParameter(key, value) { + addCustomParameter(key: string, value: any): void { this.data[key] = value; } - formatData(field) { + formatData(field: any): any { if (Array.isArray(field)) return field.join(";"); else return field; } - lookupFieldIsPopulated(lookupField) { + lookupFieldIsPopulated(lookupField: string): boolean { return this.lookup[lookupField] !== "" && this.lookup[lookupField] !== undefined; } } - -module.exports = InputData; diff --git a/src/Request.js b/src/Request.js deleted file mode 100644 index b8e427b..0000000 --- a/src/Request.js +++ /dev/null @@ -1,12 +0,0 @@ -class Request { - constructor(payload, headers = { "Content-Type": "application/json; charset=utf-8" }) { - this.baseUrl = ""; - this.baseUrlParam = ""; - this.payload = payload; - this.headers = headers; - - this.parameters = {}; - } -} - -module.exports = Request; diff --git a/src/Response.js b/src/Response.js deleted file mode 100644 index a2b0f02..0000000 --- a/src/Response.js +++ /dev/null @@ -1,10 +0,0 @@ -class Response { - constructor(statusCode, payload, error, headers) { - this.statusCode = statusCode; - this.payload = payload; - this.error = error; - this.headers = headers; - } -} - -module.exports = Response; diff --git a/src/international_address_autocomplete/Lookup.js b/src/international_address_autocomplete/Lookup.js deleted file mode 100644 index 5f0383e..0000000 --- a/src/international_address_autocomplete/Lookup.js +++ /dev/null @@ -1,26 +0,0 @@ -class Lookup { - constructor({ - search, - addressId, - country, - maxResults = 5, - includeOnlyLocality, - includeOnlyPostalCode, - } = {}) { - this.result = []; - - this.search = search; - this.addressId = addressId; - this.country = country; - this.maxResults = maxResults; - this.includeOnlyLocality = includeOnlyLocality; - this.includeOnlyPostalCode = includeOnlyPostalCode; - this.customParameters = {}; - } - - addCustomParameter(key, value) { - this.customParameters[key] = value; - } -} - -module.exports = Lookup; diff --git a/src/international_address_autocomplete/Lookup.ts b/src/international_address_autocomplete/Lookup.ts new file mode 100644 index 0000000..0bc19f4 --- /dev/null +++ b/src/international_address_autocomplete/Lookup.ts @@ -0,0 +1,40 @@ +export default class Lookup { + result: any[]; + search: string | undefined; + addressId: string | undefined; + country: string | undefined; + maxResults: number; + includeOnlyLocality: string | undefined; + includeOnlyPostalCode: string | undefined; + customParameters: Record; + + constructor({ + search, + addressId, + country, + maxResults = 5, + includeOnlyLocality, + includeOnlyPostalCode, + }: { + search?: string; + addressId?: string; + country?: string; + maxResults?: number; + includeOnlyLocality?: string; + includeOnlyPostalCode?: string; + } = {}) { + this.result = []; + + this.search = search; + this.addressId = addressId; + this.country = country; + this.maxResults = maxResults; + this.includeOnlyLocality = includeOnlyLocality; + this.includeOnlyPostalCode = includeOnlyPostalCode; + this.customParameters = {}; + } + + addCustomParameter(key: string, value: any): void { + this.customParameters[key] = value; + } +} diff --git a/src/international_address_autocomplete/Suggestion.js b/src/international_address_autocomplete/Suggestion.ts similarity index 61% rename from src/international_address_autocomplete/Suggestion.js rename to src/international_address_autocomplete/Suggestion.ts index cfd0cc1..15a484d 100644 --- a/src/international_address_autocomplete/Suggestion.js +++ b/src/international_address_autocomplete/Suggestion.ts @@ -1,5 +1,16 @@ -class Suggestion { - constructor(responseData) { +export default class Suggestion { + street: string; + locality: string; + administrativeArea: string; + administrativeAreaShort: string; + administrativeAreaLong: string; + postalCode: string; + countryIso3: string; + entries: number; + addressText: string; + addressId: string; + + constructor(responseData: Record) { this.street = responseData.street; this.locality = responseData.locality; this.administrativeArea = responseData.administrative_area; @@ -12,5 +23,3 @@ class Suggestion { this.addressId = responseData.address_id; } } - -module.exports = Suggestion; diff --git a/src/international_postal_code/Lookup.js b/src/international_postal_code/Lookup.js deleted file mode 100644 index a205418..0000000 --- a/src/international_postal_code/Lookup.js +++ /dev/null @@ -1,22 +0,0 @@ -/** - * In addition to holding all of the input data for this lookup, this class also
- * will contain the result of the lookup after it comes back from the API. - * @see "https://www.smarty.com/docs/cloud/international-postal-code-api#http-request-input-fields" - */ -class Lookup { - constructor(country, postalCode, administrativeArea, locality, inputId) { - this.inputId = inputId; - this.country = country; - this.postalCode = postalCode; - this.administrativeArea = administrativeArea; - this.locality = locality; - this.result = []; - this.customParameters = {}; - } - - addCustomParameter(key, value) { - this.customParameters[key] = value; - } -} - -module.exports = Lookup; diff --git a/src/international_postal_code/Lookup.ts b/src/international_postal_code/Lookup.ts new file mode 100644 index 0000000..bd0d3c5 --- /dev/null +++ b/src/international_postal_code/Lookup.ts @@ -0,0 +1,29 @@ +export default class Lookup { + inputId: string | undefined; + country: string | undefined; + postalCode: string | undefined; + administrativeArea: string | undefined; + locality: string | undefined; + result: any[]; + customParameters: Record; + + constructor( + country?: string, + postalCode?: string, + administrativeArea?: string, + locality?: string, + inputId?: string, + ) { + this.inputId = inputId; + this.country = country; + this.postalCode = postalCode; + this.administrativeArea = administrativeArea; + this.locality = locality; + this.result = []; + this.customParameters = {}; + } + + addCustomParameter(key: string, value: any): void { + this.customParameters[key] = value; + } +} diff --git a/src/international_postal_code/Result.js b/src/international_postal_code/Result.ts similarity index 63% rename from src/international_postal_code/Result.js rename to src/international_postal_code/Result.ts index ccfa723..5c979b2 100644 --- a/src/international_postal_code/Result.js +++ b/src/international_postal_code/Result.ts @@ -1,8 +1,17 @@ -/** - * @see "https://www.smarty.com/docs/cloud/international-postal-code-api#output-fields" - */ -class Result { - constructor(responseData) { +export default class Result { + inputId: string; + administrativeArea: string; + superAdministrativeArea: string; + subAdministrativeArea: string; + locality: string; + dependentLocality: string; + dependentLocalityName: string; + doubleDependentLocality: string; + postalCode: string; + postalCodeExtra: string; + countryIso3: string; + + constructor(responseData: Record) { this.inputId = responseData.input_id; this.administrativeArea = responseData.administrative_area; this.superAdministrativeArea = responseData.super_administrative_area; @@ -16,5 +25,3 @@ class Result { this.countryIso3 = responseData.country_iso_3; } } - -module.exports = Result; diff --git a/src/international_street/Candidate.js b/src/international_street/Candidate.ts similarity index 96% rename from src/international_street/Candidate.js rename to src/international_street/Candidate.ts index 180dfe1..ed29473 100644 --- a/src/international_street/Candidate.js +++ b/src/international_street/Candidate.ts @@ -1,11 +1,22 @@ -/** - * A candidate is a possible match for an address that was submitted.
- * A lookup can have multiple candidates if the address was ambiguous. - * - * @see "https://www.smarty.com/docs/cloud/international-street-api#root" - */ -class Candidate { - constructor(responseData) { +export default class Candidate { + organization: string; + address1: string; + address2: string; + address3: string; + address4: string; + address5: string; + address6: string; + address7: string; + address8: string; + address9: string; + address10: string; + address11: string; + address12: string; + components: Record; + analysis: Record; + metadata: Record; + + constructor(responseData: Record) { this.organization = responseData.organization; this.address1 = responseData.address1; this.address2 = responseData.address2; @@ -210,5 +221,3 @@ class Candidate { } } } - -module.exports = Candidate; diff --git a/src/international_street/Lookup.js b/src/international_street/Lookup.ts similarity index 65% rename from src/international_street/Lookup.js rename to src/international_street/Lookup.ts index 050d990..0445160 100644 --- a/src/international_street/Lookup.js +++ b/src/international_street/Lookup.ts @@ -1,4 +1,5 @@ -const UnprocessableEntityError = require("../Errors").UnprocessableEntityError; +import { UnprocessableEntityError } from "../Errors.js"; + const messages = { countryRequired: "Country field is required.", freeformOrAddress1Required: "Either freeform or address1 is required.", @@ -9,15 +10,36 @@ const messages = { "Invalid input: language can only be set to 'latin' or 'native'. When not set, the the output language will match the language of the input values.", }; -/** - * In addition to holding all of the input data for this lookup, this class also
- * will contain the result of the lookup after it comes back from the API. - *

Note: Lookups must have certain required fields set with non-blank values.
- * These can be found at the URL below.

- * @see "https://www.smarty.com/docs/cloud/international-street-api#http-input-fields" - */ -class Lookup { - constructor(country, freeform) { +function fieldIsMissing(field: string | undefined): boolean { + if (!field) return true; + + const whitespaceCharacters = /\s/g; + + return field.replace(whitespaceCharacters, "").length < 1; +} + +function fieldIsSet(field: string | undefined): boolean { + return !fieldIsMissing(field); +} + +export default class Lookup { + result: any[]; + country: string | undefined; + freeform: string | undefined; + address1: string | undefined; + address2: string | undefined; + address3: string | undefined; + address4: string | undefined; + organization: string | undefined; + locality: string | undefined; + administrativeArea: string | undefined; + postalCode: string | undefined; + geocode: string | undefined; + language: string | undefined; + inputId: string | undefined; + customParameters: Record; + + constructor(country?: string, freeform?: string) { this.result = []; this.country = country; @@ -39,11 +61,11 @@ class Lookup { this.customParameters = {}; } - addCustomParameter(key, value) { + addCustomParameter(key: string, value: any): void { this.customParameters[key] = value; } - ensureEnoughInfo() { + ensureEnoughInfo(): boolean { if (fieldIsMissing(this.country)) throw new UnprocessableEntityError(messages.countryRequired); if (fieldIsSet(this.freeform)) return true; @@ -59,15 +81,15 @@ class Lookup { return true; } - ensureValidData() { - let languageIsSetIncorrectly = () => { - let isLanguage = (language) => this.language.toLowerCase() === language; + ensureValidData(): boolean { + const languageIsSetIncorrectly = () => { + const isLanguage = (language: string) => this.language!.toLowerCase() === language; return fieldIsSet(this.language) && !(isLanguage("latin") || isLanguage("native")); }; - let geocodeIsSetIncorrectly = () => { - return fieldIsSet(this.geocode) && this.geocode.toLowerCase() !== "true"; + const geocodeIsSetIncorrectly = () => { + return fieldIsSet(this.geocode) && this.geocode!.toLowerCase() !== "true"; }; if (geocodeIsSetIncorrectly()) throw new UnprocessableEntityError(messages.badGeocode); @@ -77,17 +99,3 @@ class Lookup { return true; } } - -function fieldIsMissing(field) { - if (!field) return true; - - const whitespaceCharacters = /\s/g; - - return field.replace(whitespaceCharacters, "").length < 1; -} - -function fieldIsSet(field) { - return !fieldIsMissing(field); -} - -module.exports = Lookup; diff --git a/src/us_autocomplete_pro/Lookup.js b/src/us_autocomplete_pro/Lookup.js deleted file mode 100644 index 4ad5dfc..0000000 --- a/src/us_autocomplete_pro/Lookup.js +++ /dev/null @@ -1,34 +0,0 @@ -/** - * In addition to holding all of the input data for this lookup, this class also
- * will contain the result of the lookup after it comes back from the API. - * @see "https://www.smarty.com/docs/cloud/us-autocomplete-api#pro-http-request-input-fields" - */ -class Lookup { - /** - * @param search The beginning of an address. This is required to be set. - */ - constructor(search) { - this.result = []; - - this.search = search; - this.selected = undefined; - this.maxResults = undefined; - this.includeOnlyCities = []; - this.includeOnlyStates = []; - this.includeOnlyZIPCodes = []; - this.excludeStates = []; - this.preferCities = []; - this.preferStates = []; - this.preferZIPCodes = []; - this.preferRatio = undefined; - this.preferGeolocation = undefined; - this.source = undefined; - this.customParameters = {}; - } - - addCustomParameter(key, value) { - this.customParameters[key] = value; - } -} - -module.exports = Lookup; diff --git a/src/us_autocomplete_pro/Lookup.ts b/src/us_autocomplete_pro/Lookup.ts new file mode 100644 index 0000000..c914e1d --- /dev/null +++ b/src/us_autocomplete_pro/Lookup.ts @@ -0,0 +1,40 @@ +export default class Lookup { + result: any[]; + search: string | undefined; + selected: string | undefined; + maxResults: number | undefined; + includeOnlyCities: string[]; + includeOnlyStates: string[]; + includeOnlyZIPCodes: string[]; + excludeStates: string[]; + preferCities: string[]; + preferStates: string[]; + preferZIPCodes: string[]; + preferRatio: number | undefined; + preferGeolocation: string | undefined; + source: string | undefined; + customParameters: Record; + + constructor(search?: string) { + this.result = []; + + this.search = search; + this.selected = undefined; + this.maxResults = undefined; + this.includeOnlyCities = []; + this.includeOnlyStates = []; + this.includeOnlyZIPCodes = []; + this.excludeStates = []; + this.preferCities = []; + this.preferStates = []; + this.preferZIPCodes = []; + this.preferRatio = undefined; + this.preferGeolocation = undefined; + this.source = undefined; + this.customParameters = {}; + } + + addCustomParameter(key: string, value: any): void { + this.customParameters[key] = value; + } +} diff --git a/src/us_autocomplete_pro/Suggestion.js b/src/us_autocomplete_pro/Suggestion.ts similarity index 58% rename from src/us_autocomplete_pro/Suggestion.js rename to src/us_autocomplete_pro/Suggestion.ts index c58ab3e..d7b3249 100644 --- a/src/us_autocomplete_pro/Suggestion.js +++ b/src/us_autocomplete_pro/Suggestion.ts @@ -1,8 +1,13 @@ -/** - * @see "https://www.smarty.com/docs/cloud/us-autocomplete-api#pro-http-response" - */ -class Suggestion { - constructor(responseData) { +export default class Suggestion { + streetLine: string; + secondary: string; + city: string; + state: string; + zipcode: string; + entries: number; + source: string | undefined; + + constructor(responseData: Record) { this.streetLine = responseData.street_line; this.secondary = responseData.secondary; this.city = responseData.city; @@ -15,5 +20,3 @@ class Suggestion { } } } - -module.exports = Suggestion; diff --git a/src/us_enrichment/Lookup.js b/src/us_enrichment/Lookup.js deleted file mode 100644 index c4ad2a9..0000000 --- a/src/us_enrichment/Lookup.js +++ /dev/null @@ -1,19 +0,0 @@ -class Lookup { - constructor(smartyKey, include, exclude, dataset, dataSubset) { - this.smartyKey = smartyKey; - this.include = include; - this.exclude = exclude; - this.dataset = dataset; - this.dataSubset = dataSubset; - this.features = undefined; - - this.response = {}; - this.customParameters = {}; - } - - addCustomParameter(key, value) { - this.customParameters[key] = value; - } -} - -module.exports = Lookup; diff --git a/src/us_enrichment/Lookup.ts b/src/us_enrichment/Lookup.ts new file mode 100644 index 0000000..27c30ee --- /dev/null +++ b/src/us_enrichment/Lookup.ts @@ -0,0 +1,32 @@ +export default class Lookup { + smartyKey: string | undefined; + include: string | undefined; + exclude: string | undefined; + dataset: string | undefined; + dataSubset: string | undefined; + features: string | undefined; + response: Record; + customParameters: Record; + + constructor( + smartyKey?: string, + include?: string, + exclude?: string, + dataset?: string, + dataSubset?: string, + ) { + this.smartyKey = smartyKey; + this.include = include; + this.exclude = exclude; + this.dataset = dataset; + this.dataSubset = dataSubset; + this.features = undefined; + + this.response = {}; + this.customParameters = {}; + } + + addCustomParameter(key: string, value: any): void { + this.customParameters[key] = value; + } +} diff --git a/src/us_extract/Lookup.js b/src/us_extract/Lookup.js deleted file mode 100644 index 0b12633..0000000 --- a/src/us_extract/Lookup.js +++ /dev/null @@ -1,29 +0,0 @@ -/** - * In addition to holding all of the input data for this lookup, this class also
- * will contain the result of the lookup after it comes back from the API. - * @see "https://www.smarty.com/docs/cloud/us-extract-api#http-request-input-fields" - */ -class Lookup { - /** - * @param text The text that is to have addresses extracted out of it for verification (required) - */ - constructor(text) { - this.result = { - meta: {}, - addresses: [], - }; - //TODO: require the text field. - this.text = text; - this.html = undefined; - this.aggressive = undefined; - this.addressesHaveLineBreaks = undefined; - this.addressesPerLine = undefined; - this.customParameters = {}; - } - - addCustomParameter(key, value) { - this.customParameters[key] = value; - } -} - -module.exports = Lookup; diff --git a/src/us_extract/Lookup.ts b/src/us_extract/Lookup.ts new file mode 100644 index 0000000..6d9d45e --- /dev/null +++ b/src/us_extract/Lookup.ts @@ -0,0 +1,26 @@ +export default class Lookup { + result: Record; + text: string; + html: boolean | undefined; + aggressive: boolean | undefined; + addressesHaveLineBreaks: boolean | undefined; + addressesPerLine: number | undefined; + customParameters: Record; + + constructor(text: string) { + this.result = { + meta: {}, + addresses: [], + }; + this.text = text; + this.html = undefined; + this.aggressive = undefined; + this.addressesHaveLineBreaks = undefined; + this.addressesPerLine = undefined; + this.customParameters = {}; + } + + addCustomParameter(key: string, value: any): void { + this.customParameters[key] = value; + } +} diff --git a/src/us_extract/Result.js b/src/us_extract/Result.ts similarity index 54% rename from src/us_extract/Result.js rename to src/us_extract/Result.ts index eefa86f..7c43d08 100644 --- a/src/us_extract/Result.js +++ b/src/us_extract/Result.ts @@ -1,10 +1,16 @@ -const Address = require("./Address"); +import Address from "./Address.js"; -/** - * @see Smarty US Extract API docs - */ -class Result { - constructor({ meta, addresses }) { +export default class Result { + meta: Record; + addresses: Address[]; + + constructor({ + meta, + addresses, + }: { + meta: Record; + addresses: Record[]; + }) { this.meta = { lines: meta.lines, unicode: meta.unicode, @@ -17,5 +23,3 @@ class Result { this.addresses = addresses.map((rawAddress) => new Address(rawAddress)); } } - -module.exports = Result; diff --git a/src/us_reverse_geo/Lookup.js b/src/us_reverse_geo/Lookup.js deleted file mode 100644 index ce8446a..0000000 --- a/src/us_reverse_geo/Lookup.js +++ /dev/null @@ -1,22 +0,0 @@ -const Response = require("./Response"); - -/** - * In addition to holding all of the input data for this lookup, this class also
- * will contain the result of the lookup after it comes back from the API. - * @see "https://www.smarty.com/docs/cloud/us-street-api#input-fields" - */ -class Lookup { - constructor(latitude, longitude, source = "") { - this.latitude = latitude.toFixed(8); - this.longitude = longitude.toFixed(8); - this.source = source; - this.response = new Response(); - this.customParameters = {}; - } - - addCustomParameter(key, value) { - this.customParameters[key] = value; - } -} - -module.exports = Lookup; diff --git a/src/us_reverse_geo/Lookup.ts b/src/us_reverse_geo/Lookup.ts new file mode 100644 index 0000000..92a4342 --- /dev/null +++ b/src/us_reverse_geo/Lookup.ts @@ -0,0 +1,21 @@ +import Response from "./Response.js"; + +export default class Lookup { + latitude: string; + longitude: string; + source: string; + response: Response; + customParameters: Record; + + constructor(latitude: number, longitude: number, source: string = "") { + this.latitude = latitude.toFixed(8); + this.longitude = longitude.toFixed(8); + this.source = source; + this.response = new Response(); + this.customParameters = {}; + } + + addCustomParameter(key: string, value: any): void { + this.customParameters[key] = value; + } +} diff --git a/src/us_street/Candidate.js b/src/us_street/Candidate.ts similarity index 94% rename from src/us_street/Candidate.js rename to src/us_street/Candidate.ts index eb160cf..5d991cb 100644 --- a/src/us_street/Candidate.js +++ b/src/us_street/Candidate.ts @@ -1,12 +1,17 @@ -/** - * A candidate is a possible match for an address that was submitted.
- * A lookup can have multiple candidates if the address was ambiguous, and
- * the maxCandidates field is set higher than 1. - * - * @see "https://www.smarty.com/docs/cloud/us-street-api#root" - */ -class Candidate { - constructor(responseData) { +export default class Candidate { + inputIndex: number; + candidateIndex: number; + addressee: string; + deliveryLine1: string; + deliveryLine2: string; + lastLine: string; + deliveryPointBarcode: string; + smartyKey: string; + components: Record; + metadata: Record; + analysis: Record; + + constructor(responseData: Record) { this.inputIndex = responseData.input_index; this.candidateIndex = responseData.candidate_index; this.addressee = responseData.addressee; @@ -108,5 +113,3 @@ class Candidate { } } } - -module.exports = Candidate; diff --git a/src/us_street/Client.js b/src/us_street/Client.js deleted file mode 100644 index 3bee62b..0000000 --- a/src/us_street/Client.js +++ /dev/null @@ -1,41 +0,0 @@ -const Candidate = require("./Candidate"); -const Lookup = require("./Lookup"); -const Batch = require("../Batch"); -const UndefinedLookupError = require("../Errors").UndefinedLookupError; -const sendBatch = require("../util/sendBatch"); -const buildUsStreetInputData = require("../util/buildUsStreetInputData"); - -/** - * This client sends lookups to the Smarty US Street API,
- * and attaches the results to the appropriate Lookup objects. - */ -class Client { - constructor(sender) { - this.sender = sender; - } - - /** - * Sends up to 100 lookups for validation. - * @param data may be a Lookup object, or a Batch which must contain between 1 and 100 Lookup objects - * @throws SmartyException - */ - send(data) { - const dataIsBatch = data instanceof Batch; - const dataIsLookup = data instanceof Lookup; - - if (!dataIsLookup && !dataIsBatch) throw new UndefinedLookupError(); - - let batch; - - if (dataIsLookup) { - batch = new Batch(); - batch.add(data); - } else { - batch = data; - } - - return sendBatch(batch, this.sender, Candidate, null, buildUsStreetInputData); - } -} - -module.exports = Client; diff --git a/src/us_street/Client.ts b/src/us_street/Client.ts new file mode 100644 index 0000000..d7e35fa --- /dev/null +++ b/src/us_street/Client.ts @@ -0,0 +1,33 @@ +import Candidate from "./Candidate.js"; +import Lookup from "./Lookup.js"; +import Batch from "../Batch.js"; +import { UndefinedLookupError } from "../Errors.js"; +import sendBatch from "../util/sendBatch.js"; +import buildUsStreetInputData from "../util/buildUsStreetInputData.js"; +import { Sender } from "../types.js"; + +export default class Client { + private sender: Sender; + + constructor(sender: Sender) { + this.sender = sender; + } + + send(data: Lookup | Batch): Promise { + const dataIsBatch = data instanceof Batch; + const dataIsLookup = data instanceof Lookup; + + if (!dataIsLookup && !dataIsBatch) throw new UndefinedLookupError(); + + let batch: Batch; + + if (dataIsLookup) { + batch = new Batch(); + batch.add(data); + } else { + batch = data; + } + + return sendBatch(batch, this.sender, Candidate, null, buildUsStreetInputData); + } +} diff --git a/src/us_street/Lookup.js b/src/us_street/Lookup.js deleted file mode 100644 index 0088b1e..0000000 --- a/src/us_street/Lookup.js +++ /dev/null @@ -1,46 +0,0 @@ -/** - * In addition to holding all of the input data for this lookup, this class also
- * will contain the result of the lookup after it comes back from the API. - * @see "https://www.smarty.com/docs/cloud/us-street-api#input-fields" - */ -class Lookup { - constructor( - street, - street2, - secondary, - city, - state, - zipCode, - lastLine, - addressee, - urbanization, - match, - maxCandidates, - inputId, - format, - countySource, - ) { - this.street = street; - this.street2 = street2; - this.secondary = secondary; - this.city = city; - this.state = state; - this.zipCode = zipCode; - this.lastLine = lastLine; - this.addressee = addressee; - this.urbanization = urbanization; - this.match = match; - this.maxCandidates = maxCandidates; - this.inputId = inputId; - this.format = format; - this.countySource = countySource; - this.result = []; - this.customParameters = {}; - } - - addCustomParameter(key, value) { - this.customParameters[key] = value; - } -} - -module.exports = Lookup; diff --git a/src/us_street/Lookup.ts b/src/us_street/Lookup.ts new file mode 100644 index 0000000..08bec1f --- /dev/null +++ b/src/us_street/Lookup.ts @@ -0,0 +1,56 @@ +export default class Lookup { + street: string | undefined; + street2: string | undefined; + secondary: string | undefined; + city: string | undefined; + state: string | undefined; + zipCode: string | undefined; + lastLine: string | undefined; + addressee: string | undefined; + urbanization: string | undefined; + match: string | undefined; + maxCandidates: number | undefined; + inputId: string | undefined; + format: string | undefined; + countySource: string | undefined; + result: any[]; + customParameters: Record; + + constructor( + street?: string, + street2?: string, + secondary?: string, + city?: string, + state?: string, + zipCode?: string, + lastLine?: string, + addressee?: string, + urbanization?: string, + match?: string, + maxCandidates?: number, + inputId?: string, + format?: string, + countySource?: string, + ) { + this.street = street; + this.street2 = street2; + this.secondary = secondary; + this.city = city; + this.state = state; + this.zipCode = zipCode; + this.lastLine = lastLine; + this.addressee = addressee; + this.urbanization = urbanization; + this.match = match; + this.maxCandidates = maxCandidates; + this.inputId = inputId; + this.format = format; + this.countySource = countySource; + this.result = []; + this.customParameters = {}; + } + + addCustomParameter(key: string, value: any): void { + this.customParameters[key] = value; + } +} diff --git a/src/us_zipcode/Client.js b/src/us_zipcode/Client.js deleted file mode 100644 index 4b7c7df..0000000 --- a/src/us_zipcode/Client.js +++ /dev/null @@ -1,39 +0,0 @@ -const Lookup = require("./Lookup"); -const Result = require("./Result"); -const Batch = require("../Batch"); -const UndefinedLookupError = require("../Errors").UndefinedLookupError; -const sendBatch = require("../util/sendBatch"); -const keyTranslationFormat = require("../util/apiToSDKKeyMap").usZipcode; - -/** - * This client sends lookups to the Smarty US ZIP Code API,
- * and attaches the results to the appropriate Lookup objects. - */ -class Client { - constructor(sender) { - this.sender = sender; - } - - /** - * Sends up to 100 lookups for validation. - * @param data May be a Lookup object, or a Batch which must contain between 1 and 100 Lookup objects - * @throws SmartyException - */ - send(data) { - const dataIsBatch = data instanceof Batch; - const dataIsLookup = data instanceof Lookup; - - if (!dataIsLookup && !dataIsBatch) throw new UndefinedLookupError(); - - let batch; - - if (dataIsLookup) { - batch = new Batch(); - batch.add(data); - } else batch = data; - - return sendBatch(batch, this.sender, Result, keyTranslationFormat); - } -} - -module.exports = Client; diff --git a/src/us_zipcode/Client.ts b/src/us_zipcode/Client.ts new file mode 100644 index 0000000..622ac41 --- /dev/null +++ b/src/us_zipcode/Client.ts @@ -0,0 +1,33 @@ +import Lookup from "./Lookup.js"; +import Result from "./Result.js"; +import Batch from "../Batch.js"; +import { UndefinedLookupError } from "../Errors.js"; +import sendBatch from "../util/sendBatch.js"; +import apiToSDKKeyMap from "../util/apiToSDKKeyMap.js"; +import { Sender } from "../types.js"; + +const keyTranslationFormat = apiToSDKKeyMap.usZipcode; + +export default class Client { + private sender: Sender; + + constructor(sender: Sender) { + this.sender = sender; + } + + send(data: Lookup | Batch): Promise { + const dataIsBatch = data instanceof Batch; + const dataIsLookup = data instanceof Lookup; + + if (!dataIsLookup && !dataIsBatch) throw new UndefinedLookupError(); + + let batch: Batch; + + if (dataIsLookup) { + batch = new Batch(); + batch.add(data); + } else batch = data; + + return sendBatch(batch, this.sender, Result, keyTranslationFormat); + } +} diff --git a/src/us_zipcode/Lookup.js b/src/us_zipcode/Lookup.js deleted file mode 100644 index 558c140..0000000 --- a/src/us_zipcode/Lookup.js +++ /dev/null @@ -1,21 +0,0 @@ -/** - * In addition to holding all of the input data for this lookup, this class also
- * will contain the result of the lookup after it comes back from the API. - * @see "https://www.smarty.com/docs/cloud/us-zipcode-api#http-request-input-fields" - */ -class Lookup { - constructor(city, state, zipCode, inputId) { - this.city = city; - this.state = state; - this.zipCode = zipCode; - this.inputId = inputId; - this.result = []; - this.customParameters = {}; - } - - addCustomParameter(key, value) { - this.customParameters[key] = value; - } -} - -module.exports = Lookup; diff --git a/src/us_zipcode/Lookup.ts b/src/us_zipcode/Lookup.ts new file mode 100644 index 0000000..aa343ec --- /dev/null +++ b/src/us_zipcode/Lookup.ts @@ -0,0 +1,21 @@ +export default class Lookup { + city: string | undefined; + state: string | undefined; + zipCode: string | undefined; + inputId: string | undefined; + result: any[]; + customParameters: Record; + + constructor(city?: string, state?: string, zipCode?: string, inputId?: string) { + this.city = city; + this.state = state; + this.zipCode = zipCode; + this.inputId = inputId; + this.result = []; + this.customParameters = {}; + } + + addCustomParameter(key: string, value: any): void { + this.customParameters[key] = value; + } +} diff --git a/src/us_zipcode/Result.js b/src/us_zipcode/Result.ts similarity index 71% rename from src/us_zipcode/Result.js rename to src/us_zipcode/Result.ts index f92188a..e2ef783 100644 --- a/src/us_zipcode/Result.js +++ b/src/us_zipcode/Result.ts @@ -1,8 +1,12 @@ -/** - * @see "https://www.smarty.com/docs/cloud/us-zipcode-api#root" - */ -class Result { - constructor(responseData) { +export default class Result { + inputIndex: number; + status: string | undefined; + reason: string | undefined; + valid: boolean; + cities: Record[]; + zipcodes: Record[]; + + constructor(responseData: Record) { this.inputIndex = responseData.input_index; this.status = responseData.status; this.reason = responseData.reason; @@ -10,7 +14,7 @@ class Result { this.cities = !responseData.city_states ? [] - : responseData.city_states.map((city) => { + : responseData.city_states.map((city: Record) => { return { city: city.city, stateAbbreviation: city.state_abbreviation, @@ -21,7 +25,7 @@ class Result { this.zipcodes = !responseData.zipcodes ? [] - : responseData.zipcodes.map((zipcode) => { + : responseData.zipcodes.map((zipcode: Record) => { return { zipcode: zipcode.zipcode, zipcodeType: zipcode.zipcode_type, @@ -35,7 +39,7 @@ class Result { state: zipcode.state, alternateCounties: !zipcode.alternate_counties ? [] - : zipcode.alternate_counties.map((county) => { + : zipcode.alternate_counties.map((county: Record) => { return { countyFips: county.county_fips, countyName: county.county_name, @@ -47,5 +51,3 @@ class Result { }); } } - -module.exports = Result; diff --git a/src/util/apiToSDKKeyMap.js b/src/util/apiToSDKKeyMap.ts similarity index 95% rename from src/util/apiToSDKKeyMap.js rename to src/util/apiToSDKKeyMap.ts index 069a9e3..bb62bb5 100644 --- a/src/util/apiToSDKKeyMap.js +++ b/src/util/apiToSDKKeyMap.ts @@ -1,4 +1,4 @@ -module.exports = { +const apiToSDKKeyMap: Record> = { usStreet: { street: "street", street2: "street2", @@ -82,3 +82,5 @@ module.exports = { postal_code: "postalCode", }, }; + +export default apiToSDKKeyMap; diff --git a/src/util/buildClients.js b/src/util/buildClients.ts similarity index 57% rename from src/util/buildClients.js rename to src/util/buildClients.ts index dc59b09..6f2ad55 100644 --- a/src/util/buildClients.js +++ b/src/util/buildClients.ts @@ -1,46 +1,51 @@ -const ClientBuilder = require("../ClientBuilder"); +import ClientBuilder from "../ClientBuilder.js"; +import StaticCredentials from "../StaticCredentials.js"; +import SharedCredentials from "../SharedCredentials.js"; +import BasicAuthCredentials from "../BasicAuthCredentials.js"; -function instantiateClientBuilder(credentials) { +type Credentials = StaticCredentials | SharedCredentials | BasicAuthCredentials; + +function instantiateClientBuilder(credentials: Credentials): ClientBuilder { return new ClientBuilder(credentials); } -function buildUsStreetApiClient(credentials) { +function buildUsStreetApiClient(credentials: Credentials) { return instantiateClientBuilder(credentials).buildUsStreetApiClient(); } -function buildUsAutocompleteProApiClient(credentials) { +function buildUsAutocompleteProApiClient(credentials: Credentials) { return instantiateClientBuilder(credentials).buildUsAutocompleteProClient(); } -function buildUsExtractApiClient(credentials) { +function buildUsExtractApiClient(credentials: Credentials) { return instantiateClientBuilder(credentials).buildUsExtractClient(); } -function buildUsZipcodeApiClient(credentials) { +function buildUsZipcodeApiClient(credentials: Credentials) { return instantiateClientBuilder(credentials).buildUsZipcodeClient(); } -function buildInternationalStreetApiClient(credentials) { +function buildInternationalStreetApiClient(credentials: Credentials) { return instantiateClientBuilder(credentials).buildInternationalStreetClient(); } -function buildUsReverseGeoApiClient(credentials) { +function buildUsReverseGeoApiClient(credentials: Credentials) { return instantiateClientBuilder(credentials).buildUsReverseGeoClient(); } -function buildInternationalAddressAutocompleteApiClient(credentials) { +function buildInternationalAddressAutocompleteApiClient(credentials: Credentials) { return instantiateClientBuilder(credentials).buildInternationalAddressAutocompleteClient(); } -function buildUsEnrichmentApiClient(credentials) { +function buildUsEnrichmentApiClient(credentials: Credentials) { return instantiateClientBuilder(credentials).buildUsEnrichmentClient(); } -function buildInternationalPostalCodeApiClient(credentials) { +function buildInternationalPostalCodeApiClient(credentials: Credentials) { return instantiateClientBuilder(credentials).buildInternationalPostalCodeClient(); } -module.exports = { +export default { usStreet: buildUsStreetApiClient, usAutocompletePro: buildUsAutocompleteProApiClient, usExtract: buildUsExtractApiClient, diff --git a/src/util/buildInputData.js b/src/util/buildInputData.js deleted file mode 100644 index de254e8..0000000 --- a/src/util/buildInputData.js +++ /dev/null @@ -1,19 +0,0 @@ -const InputData = require("../InputData"); - -module.exports = (lookup, keyTranslationFormat) => { - let inputData = new InputData(lookup); - - const hasCustomParameters = Object.keys(lookup.customParameters ?? {}).length > 0; - - for (let key in keyTranslationFormat) { - inputData.add(key, keyTranslationFormat[key]); - } - - if (hasCustomParameters) { - for (let key in lookup.customParameters) { - inputData.addCustomParameter(key, lookup.customParameters[key]); - } - } - - return inputData.data; -}; diff --git a/src/util/buildInputData.ts b/src/util/buildInputData.ts new file mode 100644 index 0000000..1f67887 --- /dev/null +++ b/src/util/buildInputData.ts @@ -0,0 +1,22 @@ +import InputData from "../InputData.js"; + +export default function buildInputData( + lookup: Record, + keyTranslationFormat: Record, +): Record { + const inputData = new InputData(lookup); + + const hasCustomParameters = Object.keys(lookup.customParameters ?? {}).length > 0; + + for (const key in keyTranslationFormat) { + inputData.add(key, keyTranslationFormat[key]); + } + + if (hasCustomParameters) { + for (const key in lookup.customParameters) { + inputData.addCustomParameter(key, lookup.customParameters[key]); + } + } + + return inputData.data; +} diff --git a/src/util/buildUsStreetInputData.js b/src/util/buildUsStreetInputData.ts similarity index 75% rename from src/util/buildUsStreetInputData.js rename to src/util/buildUsStreetInputData.ts index a122803..b6772bc 100644 --- a/src/util/buildUsStreetInputData.js +++ b/src/util/buildUsStreetInputData.ts @@ -1,7 +1,9 @@ -const buildInputData = require("./buildInputData"); -const keyTranslationFormat = require("./apiToSDKKeyMap").usStreet; +import buildInputData from "./buildInputData.js"; +import apiToSDKKeyMap from "./apiToSDKKeyMap.js"; -module.exports = (lookup) => { +const keyTranslationFormat = apiToSDKKeyMap.usStreet; + +export default function buildUsStreetInputData(lookup: Record): Record { // Apply default match strategy and candidates logic per Go SDK behavior let effectiveMatch = lookup.match; let effectiveCandidates = lookup.maxCandidates; @@ -28,4 +30,4 @@ module.exports = (lookup) => { }); return buildInputData(effectiveLookup, keyTranslationFormat); -}; +} diff --git a/tests/fixtures/MockSleeper.js b/tests/fixtures/MockSleeper.ts similarity index 50% rename from tests/fixtures/MockSleeper.js rename to tests/fixtures/MockSleeper.ts index 3b0ba5f..221fed5 100644 --- a/tests/fixtures/MockSleeper.js +++ b/tests/fixtures/MockSleeper.ts @@ -1,10 +1,11 @@ -class MockSleeper { +export default class MockSleeper { + sleepDurations: number[]; + constructor() { this.sleepDurations = []; } - sleep(ms) { + + sleep(ms: number) { this.sleepDurations.push(ms); } } - -module.exports = MockSleeper; diff --git a/tests/international_address_autocomplete/test_Client.js b/tests/international_address_autocomplete/test_Client.ts similarity index 80% rename from tests/international_address_autocomplete/test_Client.js rename to tests/international_address_autocomplete/test_Client.ts index a4c50fe..20a86ab 100644 --- a/tests/international_address_autocomplete/test_Client.js +++ b/tests/international_address_autocomplete/test_Client.ts @@ -1,11 +1,9 @@ -const chai = require("chai"); -const expect = chai.expect; -const Client = require("../../src/international_address_autocomplete/Client"); -const Lookup = require("../../src/international_address_autocomplete/Lookup"); -const Suggestion = require("../../src/international_address_autocomplete/Suggestion"); -const errors = require("../../src/Errors"); -const MockSender = require("../fixtures/mock_senders").MockSender; -const MockSenderWithResponse = require("../fixtures/mock_senders").MockSenderWithResponse; +import { expect } from "chai"; +import Client from "../../src/international_address_autocomplete/Client.js"; +import Lookup from "../../src/international_address_autocomplete/Lookup.js"; +import Suggestion from "../../src/international_address_autocomplete/Suggestion.js"; +import errors from "../../src/Errors.js"; +import { MockSender, MockSenderWithResponse } from "../fixtures/mock_senders.js"; describe("An International Address Autocomplete Client", function () { it("correctly builds parameter", function () { diff --git a/tests/international_address_autocomplete/test_Lookup.js b/tests/international_address_autocomplete/test_Lookup.ts similarity index 92% rename from tests/international_address_autocomplete/test_Lookup.js rename to tests/international_address_autocomplete/test_Lookup.ts index d0bc05c..54a64a9 100644 --- a/tests/international_address_autocomplete/test_Lookup.js +++ b/tests/international_address_autocomplete/test_Lookup.ts @@ -1,6 +1,5 @@ -const chai = require("chai"); -const expect = chai.expect; -const Lookup = require("../../src/international_address_autocomplete/Lookup"); +import { expect } from "chai"; +import Lookup from "../../src/international_address_autocomplete/Lookup.js"; describe("An International Address Autocomplete lookup", function () { it("Can be newed up with a prefix", function () { diff --git a/tests/international_postal_code/test_Lookup.js b/tests/international_postal_code/test_Lookup.ts similarity index 85% rename from tests/international_postal_code/test_Lookup.js rename to tests/international_postal_code/test_Lookup.ts index 94367db..2314109 100644 --- a/tests/international_postal_code/test_Lookup.js +++ b/tests/international_postal_code/test_Lookup.ts @@ -1,6 +1,5 @@ -const chai = require("chai"); -const expect = chai.expect; -const Lookup = require("../../src/international_postal_code/Lookup"); +import { expect } from "chai"; +import Lookup from "../../src/international_postal_code/Lookup.js"; describe("An International Postal Code lookup", function () { it("correctly populates fields.", function () { diff --git a/tests/international_postal_code/test_Result.js b/tests/international_postal_code/test_Result.ts similarity index 93% rename from tests/international_postal_code/test_Result.js rename to tests/international_postal_code/test_Result.ts index bc873de..3f1226c 100644 --- a/tests/international_postal_code/test_Result.js +++ b/tests/international_postal_code/test_Result.ts @@ -1,6 +1,5 @@ -const chai = require("chai"); -const expect = chai.expect; -const Result = require("../../src/international_postal_code/Result"); +import { expect } from "chai"; +import Result from "../../src/international_postal_code/Result.js"; describe("An International Postal Code result", function () { it("populates with the appropriate fields.", function () { diff --git a/tests/international_street/test_Candidate.js b/tests/international_street/test_Candidate.ts similarity index 98% rename from tests/international_street/test_Candidate.js rename to tests/international_street/test_Candidate.ts index 7e3b898..b550606 100644 --- a/tests/international_street/test_Candidate.js +++ b/tests/international_street/test_Candidate.ts @@ -1,6 +1,5 @@ -const chai = require("chai"); -const expect = chai.expect; -const Candidate = require("../../src/international_street/Candidate"); +import { expect } from "chai"; +import Candidate from "../../src/international_street/Candidate.js"; describe("An International match candidate", function () { it("populates with the appropriate fields.", function () { diff --git a/tests/international_street/test_Lookup.js b/tests/international_street/test_Lookup.ts similarity index 93% rename from tests/international_street/test_Lookup.js rename to tests/international_street/test_Lookup.ts index 178e771..5b9f9d0 100644 --- a/tests/international_street/test_Lookup.js +++ b/tests/international_street/test_Lookup.ts @@ -1,7 +1,6 @@ -const chai = require("chai"); -const expect = chai.expect; -const Lookup = require("../../src/international_street/Lookup"); -const errors = require("../../src/Errors"); +import { expect } from "chai"; +import Lookup from "../../src/international_street/Lookup.js"; +import errors from "../../src/Errors.js"; describe("An International Street lookup", function () { const messages = { @@ -95,13 +94,13 @@ describe("An International Street lookup", function () { expect(lookup2.ensureValidData()).to.equal(true); }); - function ensureValidationThrows(callback, message) { + function ensureValidationThrows(callback: any, message: any) { let expectedError = new errors.UnprocessableEntityError(message); try { callback(); expect(true).to.equal(false); - } catch (error) { + } catch (error: any) { expect(error.message).to.equal(expectedError.message); expect(error).to.be.an.instanceOf(errors.UnprocessableEntityError); } diff --git a/tests/test_Batch.js b/tests/test_Batch.ts similarity index 87% rename from tests/test_Batch.js rename to tests/test_Batch.ts index 3ecd33c..212ec3b 100644 --- a/tests/test_Batch.js +++ b/tests/test_Batch.ts @@ -1,11 +1,10 @@ -const chai = require("chai"); -const expect = chai.expect; -const errors = require("../src/Errors"); -const Batch = require("../src/Batch"); -const Lookup = require("../src/us_street/Lookup"); +import { expect } from "chai"; +import errors from "../src/Errors.js"; +import Batch from "../src/Batch.js"; +import Lookup from "../src/us_street/Lookup.js"; describe("A batch", function () { - let batch; + let batch: any; beforeEach(function () { batch = new Batch(); @@ -56,7 +55,7 @@ describe("A batch", function () { it("returns a lookup by input id.", function () { for (let i = 0; i < 100; i++) { let lookup = new Lookup(); - lookup.inputId = i; + lookup.inputId = i as any; batch.add(lookup); } diff --git a/tests/test_HttpSender.js b/tests/test_HttpSender.ts similarity index 86% rename from tests/test_HttpSender.js rename to tests/test_HttpSender.ts index f7eb222..cbfa971 100644 --- a/tests/test_HttpSender.js +++ b/tests/test_HttpSender.ts @@ -1,8 +1,7 @@ -const chai = require("chai"); -const expect = chai.expect; -const Request = require("../src/Request"); -const HttpSender = require("../src/HttpSender"); -const { buildSmartyResponse } = require("../src/util/buildSmartyResponse"); +import { expect } from "chai"; +import Request from "../src/Request.js"; +import HttpSender from "../src/HttpSender.js"; +import { buildSmartyResponse } from "../src/util/buildSmartyResponse.js"; describe("An Axios implementation of a HTTP sender", function () { it("adds a data payload to the HTTP request config.", function () { @@ -61,14 +60,12 @@ describe("An Axios implementation of a HTTP sender", function () { let request = new Request(""); let sender = new HttpSender(); let requestConfig = sender.buildRequestConfig(request); - let version = require("../package.json").version; expect(requestConfig.hasOwnProperty("headers")).to.equal(true); - expect(requestConfig.headers["Content-Type"]).to.equal("application/json; charset=utf-8"); + expect(requestConfig.headers!["Content-Type"]).to.equal("application/json; charset=utf-8"); }); it("has a response with the right status code.", function () { - let sender = new HttpSender(); let mockResponse = { status: 200, }; @@ -79,7 +76,6 @@ describe("An Axios implementation of a HTTP sender", function () { }); it("has a response with a payload.", function () { - let sender = new HttpSender(); let mockData = [1, 2, 3]; let mockResponse = { status: 200, diff --git a/tests/test_StatusCodeSender.js b/tests/test_StatusCodeSender.js deleted file mode 100644 index 06df7dc..0000000 --- a/tests/test_StatusCodeSender.js +++ /dev/null @@ -1,99 +0,0 @@ -const chai = require("chai"); -const expect = chai.expect; -const StatusCodeSender = require("../src/StatusCodeSender"); -const Response = require("../src/Response"); -const Request = require("../src/Request"); -const errors = require("../src/Errors"); - -describe("A status code sender", function () { - it("doesn't attach an error on a 200.", function () { - let mockSender = { - send: () => { - return new Promise((resolve, reject) => { - resolve(new Response(200)); - }); - }, - }; - - let statusCodeSender = new StatusCodeSender(mockSender); - let request = new Request(); - - return statusCodeSender.send(request).then((response) => { - expect(response.error === undefined).to.equal(true); - }); - }); - - it("gives a custom message for 400", function () { - const payload = { - errors: [{ message: "custom message" }], - }; - return expectedErrorWithPayloadMessage(400, payload); - }); - - it("returns an error message if payload is undefined", function () { - return expectedDefaultError(); - }); - - it("gives an Internal Server Error on a 500.", function () { - return expectedErrorForStatusCode(errors.InternalServerError, 500); - }); - - it("gives an Service Unavailable error on a 503.", function () { - return expectedErrorForStatusCode(errors.ServiceUnavailableError, 503); - }); - - it("gives an Gateway Timeout error on a 504.", function () { - return expectedErrorForStatusCode(errors.GatewayTimeoutError, 504); - }); -}); - -const expectedErrorWithPayloadMessage = (errorCode, payload) => { - let mockSender = generateMockSender(errorCode, payload); - let statusCodeSender = new StatusCodeSender(mockSender); - let request = new Request(); - - return statusCodeSender.send(request).then( - () => {}, - (error) => { - expect(error.error).to.be.an.instanceOf(errors.DefaultError); - expect(error.error.message).to.be.equal(payload.errors[0].message); - }, - ); -}; - -const expectedDefaultError = () => { - let mockSender = generateMockSender(400); - let statusCodeSender = new StatusCodeSender(mockSender); - let request = new Request(); - - return statusCodeSender.send(request).then( - () => {}, - (error) => { - expect(error.error).to.be.an.instanceOf(errors.DefaultError); - expect(error.error.message).to.be.equal("unexpected error"); - }, - ); -}; - -function expectedErrorForStatusCode(expectedError, errorCode) { - let mockSender = generateMockSender(errorCode); - let statusCodeSender = new StatusCodeSender(mockSender); - let request = new Request(); - - return statusCodeSender.send(request).then( - () => {}, - (error) => { - expect(error.error).to.be.an.instanceOf(expectedError); - }, - ); -} - -function generateMockSender(errorCode, payload) { - return { - send: () => { - return new Promise((resolve, reject) => { - reject(new Response(errorCode, payload)); - }); - }, - }; -} diff --git a/tests/us_autocomplete_pro/test_Client.js b/tests/us_autocomplete_pro/test_Client.ts similarity index 83% rename from tests/us_autocomplete_pro/test_Client.js rename to tests/us_autocomplete_pro/test_Client.ts index be7d43f..7c3c36a 100644 --- a/tests/us_autocomplete_pro/test_Client.js +++ b/tests/us_autocomplete_pro/test_Client.ts @@ -1,11 +1,9 @@ -const chai = require("chai"); -const expect = chai.expect; -const Client = require("../../src/us_autocomplete_pro/Client"); -const Lookup = require("../../src/us_autocomplete_pro/Lookup"); -const Suggestion = require("../../src/us_autocomplete_pro/Suggestion"); -const errors = require("../../src/Errors"); -const MockSender = require("../fixtures/mock_senders").MockSender; -const MockSenderWithResponse = require("../fixtures/mock_senders").MockSenderWithResponse; +import { expect } from "chai"; +import Client from "../../src/us_autocomplete_pro/Client.js"; +import Lookup from "../../src/us_autocomplete_pro/Lookup.js"; +import Suggestion from "../../src/us_autocomplete_pro/Suggestion.js"; +import errors from "../../src/Errors.js"; +import { MockSender, MockSenderWithResponse } from "../fixtures/mock_senders.js"; describe("A US Autocomplete Pro Client", function () { it("correctly builds parameters for a prefix only lookup.", function () { @@ -35,7 +33,7 @@ describe("A US Autocomplete Pro Client", function () { let lookup = new Lookup(); lookup.search = "1"; lookup.selected = "2"; - lookup.maxResults = "3"; + lookup.maxResults = "3" as any; lookup.includeOnlyCities = ["a,b", "c,d"]; lookup.includeOnlyStates = ["e", "f"]; lookup.includeOnlyZIPCodes = ["g", "h"]; @@ -43,7 +41,7 @@ describe("A US Autocomplete Pro Client", function () { lookup.preferCities = ["k,l", "m,n"]; lookup.preferStates = ["o", "p"]; lookup.preferZIPCodes = ["q", "r"]; - lookup.preferRatio = "s"; + lookup.preferRatio = "s" as any; lookup.preferGeolocation = "t"; lookup.source = "all"; @@ -89,9 +87,9 @@ describe("A US Autocomplete Pro Client", function () { let mockSender = new MockSenderWithResponse(mockExpectedPayload); let client = new Client(mockSender); let lookup = new Lookup("Please let this be easy to test."); - let expectedSuggestion = []; + let expectedSuggestion: any[] = []; - return client.send(lookup).then((response) => { + return client.send(lookup).then((_response) => { expect(lookup.result).to.deep.equal(expectedSuggestion); }); }); @@ -111,7 +109,7 @@ describe("A US Autocomplete Pro Client", function () { let lookup = new Lookup("Trevor the Vampire"); let expectedSuggestion = new Suggestion(responseData); - return client.send(lookup).then((response) => { + return client.send(lookup).then((_response) => { expect(lookup.result[0]).to.deep.equal(expectedSuggestion); }); }); diff --git a/tests/us_autocomplete_pro/test_Lookup.js b/tests/us_autocomplete_pro/test_Lookup.ts similarity index 66% rename from tests/us_autocomplete_pro/test_Lookup.js rename to tests/us_autocomplete_pro/test_Lookup.ts index 6c355bc..79dc27b 100644 --- a/tests/us_autocomplete_pro/test_Lookup.js +++ b/tests/us_autocomplete_pro/test_Lookup.ts @@ -1,6 +1,5 @@ -const chai = require("chai"); -const expect = chai.expect; -const Lookup = require("../../src/us_autocomplete_pro/Lookup"); +import { expect } from "chai"; +import Lookup from "../../src/us_autocomplete_pro/Lookup.js"; describe("A US Autocomplete Pro Lookup", function () { it("can be newed up with a prefix.", function () { diff --git a/tests/us_autocomplete_pro/test_Suggestion.js b/tests/us_autocomplete_pro/test_Suggestion.ts similarity index 81% rename from tests/us_autocomplete_pro/test_Suggestion.js rename to tests/us_autocomplete_pro/test_Suggestion.ts index 6770355..94c4723 100644 --- a/tests/us_autocomplete_pro/test_Suggestion.js +++ b/tests/us_autocomplete_pro/test_Suggestion.ts @@ -1,6 +1,5 @@ -const chai = require("chai"); -const expect = chai.expect; -const Suggestion = require("../../src/us_autocomplete_pro/Suggestion"); +import { expect } from "chai"; +import Suggestion from "../../src/us_autocomplete_pro/Suggestion.js"; describe("A US Autocomplete Pro Suggestion", function () { it("is initialized correctly with API response data.", function () { diff --git a/tests/us_enrichment/test_Client.js b/tests/us_enrichment/test_Client.ts similarity index 92% rename from tests/us_enrichment/test_Client.js rename to tests/us_enrichment/test_Client.ts index 987c442..9c7cb01 100644 --- a/tests/us_enrichment/test_Client.js +++ b/tests/us_enrichment/test_Client.ts @@ -1,11 +1,9 @@ -const chai = require("chai"); -const expect = chai.expect; -const Client = require("../../src/us_enrichment/Client"); -const Lookup = require("../../src/us_enrichment/Lookup"); -const errors = require("../../src/Errors"); -const MockSender = require("../fixtures/mock_senders").MockSender; -const MockSenderWithResponse = require("../fixtures/mock_senders").MockSenderWithResponse; -const { Response, FinancialResponse, GeoResponse } = require("../../src/us_enrichment/Response"); +import { expect } from "chai"; +import Client from "../../src/us_enrichment/Client.js"; +import Lookup from "../../src/us_enrichment/Lookup.js"; +import errors from "../../src/Errors.js"; +import { MockSender, MockSenderWithResponse } from "../fixtures/mock_senders.js"; +import { Response, FinancialResponse, GeoResponse } from "../../src/us_enrichment/Response.js"; describe("A US Enrichment Client", function () { it("composes principal url path properly", function () { @@ -308,7 +306,7 @@ describe("A US Enrichment Client", function () { let client = new Client(mockSender); let lookup = new Lookup("smartyKey"); - return client.sendPrincipal(lookup).then((response) => { + return client.sendPrincipal(lookup).then((_response) => { expect(lookup.response).to.deep.equal({}); }); }); @@ -318,7 +316,7 @@ describe("A US Enrichment Client", function () { let client = new Client(mockSender); let lookup = new Lookup("smartyKey"); - return client.sendFinancial(lookup).then((response) => { + return client.sendFinancial(lookup).then((_response) => { expect(lookup.response).to.deep.equal({}); }); }); @@ -328,7 +326,7 @@ describe("A US Enrichment Client", function () { let client = new Client(mockSender); let lookup = new Lookup("smartyKey"); - return client.sendGeo(lookup).then((response) => { + return client.sendGeo(lookup).then((_response) => { expect(lookup.response).to.deep.equal({}); }); }); @@ -338,7 +336,7 @@ describe("A US Enrichment Client", function () { let client = new Client(mockSender); let lookup = new Lookup("smartyKey"); - return client.sendSecondary(lookup).then((response) => { + return client.sendSecondary(lookup).then((_response) => { expect(lookup.response).to.deep.equal({}); }); }); @@ -348,7 +346,7 @@ describe("A US Enrichment Client", function () { let client = new Client(mockSender); let lookup = new Lookup("smartyKey"); - return client.sendSecondaryCount(lookup).then((response) => { + return client.sendSecondaryCount(lookup).then((_response) => { expect(lookup.response).to.deep.equal({}); }); }); @@ -368,7 +366,7 @@ describe("A US Enrichment Client", function () { let client = new Client(mockSender); let lookup = new Lookup("smartyKey"); - return client.sendPrincipal(lookup).then((response) => { + return client.sendPrincipal(lookup).then((_response) => { expect(lookup.response).to.deep.equal(mockResponse); }); }); @@ -388,7 +386,7 @@ describe("A US Enrichment Client", function () { let client = new Client(mockSender); let lookup = new Lookup("smartyKey"); - return client.sendFinancial(lookup).then((response) => { + return client.sendFinancial(lookup).then((_response) => { expect(lookup.response).to.deep.equal(mockResponse); }); }); @@ -408,7 +406,7 @@ describe("A US Enrichment Client", function () { let client = new Client(mockSender); let lookup = new Lookup("smartyKey"); - return client.sendGeo(lookup).then((response) => { + return client.sendGeo(lookup).then((_response) => { expect(lookup.response).to.deep.equal(mockResponse); }); }); @@ -428,7 +426,7 @@ describe("A US Enrichment Client", function () { let client = new Client(mockSender); let lookup = new Lookup("smartyKey"); - return client.sendSecondary(lookup).then((response) => { + return client.sendSecondary(lookup).then((_response) => { expect(lookup.response).to.deep.equal(mockResponse); }); }); @@ -448,7 +446,7 @@ describe("A US Enrichment Client", function () { let client = new Client(mockSender); let lookup = new Lookup("smartyKey"); - return client.sendSecondaryCount(lookup).then((response) => { + return client.sendSecondaryCount(lookup).then((_response) => { expect(lookup.response).to.deep.equal(mockResponse); }); }); diff --git a/tests/us_enrichment/test_Lookup.js b/tests/us_enrichment/test_Lookup.ts similarity index 87% rename from tests/us_enrichment/test_Lookup.js rename to tests/us_enrichment/test_Lookup.ts index 6f860ce..2188d1e 100644 --- a/tests/us_enrichment/test_Lookup.js +++ b/tests/us_enrichment/test_Lookup.ts @@ -1,6 +1,5 @@ -const chai = require("chai"); -const expect = chai.expect; -const Lookup = require("../../src/us_enrichment/Lookup"); +import { expect } from "chai"; +import Lookup from "../../src/us_enrichment/Lookup.js"; describe("A US Enrichment Lookup", function () { it("can be newed up with all basic fields.", function () { diff --git a/tests/us_extract/test_Address.js b/tests/us_extract/test_Address.ts similarity index 90% rename from tests/us_extract/test_Address.js rename to tests/us_extract/test_Address.ts index 0acaa0e..adfe84f 100644 --- a/tests/us_extract/test_Address.js +++ b/tests/us_extract/test_Address.ts @@ -1,7 +1,6 @@ -const chai = require("chai"); -const expect = chai.expect; -const Address = require("../../src/us_extract/Address"); -const Candidate = require("../../src/us_street/Candidate"); +import { expect } from "chai"; +import Address from "../../src/us_extract/Address.js"; +import Candidate from "../../src/us_street/Candidate.js"; describe("A US Extract Address", function () { it("populates fields correctly.", function () { diff --git a/tests/us_extract/test_Client.js b/tests/us_extract/test_Client.ts similarity index 87% rename from tests/us_extract/test_Client.js rename to tests/us_extract/test_Client.ts index 045bdfc..cf893fb 100644 --- a/tests/us_extract/test_Client.js +++ b/tests/us_extract/test_Client.ts @@ -1,11 +1,9 @@ -const chai = require("chai"); -const expect = chai.expect; -const Client = require("../../src/us_extract/Client"); -const Lookup = require("../../src/us_extract/Lookup"); -const Result = require("../../src/us_extract/Result"); -const MockSender = require("../fixtures/mock_senders").MockSender; -const MockSenderWithResponse = require("../fixtures/mock_senders").MockSenderWithResponse; -const errors = require("../../src/Errors"); +import { expect } from "chai"; +import Client from "../../src/us_extract/Client.js"; +import Lookup from "../../src/us_extract/Lookup.js"; +import Result from "../../src/us_extract/Result.js"; +import { MockSender, MockSenderWithResponse } from "../fixtures/mock_senders.js"; +import errors from "../../src/Errors.js"; describe("A US Extract Client", function () { it("throws an error if sending without a lookup.", function () { @@ -44,9 +42,9 @@ describe("A US Extract Client", function () { let client = new Client(mockSender); const mockText = "Picard is coming back. All power to the engines."; let lookup = new Lookup(mockText); - lookup.html = 1; - lookup.aggressive = 2; - lookup.addressesHaveLineBreaks = 3; + lookup.html = 1 as any; + lookup.aggressive = 2 as any; + lookup.addressesHaveLineBreaks = 3 as any; lookup.addressesPerLine = 4; let expectedParams = { @@ -143,7 +141,7 @@ describe("A US Extract Client", function () { let lookup = new Lookup("Sometimes when you're testing this field doesn't matter too much."); let expectedResult = new Result(responseData); - return client.send(lookup).then((response) => { + return client.send(lookup).then((_response) => { expect(lookup.result).to.deep.equal(expectedResult); }); }); diff --git a/tests/us_extract/test_Lookup.js b/tests/us_extract/test_Lookup.ts similarity index 81% rename from tests/us_extract/test_Lookup.js rename to tests/us_extract/test_Lookup.ts index 2078f8b..39a0682 100644 --- a/tests/us_extract/test_Lookup.js +++ b/tests/us_extract/test_Lookup.ts @@ -1,6 +1,5 @@ -const chai = require("chai"); -const expect = chai.expect; -const Lookup = require("../../src/us_extract/Lookup"); +import { expect } from "chai"; +import Lookup from "../../src/us_extract/Lookup.js"; describe("A US Extract Lookup", function () { it("correctly populates fields.", function () { diff --git a/tests/us_extract/test_Result.js b/tests/us_extract/test_Result.ts similarity index 83% rename from tests/us_extract/test_Result.js rename to tests/us_extract/test_Result.ts index ee543fa..c7a88aa 100644 --- a/tests/us_extract/test_Result.js +++ b/tests/us_extract/test_Result.ts @@ -1,7 +1,6 @@ -const chai = require("chai"); -const expect = chai.expect; -const Result = require("../../src/us_extract/Result"); -const Address = require("../../src/us_extract/Address"); +import { expect } from "chai"; +import Result from "../../src/us_extract/Result.js"; +import Address from "../../src/us_extract/Address.js"; describe("A US Extract Result", function () { it("correctly populates fields.", function () { diff --git a/tests/us_reverse_geo/test_Lookup.js b/tests/us_reverse_geo/test_Lookup.ts similarity index 76% rename from tests/us_reverse_geo/test_Lookup.js rename to tests/us_reverse_geo/test_Lookup.ts index e60d512..d5d6f09 100644 --- a/tests/us_reverse_geo/test_Lookup.js +++ b/tests/us_reverse_geo/test_Lookup.ts @@ -1,6 +1,5 @@ -const chai = require("chai"); -const expect = chai.expect; -const Lookup = require("../../src/us_reverse_geo/Lookup"); +import { expect } from "chai"; +import Lookup from "../../src/us_reverse_geo/Lookup.js"; describe("A US Reverse Geo lookup", function () { it("correctly populates fields.", function () { diff --git a/tests/us_street/test_Candidate.js b/tests/us_street/test_Candidate.ts similarity index 98% rename from tests/us_street/test_Candidate.js rename to tests/us_street/test_Candidate.ts index 2bfd515..d8d99de 100644 --- a/tests/us_street/test_Candidate.js +++ b/tests/us_street/test_Candidate.ts @@ -1,6 +1,5 @@ -const chai = require("chai"); -const expect = chai.expect; -const Candidate = require("../../src/us_street/Candidate"); +import { expect } from "chai"; +import Candidate from "../../src/us_street/Candidate.js"; describe("A match candidate", function () { it("has populated fields.", function () { diff --git a/tests/us_street/test_Lookup.js b/tests/us_street/test_Lookup.ts similarity index 77% rename from tests/us_street/test_Lookup.js rename to tests/us_street/test_Lookup.ts index bcc28ed..92ebb06 100644 --- a/tests/us_street/test_Lookup.js +++ b/tests/us_street/test_Lookup.ts @@ -1,10 +1,23 @@ -const chai = require("chai"); -const expect = chai.expect; -const Lookup = require("../../src/us_street/Lookup"); +import { expect } from "chai"; +import Lookup from "../../src/us_street/Lookup.js"; describe("A US Street lookup", function () { it("correctly populates fields.", function () { - const lookup = new Lookup("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m"); + const lookup = new Lookup( + "a", + "b", + "c", + "d", + "e", + "f", + "g", + "h", + "i", + "j", + "k" as any, + "l", + "m", + ); expect(lookup.street).to.equal("a"); expect(lookup.street2).to.equal("b"); diff --git a/tests/us_zipcode/test_Result.js b/tests/us_zipcode/test_Result.ts similarity index 95% rename from tests/us_zipcode/test_Result.js rename to tests/us_zipcode/test_Result.ts index 8f20c65..e0a1c77 100644 --- a/tests/us_zipcode/test_Result.js +++ b/tests/us_zipcode/test_Result.ts @@ -1,6 +1,5 @@ -const chai = require("chai"); -const expect = chai.expect; -const Result = require("../../src/us_zipcode/Result"); +import { expect } from "chai"; +import Result from "../../src/us_zipcode/Result.js"; describe("A US Zipcode result", function () { it("populates accurately on a valid lookup.", function () { diff --git a/tsconfig.json b/tsconfig.json index b614533..8aeb2fd 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -7,10 +7,8 @@ "paths": { "@/*": ["./*"] }, - "allowJs": true, "alwaysStrict": true, "exactOptionalPropertyTypes": true, - "noPropertyAccessFromIndexSignature": true, "noImplicitAny": true, "noImplicitReturns": true, "noImplicitOverride": true, From c023e87f34cf6d513ff6ce79a679d734793cc182 Mon Sep 17 00:00:00 2001 From: Ryan Cox Date: Mon, 2 Mar 2026 14:35:34 -0700 Subject: [PATCH 18/29] Type Lookup result fields and narrow customParameters from any to string MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - us_street/Lookup.result: any[] → Candidate[] - us_zipcode/Lookup.result: any[] → Result[] - us_autocomplete_pro/Lookup.result: any[] → Suggestion[] - international_street/Lookup.result: any[] → Candidate[] - international_address_autocomplete/Lookup.result: any[] → Suggestion[] - international_postal_code/Lookup.result: any[] → Result[] - us_extract/Lookup.result: Record → Result (with proper init) - us_enrichment/Lookup.response: Record → Record - All customParameters: Record → Record - All addCustomParameter value params: any → string --- src/InputData.ts | 2 +- src/international_address_autocomplete/Lookup.ts | 8 +++++--- src/international_postal_code/Lookup.ts | 8 +++++--- src/international_street/Lookup.ts | 7 ++++--- src/us_autocomplete_pro/Lookup.ts | 8 +++++--- src/us_enrichment/Lookup.ts | 6 +++--- src/us_extract/Lookup.ts | 13 ++++++------- src/us_reverse_geo/Lookup.ts | 4 ++-- src/us_street/Lookup.ts | 8 +++++--- src/us_zipcode/Lookup.ts | 8 +++++--- 10 files changed, 41 insertions(+), 31 deletions(-) diff --git a/src/InputData.ts b/src/InputData.ts index 666cbc9..471240b 100644 --- a/src/InputData.ts +++ b/src/InputData.ts @@ -12,7 +12,7 @@ export default class InputData { this.data[apiField] = this.formatData(this.lookup[lookupField]); } - addCustomParameter(key: string, value: any): void { + addCustomParameter(key: string, value: string): void { this.data[key] = value; } diff --git a/src/international_address_autocomplete/Lookup.ts b/src/international_address_autocomplete/Lookup.ts index 0bc19f4..d157817 100644 --- a/src/international_address_autocomplete/Lookup.ts +++ b/src/international_address_autocomplete/Lookup.ts @@ -1,12 +1,14 @@ +import Suggestion from "./Suggestion.js"; + export default class Lookup { - result: any[]; + result: Suggestion[]; search: string | undefined; addressId: string | undefined; country: string | undefined; maxResults: number; includeOnlyLocality: string | undefined; includeOnlyPostalCode: string | undefined; - customParameters: Record; + customParameters: Record; constructor({ search, @@ -34,7 +36,7 @@ export default class Lookup { this.customParameters = {}; } - addCustomParameter(key: string, value: any): void { + addCustomParameter(key: string, value: string): void { this.customParameters[key] = value; } } diff --git a/src/international_postal_code/Lookup.ts b/src/international_postal_code/Lookup.ts index bd0d3c5..8bb1edb 100644 --- a/src/international_postal_code/Lookup.ts +++ b/src/international_postal_code/Lookup.ts @@ -1,11 +1,13 @@ +import Result from "./Result.js"; + export default class Lookup { inputId: string | undefined; country: string | undefined; postalCode: string | undefined; administrativeArea: string | undefined; locality: string | undefined; - result: any[]; - customParameters: Record; + result: Result[]; + customParameters: Record; constructor( country?: string, @@ -23,7 +25,7 @@ export default class Lookup { this.customParameters = {}; } - addCustomParameter(key: string, value: any): void { + addCustomParameter(key: string, value: string): void { this.customParameters[key] = value; } } diff --git a/src/international_street/Lookup.ts b/src/international_street/Lookup.ts index 0445160..e32ae29 100644 --- a/src/international_street/Lookup.ts +++ b/src/international_street/Lookup.ts @@ -1,3 +1,4 @@ +import Candidate from "./Candidate.js"; import { UnprocessableEntityError } from "../Errors.js"; const messages = { @@ -23,7 +24,7 @@ function fieldIsSet(field: string | undefined): boolean { } export default class Lookup { - result: any[]; + result: Candidate[]; country: string | undefined; freeform: string | undefined; address1: string | undefined; @@ -37,7 +38,7 @@ export default class Lookup { geocode: string | undefined; language: string | undefined; inputId: string | undefined; - customParameters: Record; + customParameters: Record; constructor(country?: string, freeform?: string) { this.result = []; @@ -61,7 +62,7 @@ export default class Lookup { this.customParameters = {}; } - addCustomParameter(key: string, value: any): void { + addCustomParameter(key: string, value: string): void { this.customParameters[key] = value; } diff --git a/src/us_autocomplete_pro/Lookup.ts b/src/us_autocomplete_pro/Lookup.ts index c914e1d..53a4e8f 100644 --- a/src/us_autocomplete_pro/Lookup.ts +++ b/src/us_autocomplete_pro/Lookup.ts @@ -1,5 +1,7 @@ +import Suggestion from "./Suggestion.js"; + export default class Lookup { - result: any[]; + result: Suggestion[]; search: string | undefined; selected: string | undefined; maxResults: number | undefined; @@ -13,7 +15,7 @@ export default class Lookup { preferRatio: number | undefined; preferGeolocation: string | undefined; source: string | undefined; - customParameters: Record; + customParameters: Record; constructor(search?: string) { this.result = []; @@ -34,7 +36,7 @@ export default class Lookup { this.customParameters = {}; } - addCustomParameter(key: string, value: any): void { + addCustomParameter(key: string, value: string): void { this.customParameters[key] = value; } } diff --git a/src/us_enrichment/Lookup.ts b/src/us_enrichment/Lookup.ts index 27c30ee..33a19e5 100644 --- a/src/us_enrichment/Lookup.ts +++ b/src/us_enrichment/Lookup.ts @@ -5,8 +5,8 @@ export default class Lookup { dataset: string | undefined; dataSubset: string | undefined; features: string | undefined; - response: Record; - customParameters: Record; + response: Record; + customParameters: Record; constructor( smartyKey?: string, @@ -26,7 +26,7 @@ export default class Lookup { this.customParameters = {}; } - addCustomParameter(key: string, value: any): void { + addCustomParameter(key: string, value: string): void { this.customParameters[key] = value; } } diff --git a/src/us_extract/Lookup.ts b/src/us_extract/Lookup.ts index 6d9d45e..bb9d1ce 100644 --- a/src/us_extract/Lookup.ts +++ b/src/us_extract/Lookup.ts @@ -1,17 +1,16 @@ +import Result from "./Result.js"; + export default class Lookup { - result: Record; + result: Result; text: string; html: boolean | undefined; aggressive: boolean | undefined; addressesHaveLineBreaks: boolean | undefined; addressesPerLine: number | undefined; - customParameters: Record; + customParameters: Record; constructor(text: string) { - this.result = { - meta: {}, - addresses: [], - }; + this.result = new Result({ meta: {}, addresses: [] }); this.text = text; this.html = undefined; this.aggressive = undefined; @@ -20,7 +19,7 @@ export default class Lookup { this.customParameters = {}; } - addCustomParameter(key: string, value: any): void { + addCustomParameter(key: string, value: string): void { this.customParameters[key] = value; } } diff --git a/src/us_reverse_geo/Lookup.ts b/src/us_reverse_geo/Lookup.ts index 92a4342..53fb25c 100644 --- a/src/us_reverse_geo/Lookup.ts +++ b/src/us_reverse_geo/Lookup.ts @@ -5,7 +5,7 @@ export default class Lookup { longitude: string; source: string; response: Response; - customParameters: Record; + customParameters: Record; constructor(latitude: number, longitude: number, source: string = "") { this.latitude = latitude.toFixed(8); @@ -15,7 +15,7 @@ export default class Lookup { this.customParameters = {}; } - addCustomParameter(key: string, value: any): void { + addCustomParameter(key: string, value: string): void { this.customParameters[key] = value; } } diff --git a/src/us_street/Lookup.ts b/src/us_street/Lookup.ts index 08bec1f..9f86576 100644 --- a/src/us_street/Lookup.ts +++ b/src/us_street/Lookup.ts @@ -1,3 +1,5 @@ +import Candidate from "./Candidate.js"; + export default class Lookup { street: string | undefined; street2: string | undefined; @@ -13,8 +15,8 @@ export default class Lookup { inputId: string | undefined; format: string | undefined; countySource: string | undefined; - result: any[]; - customParameters: Record; + result: Candidate[]; + customParameters: Record; constructor( street?: string, @@ -50,7 +52,7 @@ export default class Lookup { this.customParameters = {}; } - addCustomParameter(key: string, value: any): void { + addCustomParameter(key: string, value: string): void { this.customParameters[key] = value; } } diff --git a/src/us_zipcode/Lookup.ts b/src/us_zipcode/Lookup.ts index aa343ec..abe036e 100644 --- a/src/us_zipcode/Lookup.ts +++ b/src/us_zipcode/Lookup.ts @@ -1,10 +1,12 @@ +import Result from "./Result.js"; + export default class Lookup { city: string | undefined; state: string | undefined; zipCode: string | undefined; inputId: string | undefined; - result: any[]; - customParameters: Record; + result: Result[]; + customParameters: Record; constructor(city?: string, state?: string, zipCode?: string, inputId?: string) { this.city = city; @@ -15,7 +17,7 @@ export default class Lookup { this.customParameters = {}; } - addCustomParameter(key: string, value: any): void { + addCustomParameter(key: string, value: string): void { this.customParameters[key] = value; } } From a9c10a5a77af8134ae3d4054b2b5d4b0fc885a9a Mon Sep 17 00:00:00 2001 From: Ryan Cox Date: Mon, 2 Mar 2026 14:38:00 -0700 Subject: [PATCH 19/29] Add exported interfaces for Candidate/Result/Suggestion output fields Replace Record with typed interfaces on all output fields that SDK consumers access: - us_street/Candidate: UsStreetComponents, UsStreetMetadata, UsStreetAnalysis, AnalysisComponents - international_street/Candidate: IntlStreetComponents, IntlStreetAnalysis, IntlChanges, IntlChangesComponents, IntlStreetMetadata - us_zipcode/Result: CityEntry, ZipcodeEntry, AlternateCounty - us_reverse_geo/Result: ReverseGeoAddress, ReverseGeoCoordinate - us_extract/Result: ExtractMeta Constructor responseData params remain Record (JSON boundary). --- src/international_street/Candidate.ts | 150 ++++++++++++++++++++++++-- src/us_extract/Result.ts | 11 +- src/us_reverse_geo/Result.ts | 23 +++- src/us_street/Candidate.ts | 90 ++++++++++++++-- src/us_zipcode/Result.ts | 54 +++++++--- 5 files changed, 296 insertions(+), 32 deletions(-) diff --git a/src/international_street/Candidate.ts b/src/international_street/Candidate.ts index ed29473..43f3151 100644 --- a/src/international_street/Candidate.ts +++ b/src/international_street/Candidate.ts @@ -1,3 +1,137 @@ +export interface IntlStreetComponents { + countryIso3: string | undefined; + superAdministrativeArea: string | undefined; + administrativeArea: string | undefined; + administrativeAreaIso2: string | undefined; + administrativeAreaShort: string | undefined; + administrativeAreaLong: string | undefined; + subAdministrativeArea: string | undefined; + dependentLocality: string | undefined; + dependentLocalityName: string | undefined; + doubleDependentLocality: string | undefined; + locality: string | undefined; + postalCode: string | undefined; + postalCodeShort: string | undefined; + postalCodeExtra: string | undefined; + premise: string | undefined; + premiseExtra: string | undefined; + premisePrefixNumber: string | undefined; + premiseNumber: string | undefined; + premiseType: string | undefined; + thoroughfare: string | undefined; + thoroughfarePredirection: string | undefined; + thoroughfarePostdirection: string | undefined; + thoroughfareName: string | undefined; + thoroughfareTrailingType: string | undefined; + thoroughfareType: string | undefined; + dependentThoroughfare: string | undefined; + dependentThoroughfarePredirection: string | undefined; + dependentThoroughfarePostdirection: string | undefined; + dependentThoroughfareName: string | undefined; + dependentThoroughfareTrailingType: string | undefined; + dependentThoroughfareType: string | undefined; + building: string | undefined; + buildingLeadingType: string | undefined; + buildingName: string | undefined; + buildingTrailingType: string | undefined; + subBuildingType: string | undefined; + subBuildingNumber: string | undefined; + subBuildingName: string | undefined; + subBuilding: string | undefined; + levelType: string | undefined; + levelNumber: string | undefined; + postBox: string | undefined; + postBoxType: string | undefined; + postBoxNumber: string | undefined; + additionalContent: string | undefined; + deliveryInstallation: string | undefined; + deliveryInstallationType: string | undefined; + deliveryInstallationQualifierName: string | undefined; + route: string | undefined; + routeNumber: string | undefined; + routeType: string | undefined; +} + +export interface IntlChangesComponents { + countryIso3: string | undefined; + superAdministrativeArea: string | undefined; + administrativeArea: string | undefined; + administrativeAreaIso2: string | undefined; + administrativeAreaShort: string | undefined; + administrativeAreaLong: string | undefined; + subAdministrativeArea: string | undefined; + dependentLocality: string | undefined; + dependentLocalityName: string | undefined; + doubleDependentLocality: string | undefined; + locality: string | undefined; + postalCode: string | undefined; + postalCodeShort: string | undefined; + postalCodeExtra: string | undefined; + premise: string | undefined; + premiseExtra: string | undefined; + premisePrefixNumber: string | undefined; + premiseNumber: string | undefined; + premiseType: string | undefined; + thoroughfare: string | undefined; + thoroughfarePredirection: string | undefined; + thoroughfarePostdirection: string | undefined; + thoroughfareName: string | undefined; + thoroughfareTrailingType: string | undefined; + thoroughfareType: string | undefined; + dependentThoroughfare: string | undefined; + dependentThoroughfarePredirection: string | undefined; + dependentThoroughfarePostdirection: string | undefined; + dependentThoroughfareName: string | undefined; + dependentThoroughfareTrailingType: string | undefined; + dependentThoroughfareType: string | undefined; + building: string | undefined; + buildingLeadingType: string | undefined; + buildingName: string | undefined; + buildingTrailingType: string | undefined; + subBuildingType: string | undefined; + subBuildingNumber: string | undefined; + subBuildingName: string | undefined; + subBuilding: string | undefined; + levelType: string | undefined; + levelNumber: string | undefined; + postBox: string | undefined; + postBoxType: string | undefined; + postBoxNumber: string | undefined; +} + +export interface IntlChanges { + organization: string | undefined; + address1: string | undefined; + address2: string | undefined; + address3: string | undefined; + address4: string | undefined; + address5: string | undefined; + address6: string | undefined; + address7: string | undefined; + address8: string | undefined; + address9: string | undefined; + address10: string | undefined; + address11: string | undefined; + address12: string | undefined; + components: IntlChangesComponents; +} + +export interface IntlStreetAnalysis { + verificationStatus: string | undefined; + addressPrecision: string | undefined; + maxAddressPrecision: string | undefined; + changes: IntlChanges; +} + +export interface IntlStreetMetadata { + latitude: number | undefined; + longitude: number | undefined; + geocodePrecision: string | undefined; + maxGeocodePrecision: string | undefined; + addressFormat: string | undefined; + occupantUse: string | undefined; +} + export default class Candidate { organization: string; address1: string; @@ -12,9 +146,9 @@ export default class Candidate { address10: string; address11: string; address12: string; - components: Record; - analysis: Record; - metadata: Record; + components: IntlStreetComponents; + analysis: IntlStreetAnalysis; + metadata: IntlStreetMetadata; constructor(responseData: Record) { this.organization = responseData.organization; @@ -31,7 +165,7 @@ export default class Candidate { this.address11 = responseData.address11; this.address12 = responseData.address12; - this.components = {}; + this.components = {} as IntlStreetComponents; if (responseData.components !== undefined) { this.components.countryIso3 = responseData.components.country_iso_3; this.components.superAdministrativeArea = responseData.components.super_administrative_area; @@ -93,13 +227,13 @@ export default class Candidate { this.components.routeType = responseData.components.route_type; } - this.analysis = {}; + this.analysis = {} as IntlStreetAnalysis; if (responseData.analysis !== undefined) { this.analysis.verificationStatus = responseData.analysis.verification_status; this.analysis.addressPrecision = responseData.analysis.address_precision; this.analysis.maxAddressPrecision = responseData.analysis.max_address_precision; - this.analysis.changes = {}; + this.analysis.changes = {} as IntlChanges; if (responseData.analysis.changes !== undefined) { this.analysis.changes.organization = responseData.analysis.changes.organization; this.analysis.changes.address1 = responseData.analysis.changes.address1; @@ -115,7 +249,7 @@ export default class Candidate { this.analysis.changes.address11 = responseData.analysis.changes.address11; this.analysis.changes.address12 = responseData.analysis.changes.address12; - this.analysis.changes.components = {}; + this.analysis.changes.components = {} as IntlChangesComponents; if (responseData.analysis.changes.components !== undefined) { this.analysis.changes.components.countryIso3 = responseData.analysis.changes.components.country_iso_3; @@ -210,7 +344,7 @@ export default class Candidate { } } - this.metadata = {}; + this.metadata = {} as IntlStreetMetadata; if (responseData.metadata !== undefined) { this.metadata.latitude = responseData.metadata.latitude; this.metadata.longitude = responseData.metadata.longitude; diff --git a/src/us_extract/Result.ts b/src/us_extract/Result.ts index 7c43d08..0571e85 100644 --- a/src/us_extract/Result.ts +++ b/src/us_extract/Result.ts @@ -1,7 +1,16 @@ import Address from "./Address.js"; +export interface ExtractMeta { + lines: number | undefined; + unicode: boolean | undefined; + addressCount: number | undefined; + verifiedCount: number | undefined; + bytes: number | undefined; + characterCount: number | undefined; +} + export default class Result { - meta: Record; + meta: ExtractMeta; addresses: Address[]; constructor({ diff --git a/src/us_reverse_geo/Result.ts b/src/us_reverse_geo/Result.ts index 9367d21..3cb9452 100644 --- a/src/us_reverse_geo/Result.ts +++ b/src/us_reverse_geo/Result.ts @@ -1,12 +1,27 @@ +export interface ReverseGeoAddress { + street: string | undefined; + city: string | undefined; + stateAbbreviation: string | undefined; + zipcode: string | undefined; + source: string | undefined; +} + +export interface ReverseGeoCoordinate { + latitude: number | undefined; + longitude: number | undefined; + accuracy: string | undefined; + license: string | undefined; +} + export default class Result { distance: number; - address: Record; - coordinate: Record; + address: ReverseGeoAddress; + coordinate: ReverseGeoCoordinate; constructor(responseData: Record) { this.distance = responseData.distance; - this.address = {}; + this.address = {} as ReverseGeoAddress; if (responseData.address) { this.address.street = responseData.address.street; this.address.city = responseData.address.city; @@ -15,7 +30,7 @@ export default class Result { this.address.source = responseData.address.source; } - this.coordinate = {}; + this.coordinate = {} as ReverseGeoCoordinate; if (responseData.coordinate) { this.coordinate.latitude = responseData.coordinate.latitude; this.coordinate.longitude = responseData.coordinate.longitude; diff --git a/src/us_street/Candidate.ts b/src/us_street/Candidate.ts index 5d991cb..0f00982 100644 --- a/src/us_street/Candidate.ts +++ b/src/us_street/Candidate.ts @@ -1,3 +1,79 @@ +export interface UsStreetComponents { + urbanization: string | undefined; + primaryNumber: string | undefined; + streetName: string | undefined; + streetPredirection: string | undefined; + streetPostdirection: string | undefined; + streetSuffix: string | undefined; + secondaryNumber: string | undefined; + secondaryDesignator: string | undefined; + extraSecondaryNumber: string | undefined; + extraSecondaryDesignator: string | undefined; + pmbDesignator: string | undefined; + pmbNumber: string | undefined; + cityName: string | undefined; + defaultCityName: string | undefined; + state: string | undefined; + zipCode: string | undefined; + plus4Code: string | undefined; + deliveryPoint: string | undefined; + deliveryPointCheckDigit: string | undefined; +} + +export interface UsStreetMetadata { + recordType: string | undefined; + zipType: string | undefined; + countyFips: string | undefined; + countyName: string | undefined; + carrierRoute: string | undefined; + congressionalDistrict: string | undefined; + buildingDefaultIndicator: string | undefined; + rdi: string | undefined; + elotSequence: string | undefined; + elotSort: string | undefined; + latitude: number | undefined; + longitude: number | undefined; + coordinateLicense: string | undefined; + precision: string | undefined; + timeZone: string | undefined; + utcOffset: number | undefined; + obeysDst: boolean | undefined; + isEwsMatch: boolean | undefined; +} + +export interface AnalysisComponents { + primaryNumber: string | undefined; + streetPredirection: string | undefined; + streetName: string | undefined; + streetPostdirection: string | undefined; + streetSuffix: string | undefined; + secondaryNumber: string | undefined; + secondaryDesignator: string | undefined; + extraSecondaryNumber: string | undefined; + extraSecondaryDesignator: string | undefined; + cityName: string | undefined; + stateAbbreviation: string | undefined; + zipCode: string | undefined; + plus4Code: string | undefined; + urbanization: string | undefined; +} + +export interface UsStreetAnalysis { + dpvMatchCode: string | undefined; + dpvFootnotes: string | undefined; + cmra: string | undefined; + vacant: string | undefined; + noStat: string | undefined; + active: string | undefined; + isEwsMatch: boolean | undefined; + footnotes: string | undefined; + lacsLinkCode: string | undefined; + lacsLinkIndicator: string | undefined; + isSuiteLinkMatch: boolean | undefined; + enhancedMatch: string | undefined; + components: AnalysisComponents; +} + export default class Candidate { inputIndex: number; candidateIndex: number; @@ -7,9 +83,9 @@ export default class Candidate { lastLine: string; deliveryPointBarcode: string; smartyKey: string; - components: Record; - metadata: Record; - analysis: Record; + components: UsStreetComponents; + metadata: UsStreetMetadata; + analysis: UsStreetAnalysis; constructor(responseData: Record) { this.inputIndex = responseData.input_index; @@ -21,7 +97,7 @@ export default class Candidate { this.deliveryPointBarcode = responseData.delivery_point_barcode; this.smartyKey = responseData.smarty_key; - this.components = {}; + this.components = {} as UsStreetComponents; if (responseData.components !== undefined) { this.components.urbanization = responseData.components.urbanization; this.components.primaryNumber = responseData.components.primary_number; @@ -44,7 +120,7 @@ export default class Candidate { this.components.deliveryPointCheckDigit = responseData.components.delivery_point_check_digit; } - this.metadata = {}; + this.metadata = {} as UsStreetMetadata; if (responseData.metadata !== undefined) { this.metadata.recordType = responseData.metadata.record_type; this.metadata.zipType = responseData.metadata.zip_type; @@ -72,7 +148,7 @@ export default class Candidate { this.metadata.isEwsMatch = responseData.metadata.ews_match; } - this.analysis = {}; + this.analysis = {} as UsStreetAnalysis; if (responseData.analysis !== undefined) { this.analysis.dpvMatchCode = responseData.analysis.dpv_match_code; this.analysis.dpvFootnotes = responseData.analysis.dpv_footnotes; @@ -86,7 +162,7 @@ export default class Candidate { this.analysis.lacsLinkIndicator = responseData.analysis.lacslink_indicator; this.analysis.isSuiteLinkMatch = responseData.analysis.suitelink_match; this.analysis.enhancedMatch = responseData.analysis.enhanced_match; - this.analysis.components = {}; + this.analysis.components = {} as AnalysisComponents; if (responseData.analysis.components !== undefined) { this.analysis.components.primaryNumber = responseData.analysis.components.primary_number; this.analysis.components.streetPredirection = diff --git a/src/us_zipcode/Result.ts b/src/us_zipcode/Result.ts index e2ef783..0701785 100644 --- a/src/us_zipcode/Result.ts +++ b/src/us_zipcode/Result.ts @@ -1,10 +1,38 @@ +export interface CityEntry { + city: string; + stateAbbreviation: string; + state: string; + mailableCity: boolean; +} + +export interface AlternateCounty { + countyFips: string; + countyName: string; + stateAbbreviation: string; + state: string; +} + +export interface ZipcodeEntry { + zipcode: string; + zipcodeType: string; + defaultCity: string; + countyFips: string; + countyName: string; + latitude: number; + longitude: number; + precision: string; + stateAbbreviation: string; + state: string; + alternateCounties: AlternateCounty[]; +} + export default class Result { inputIndex: number; status: string | undefined; reason: string | undefined; valid: boolean; - cities: Record[]; - zipcodes: Record[]; + cities: CityEntry[]; + zipcodes: ZipcodeEntry[]; constructor(responseData: Record) { this.inputIndex = responseData.input_index; @@ -14,7 +42,7 @@ export default class Result { this.cities = !responseData.city_states ? [] - : responseData.city_states.map((city: Record) => { + : responseData.city_states.map((city: Record): CityEntry => { return { city: city.city, stateAbbreviation: city.state_abbreviation, @@ -25,7 +53,7 @@ export default class Result { this.zipcodes = !responseData.zipcodes ? [] - : responseData.zipcodes.map((zipcode: Record) => { + : responseData.zipcodes.map((zipcode: Record): ZipcodeEntry => { return { zipcode: zipcode.zipcode, zipcodeType: zipcode.zipcode_type, @@ -39,14 +67,16 @@ export default class Result { state: zipcode.state, alternateCounties: !zipcode.alternate_counties ? [] - : zipcode.alternate_counties.map((county: Record) => { - return { - countyFips: county.county_fips, - countyName: county.county_name, - stateAbbreviation: county.state_abbreviation, - state: county.state, - }; - }), + : zipcode.alternate_counties.map( + (county: Record): AlternateCounty => { + return { + countyFips: county.county_fips, + countyName: county.county_name, + stateAbbreviation: county.state_abbreviation, + state: county.state, + }; + }, + ), }; }); } From 862e19700a407e1496f8a53bdb7d4dae2a62c509 Mon Sep 17 00:00:00 2001 From: Ryan Cox Date: Mon, 2 Mar 2026 14:41:54 -0700 Subject: [PATCH 20/29] Type Batch with BaseLookup, narrow sendBatch and InputData signatures MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add BaseLookup interface to types.ts for Batch type safety - Batch.lookups: any[] → BaseLookup[], add/getByIndex/getByInputId typed - sendBatch: type response param as Response, generateRequestPayload returns Record[], keep justified any on Result constructor - InputData.data: Record → Record, formatData return typed as string | number - buildInputData/buildUsStreetInputData return types narrowed - Test casts for batch.getByIndex() → specific Lookup types --- src/Batch.ts | 9 +++++---- src/InputData.ts | 6 +++--- src/types.ts | 6 ++++++ src/util/buildInputData.ts | 9 +++++---- src/util/buildUsStreetInputData.ts | 2 +- src/util/sendBatch.ts | 18 +++++++++--------- tests/us_street/test_Client.ts | 11 ++++++----- tests/us_zipcode/test_Client.ts | 11 ++++++----- 8 files changed, 41 insertions(+), 31 deletions(-) diff --git a/src/Batch.ts b/src/Batch.ts index 7070dad..a64354a 100644 --- a/src/Batch.ts +++ b/src/Batch.ts @@ -1,13 +1,14 @@ import { BatchFullError } from "./Errors.js"; +import { BaseLookup } from "./types.js"; export default class Batch { - lookups: any[]; + lookups: BaseLookup[]; constructor() { this.lookups = []; } - add(lookup: any): void { + add(lookup: BaseLookup): void { if (this.lookupsHasRoomForLookup()) this.lookups.push(lookup); else throw new BatchFullError(); } @@ -21,11 +22,11 @@ export default class Batch { return this.lookups.length; } - getByIndex(index: number): any { + getByIndex(index: number): BaseLookup { return this.lookups[index]; } - getByInputId(inputId: any): any { + getByInputId(inputId: string | number): BaseLookup | undefined { return this.lookups.filter((lookup) => { return lookup.inputId === inputId; })[0]; diff --git a/src/InputData.ts b/src/InputData.ts index 471240b..38af92f 100644 --- a/src/InputData.ts +++ b/src/InputData.ts @@ -1,6 +1,6 @@ export default class InputData { lookup: Record; - data: Record; + data: Record; constructor(lookup: Record) { this.lookup = lookup; @@ -16,9 +16,9 @@ export default class InputData { this.data[key] = value; } - formatData(field: any): any { + formatData(field: string | number | string[]): string | number { if (Array.isArray(field)) return field.join(";"); - else return field; + return field; } lookupFieldIsPopulated(lookupField: string): boolean { diff --git a/src/types.ts b/src/types.ts index 98dabcf..a0accf0 100644 --- a/src/types.ts +++ b/src/types.ts @@ -25,6 +25,12 @@ export interface Signer { sign(request: Request): void; } +export interface BaseLookup { + inputId?: string | number | undefined; + customParameters: Record; + result: { inputIndex: number }[]; +} + export interface MockSenderInstance extends Sender { statusCodes: number[]; headers?: Record | undefined; diff --git a/src/util/buildInputData.ts b/src/util/buildInputData.ts index 1f67887..a9892bc 100644 --- a/src/util/buildInputData.ts +++ b/src/util/buildInputData.ts @@ -3,18 +3,19 @@ import InputData from "../InputData.js"; export default function buildInputData( lookup: Record, keyTranslationFormat: Record, -): Record { +): Record { const inputData = new InputData(lookup); - const hasCustomParameters = Object.keys(lookup.customParameters ?? {}).length > 0; + const customParameters: Record = lookup.customParameters ?? {}; + const hasCustomParameters = Object.keys(customParameters).length > 0; for (const key in keyTranslationFormat) { inputData.add(key, keyTranslationFormat[key]); } if (hasCustomParameters) { - for (const key in lookup.customParameters) { - inputData.addCustomParameter(key, lookup.customParameters[key]); + for (const key in customParameters) { + inputData.addCustomParameter(key, customParameters[key]); } } diff --git a/src/util/buildUsStreetInputData.ts b/src/util/buildUsStreetInputData.ts index b6772bc..fb670c8 100644 --- a/src/util/buildUsStreetInputData.ts +++ b/src/util/buildUsStreetInputData.ts @@ -3,7 +3,7 @@ import apiToSDKKeyMap from "./apiToSDKKeyMap.js"; const keyTranslationFormat = apiToSDKKeyMap.usStreet; -export default function buildUsStreetInputData(lookup: Record): Record { +export default function buildUsStreetInputData(lookup: Record): Record { // Apply default match strategy and candidates logic per Go SDK behavior let effectiveMatch = lookup.match; let effectiveCandidates = lookup.maxCandidates; diff --git a/src/util/sendBatch.ts b/src/util/sendBatch.ts index 1b1ef1a..352eac6 100644 --- a/src/util/sendBatch.ts +++ b/src/util/sendBatch.ts @@ -2,14 +2,14 @@ import Request from "../Request.js"; import { BatchEmptyError } from "../Errors.js"; import buildInputData from "./buildInputData.js"; import Batch from "../Batch.js"; -import { Sender } from "../types.js"; +import { Sender, Response } from "../types.js"; export default function sendBatch( batch: Batch, sender: Sender, - Result: new (data: Record) => any, + Result: new (data: any) => { inputIndex: number }, keyTranslationFormat: Record | null, - customBuildInputData?: (lookup: Record) => Record, + customBuildInputData?: (lookup: Record) => Record, ): Promise { if (batch.isEmpty()) throw new BatchEmptyError(); @@ -29,17 +29,17 @@ export default function sendBatch( .catch(reject); }); - function generateRequestPayload(batch: Batch): Record[] { - return batch.lookups.map((lookup: Record) => { + function generateRequestPayload(batch: Batch): Record[] { + return batch.lookups.map((lookup) => { if (customBuildInputData) { - return customBuildInputData(lookup); + return customBuildInputData(lookup as Record); } - return buildInputData(lookup, keyTranslationFormat!); + return buildInputData(lookup as Record, keyTranslationFormat!); }); } - function assignResultsToLookups(batch: Batch, response: any): Batch { - response.payload.forEach((rawResult: Record) => { + function assignResultsToLookups(batch: Batch, response: Response): Batch { + (response.payload as Record[]).forEach((rawResult: Record) => { const result = new Result(rawResult); const lookup = batch.getByIndex(result.inputIndex); diff --git a/tests/us_street/test_Client.ts b/tests/us_street/test_Client.ts index d627cd3..f3dfc60 100644 --- a/tests/us_street/test_Client.ts +++ b/tests/us_street/test_Client.ts @@ -244,11 +244,12 @@ describe("A US Street client", function () { batch.add(lookup3); return client.send(batch).then((_response) => { - expect(batch.getByIndex(0).result[0].deliveryLine1).to.equal("Address 0"); - expect(batch.getByIndex(0).result[1].deliveryLine1).to.equal("Alternate address 0"); - expect(batch.getByIndex(1).result[0].deliveryLine1).to.equal("Address 1"); - expect(batch.getByIndex(2).result).to.deep.equal([]); - expect(batch.getByIndex(3).result[0].deliveryLine1).to.equal("Address 3"); + const get = (i: number) => batch.getByIndex(i) as Lookup; + expect(get(0).result[0].deliveryLine1).to.equal("Address 0"); + expect(get(0).result[1].deliveryLine1).to.equal("Alternate address 0"); + expect(get(1).result[0].deliveryLine1).to.equal("Address 1"); + expect(get(2).result).to.deep.equal([]); + expect(get(3).result[0].deliveryLine1).to.equal("Address 3"); }); }); diff --git a/tests/us_zipcode/test_Client.ts b/tests/us_zipcode/test_Client.ts index 2875818..9b28813 100644 --- a/tests/us_zipcode/test_Client.ts +++ b/tests/us_zipcode/test_Client.ts @@ -82,11 +82,12 @@ describe("A US Zipcode client", function () { batch.add(lookup3); return client.send(batch).then((_response) => { - expect(batch.getByIndex(0).result[0].status).to.equal("Status 0"); - expect(batch.getByIndex(0).result[1].status).to.equal("Alternate status 0"); - expect(batch.getByIndex(1).result[0].status).to.equal("Status 1"); - expect(batch.getByIndex(2).result).to.deep.equal([]); - expect(batch.getByIndex(3).result[0].status).to.equal("Status 3"); + const get = (i: number) => batch.getByIndex(i) as Lookup; + expect(get(0).result[0].status).to.equal("Status 0"); + expect(get(0).result[1].status).to.equal("Alternate status 0"); + expect(get(1).result[0].status).to.equal("Status 1"); + expect(get(2).result).to.deep.equal([]); + expect(get(3).result[0].status).to.equal("Status 3"); }); }); From 7d44aa2c7d6c82c90ffa9ea87791ad7a1410b99a Mon Sep 17 00:00:00 2001 From: Ryan Cox Date: Mon, 2 Mar 2026 14:43:44 -0700 Subject: [PATCH 21/29] Type Client response params and narrow us_enrichment attributes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - international_street/Client: response: any → Response, cast payload - international_postal_code/Client: response: any → Response - us_reverse_geo/Client: response: any → SdkResponse, cast payload - us_enrichment/Response: attributes: Record → Record on all 3 classes (Response, FinancialResponse, GeoResponse) - us_enrichment/Client: payload casts narrowed to Record - GeoResponse: refactored to use local typed objects to avoid unknown reads --- src/international_postal_code/Client.ts | 8 +++-- src/international_street/Client.ts | 12 ++++--- src/us_enrichment/Client.ts | 10 +++--- src/us_enrichment/Response.ts | 47 +++++++++++++------------ src/us_reverse_geo/Client.ts | 6 ++-- 5 files changed, 45 insertions(+), 38 deletions(-) diff --git a/src/international_postal_code/Client.ts b/src/international_postal_code/Client.ts index 85c9aa7..f6ca141 100644 --- a/src/international_postal_code/Client.ts +++ b/src/international_postal_code/Client.ts @@ -3,7 +3,7 @@ import Result from "./Result.js"; import buildInputData from "../util/buildInputData.js"; import apiToSDKKeyMap from "../util/apiToSDKKeyMap.js"; import { UndefinedLookupError } from "../Errors.js"; -import { Sender } from "../types.js"; +import { Sender, Response } from "../types.js"; import Lookup from "./Lookup.js"; const keyTranslationFormat = apiToSDKKeyMap.internationalPostalCode; @@ -32,9 +32,11 @@ export default class Client { .catch(reject); }); - function attachLookupResults(response: any, lookup: Lookup): Lookup { + function attachLookupResults(response: Response, lookup: Lookup): Lookup { if (response.payload && Array.isArray(response.payload)) { - lookup.result = response.payload.map((r: Record) => new Result(r)); + lookup.result = response.payload.map( + (r: Record) => new Result(r), + ); } else { lookup.result = []; } diff --git a/src/international_street/Client.ts b/src/international_street/Client.ts index 726f758..1fb1842 100644 --- a/src/international_street/Client.ts +++ b/src/international_street/Client.ts @@ -3,7 +3,7 @@ import { UndefinedLookupError } from "../Errors.js"; import Candidate from "./Candidate.js"; import buildInputData from "../util/buildInputData.js"; import apiToSDKKeyMap from "../util/apiToSDKKeyMap.js"; -import { Sender } from "../types.js"; +import { Sender, Response } from "../types.js"; import Lookup from "./Lookup.js"; const keyTranslationFormat = apiToSDKKeyMap.internationalStreet; @@ -32,11 +32,13 @@ export default class Client { .catch(reject); }); - function attachLookupCandidates(response: any, lookup: Lookup): Lookup { + function attachLookupCandidates(response: Response, lookup: Lookup): Lookup { if (response.payload) { - response.payload.forEach((rawCandidate: Record) => { - lookup.result.push(new Candidate(rawCandidate)); - }); + (response.payload as Record[]).forEach( + (rawCandidate: Record) => { + lookup.result.push(new Candidate(rawCandidate)); + }, + ); } return lookup; diff --git a/src/us_enrichment/Client.ts b/src/us_enrichment/Client.ts index 55b9823..d3f6f40 100644 --- a/src/us_enrichment/Client.ts +++ b/src/us_enrichment/Client.ts @@ -28,7 +28,7 @@ export default class Client { .then((response) => { if (response.error) return reject(response.error); - lookup.response = response.payload as Record; + lookup.response = response.payload as Record; resolve(lookup); }) .catch(reject); @@ -49,7 +49,7 @@ export default class Client { .then((response) => { if (response.error) return reject(response.error); - lookup.response = response.payload as Record; + lookup.response = response.payload as Record; resolve(lookup); }) .catch(reject); @@ -70,7 +70,7 @@ export default class Client { .then((response) => { if (response.error) return reject(response.error); - lookup.response = response.payload as Record; + lookup.response = response.payload as Record; resolve(lookup); }) .catch(reject); @@ -91,7 +91,7 @@ export default class Client { .then((response) => { if (response.error) return reject(response.error); - lookup.response = response.payload as Record; + lookup.response = response.payload as Record; resolve(lookup); }) .catch(reject); @@ -112,7 +112,7 @@ export default class Client { .then((response) => { if (response.error) return reject(response.error); - lookup.response = response.payload as Record; + lookup.response = response.payload as Record; resolve(lookup); }) .catch(reject); diff --git a/src/us_enrichment/Response.ts b/src/us_enrichment/Response.ts index 780326e..90370b5 100644 --- a/src/us_enrichment/Response.ts +++ b/src/us_enrichment/Response.ts @@ -2,7 +2,7 @@ export class Response { smartyKey: string; dataSetName: string; dataSubsetName: string; - attributes: Record; + attributes: Record; constructor(responseData: Record) { this.smartyKey = responseData.smarty_key; @@ -443,7 +443,7 @@ export class FinancialResponse { smartyKey: string; dataSetName: string; dataSubsetName: string; - attributes: Record; + attributes: Record; constructor(responseData: Record) { this.smartyKey = responseData.smarty_key; @@ -590,7 +590,7 @@ export class FinancialResponse { export class GeoResponse { smartyKey: string; dataSetName: string; - attributes: Record; + attributes: Record; constructor(responseData: Record) { this.smartyKey = responseData.smarty_key; @@ -598,40 +598,43 @@ export class GeoResponse { this.attributes = {}; if (responseData.attributes) { - this.attributes.censusBlock = {}; + const censusBlock: Record = {}; if (responseData.attributes.census_block) { - this.attributes.censusBlock.accuracy = responseData.attributes.census_block.accuracy; - this.attributes.censusBlock.geoid = responseData.attributes.census_block.geoid; + censusBlock.accuracy = responseData.attributes.census_block.accuracy; + censusBlock.geoid = responseData.attributes.census_block.geoid; } + this.attributes.censusBlock = censusBlock; - this.attributes.censusCountyDivision = {}; + const censusCountyDivision: Record = {}; if (responseData.attributes.census_county_division) { - this.attributes.censusCountyDivision.accuracy = + censusCountyDivision.accuracy = responseData.attributes.census_county_division.accuracy; - this.attributes.censusCountyDivision.code = - responseData.attributes.census_county_division.code; - this.attributes.censusCountyDivision.name = - responseData.attributes.census_county_division.name; + censusCountyDivision.code = responseData.attributes.census_county_division.code; + censusCountyDivision.name = responseData.attributes.census_county_division.name; } + this.attributes.censusCountyDivision = censusCountyDivision; - this.attributes.censusTract = {}; + const censusTract: Record = {}; if (responseData.attributes.census_tract) { - this.attributes.censusTract.code = responseData.attributes.census_tract.code; + censusTract.code = responseData.attributes.census_tract.code; } + this.attributes.censusTract = censusTract; - this.attributes.coreBasedStatArea = {}; + const coreBasedStatArea: Record = {}; if (responseData.attributes.core_based_stat_area) { - this.attributes.coreBasedStatArea.code = responseData.attributes.core_based_stat_area.code; - this.attributes.coreBasedStatArea.name = responseData.attributes.core_based_stat_area.name; + coreBasedStatArea.code = responseData.attributes.core_based_stat_area.code; + coreBasedStatArea.name = responseData.attributes.core_based_stat_area.name; } + this.attributes.coreBasedStatArea = coreBasedStatArea; - this.attributes.place = {}; + const place: Record = {}; if (responseData.attributes.place) { - this.attributes.place.accuracy = responseData.attributes.place.accuracy; - this.attributes.place.code = responseData.attributes.place.code; - this.attributes.place.name = responseData.attributes.place.name; - this.attributes.place.type = responseData.attributes.place.type; + place.accuracy = responseData.attributes.place.accuracy; + place.code = responseData.attributes.place.code; + place.name = responseData.attributes.place.name; + place.type = responseData.attributes.place.type; } + this.attributes.place = place; } } } diff --git a/src/us_reverse_geo/Client.ts b/src/us_reverse_geo/Client.ts index 541c9ca..e466f37 100644 --- a/src/us_reverse_geo/Client.ts +++ b/src/us_reverse_geo/Client.ts @@ -3,7 +3,7 @@ import Response from "./Response.js"; import buildInputData from "../util/buildInputData.js"; import apiToSDKKeyMap from "../util/apiToSDKKeyMap.js"; import { UndefinedLookupError } from "../Errors.js"; -import { Sender } from "../types.js"; +import { Sender, Response as SdkResponse } from "../types.js"; import Lookup from "./Lookup.js"; const keyTranslationFormat = apiToSDKKeyMap.usReverseGeo; @@ -32,8 +32,8 @@ export default class Client { .catch(reject); }); - function attachLookupResults(response: any, lookup: Lookup): Lookup { - lookup.response = new Response(response.payload); + function attachLookupResults(response: SdkResponse, lookup: Lookup): Lookup { + lookup.response = new Response(response.payload as Record); return lookup; } From 7933958cd55094dcdb51b423eca70f64eb6d2611 Mon Sep 17 00:00:00 2001 From: Ryan Cox Date: Mon, 2 Mar 2026 14:45:25 -0700 Subject: [PATCH 22/29] Type ClientBuilder proxy as AxiosProxyConfig and genericize buildClient MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - proxy: any → AxiosProxyConfig | undefined - buildClient: generic return type instead of any --- src/ClientBuilder.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ClientBuilder.ts b/src/ClientBuilder.ts index 4140fd7..4153af9 100644 --- a/src/ClientBuilder.ts +++ b/src/ClientBuilder.ts @@ -23,6 +23,7 @@ import InternationalAddressAutocompleteClient from "./international_address_auto import UsEnrichmentClient from "./us_enrichment/Client.js"; import InternationalPostalCodeClient from "./international_postal_code/Client.js"; import { Sender } from "./types.js"; +import { AxiosProxyConfig } from "axios"; const INTERNATIONAL_STREET_API_URI = "https://international-street.api.smarty.com/verify"; const US_AUTOCOMPLETE_PRO_API_URL = "https://us-autocomplete-pro.api.smarty.com/lookup"; @@ -43,7 +44,7 @@ export default class ClientBuilder { private maxRetries: number; private maxTimeout: number; private baseUrl: string | undefined; - private proxy: any; + private proxy: AxiosProxyConfig | undefined; private customHeaders: Record; private appendHeaders: Record; private debug: boolean | undefined; @@ -196,7 +197,7 @@ export default class ClientBuilder { return customQuerySender; } - buildClient(baseUrl: string, ClientClass: new (sender: Sender) => any): any { + buildClient(baseUrl: string, ClientClass: new (sender: Sender) => T): T { if (!this.baseUrl) { this.baseUrl = baseUrl; } From 0b12e866e469d10003e904af49b534f86c5faf3d Mon Sep 17 00:00:00 2001 From: Ryan Cox Date: Mon, 2 Mar 2026 14:46:55 -0700 Subject: [PATCH 23/29] Type test fixture mock senders - MockSender: typed request fields, send accepts IRequest - MockSenderWithResponse: typed payload/error params and send return - MockSenderWithStatusCodesAndHeaders: statusCodes number[], headers Record, error string, send accepts IRequest --- tests/fixtures/mock_senders.ts | 43 ++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/tests/fixtures/mock_senders.ts b/tests/fixtures/mock_senders.ts index a9c7c52..6b4e614 100644 --- a/tests/fixtures/mock_senders.ts +++ b/tests/fixtures/mock_senders.ts @@ -1,38 +1,43 @@ import { buildSmartyResponse } from "../../src/util/buildSmartyResponse.js"; import Response from "../../src/Response.js"; +import { Request as IRequest, Response as IResponse } from "../../src/types.js"; export class MockSender { request: { - payload: any; - parameters: any; - baseUrlParam: any; + payload: string | object | null; + parameters: Record; + baseUrlParam: string; }; constructor() { this.request = { - payload: undefined, - parameters: undefined, - baseUrlParam: undefined, + payload: null, + parameters: {}, + baseUrlParam: "", }; } - send(clientRequest: any): any { + send(clientRequest: IRequest): Promise { this.request.payload = clientRequest.payload; this.request.parameters = clientRequest.parameters; this.request.baseUrlParam = clientRequest.baseUrlParam; + return undefined as unknown as Promise; } } export class MockSenderWithResponse { - private expectedPayload: any; - private expectedError: any; + private expectedPayload: object[] | object | string | null; + private expectedError: Error | null; - constructor(expectedPayload: any, expectedError?: any) { + constructor( + expectedPayload: object[] | object | string | null, + expectedError?: Error | null, + ) { this.expectedPayload = expectedPayload; - this.expectedError = expectedError; + this.expectedError = expectedError ?? null; } - send(): Promise { + send(): Promise { return new Promise((resolve) => { resolve(new Response(0, this.expectedPayload, this.expectedError)); }); @@ -40,19 +45,23 @@ export class MockSenderWithResponse { } export class MockSenderWithStatusCodesAndHeaders { - statusCodes: any[]; - headers: any; - error: any; + statusCodes: number[]; + headers: Record | undefined; + error: string | undefined; currentStatusCodeIndex: number; - constructor(statusCodes: any[], headers?: any, error?: any) { + constructor( + statusCodes: number[], + headers?: Record, + error?: string, + ) { this.statusCodes = statusCodes; this.headers = headers; this.error = error; this.currentStatusCodeIndex = 0; } - send(_request: any) { + send(_request: IRequest) { const mockResponse = { status: this.statusCodes[this.currentStatusCodeIndex], headers: this.headers, From 76f04d2f961d6b71a226deeb487ebe63a5473b98 Mon Sep 17 00:00:00 2001 From: Ryan Cox Date: Mon, 2 Mar 2026 17:04:26 -0700 Subject: [PATCH 24/29] Wire up us_enrichment Response constructors in Client The Client was assigning raw snake_case JSON payloads directly to lookup.response, bypassing the Response/FinancialResponse/GeoResponse constructors that transform keys to camelCase. Now each send method constructs the appropriate Response type, and Lookup.response is typed accordingly. --- src/us_enrichment/Client.ts | 11 ++--- src/us_enrichment/Lookup.ts | 6 ++- tests/us_enrichment/test_Client.ts | 66 +++++++++++++++--------------- 3 files changed, 44 insertions(+), 39 deletions(-) diff --git a/src/us_enrichment/Client.ts b/src/us_enrichment/Client.ts index d3f6f40..bccea75 100644 --- a/src/us_enrichment/Client.ts +++ b/src/us_enrichment/Client.ts @@ -4,6 +4,7 @@ import buildInputData from "../util/buildInputData.js"; import apiToSDKKeyMap from "../util/apiToSDKKeyMap.js"; import { Sender } from "../types.js"; import Lookup from "./Lookup.js"; +import { Response, FinancialResponse, GeoResponse } from "./Response.js"; const keyTranslationFormat = apiToSDKKeyMap.usEnrichment; @@ -28,7 +29,7 @@ export default class Client { .then((response) => { if (response.error) return reject(response.error); - lookup.response = response.payload as Record; + lookup.response = new Response(response.payload as Record); resolve(lookup); }) .catch(reject); @@ -49,7 +50,7 @@ export default class Client { .then((response) => { if (response.error) return reject(response.error); - lookup.response = response.payload as Record; + lookup.response = new FinancialResponse(response.payload as Record); resolve(lookup); }) .catch(reject); @@ -70,7 +71,7 @@ export default class Client { .then((response) => { if (response.error) return reject(response.error); - lookup.response = response.payload as Record; + lookup.response = new GeoResponse(response.payload as Record); resolve(lookup); }) .catch(reject); @@ -91,7 +92,7 @@ export default class Client { .then((response) => { if (response.error) return reject(response.error); - lookup.response = response.payload as Record; + lookup.response = new Response(response.payload as Record); resolve(lookup); }) .catch(reject); @@ -112,7 +113,7 @@ export default class Client { .then((response) => { if (response.error) return reject(response.error); - lookup.response = response.payload as Record; + lookup.response = new Response(response.payload as Record); resolve(lookup); }) .catch(reject); diff --git a/src/us_enrichment/Lookup.ts b/src/us_enrichment/Lookup.ts index 33a19e5..dfeb49c 100644 --- a/src/us_enrichment/Lookup.ts +++ b/src/us_enrichment/Lookup.ts @@ -1,3 +1,5 @@ +import { Response, FinancialResponse, GeoResponse } from "./Response.js"; + export default class Lookup { smartyKey: string | undefined; include: string | undefined; @@ -5,7 +7,7 @@ export default class Lookup { dataset: string | undefined; dataSubset: string | undefined; features: string | undefined; - response: Record; + response: Response | FinancialResponse | GeoResponse; customParameters: Record; constructor( @@ -22,7 +24,7 @@ export default class Lookup { this.dataSubset = dataSubset; this.features = undefined; - this.response = {}; + this.response = new Response({}); this.customParameters = {}; } diff --git a/tests/us_enrichment/test_Client.ts b/tests/us_enrichment/test_Client.ts index 9c7cb01..95a0958 100644 --- a/tests/us_enrichment/test_Client.ts +++ b/tests/us_enrichment/test_Client.ts @@ -301,58 +301,58 @@ describe("A US Enrichment Client", function () { }); }); - it("returns an empty array when no principal respo are returned.", () => { + it("returns an empty response when no principal data is returned.", () => { let mockSender = new MockSenderWithResponse({}); let client = new Client(mockSender); let lookup = new Lookup("smartyKey"); return client.sendPrincipal(lookup).then((_response) => { - expect(lookup.response).to.deep.equal({}); + expect(lookup.response).to.deep.equal(new Response({})); }); }); - it("returns an empty array when no financial suggestions are returned.", () => { + it("returns an empty response when no financial data is returned.", () => { let mockSender = new MockSenderWithResponse({}); let client = new Client(mockSender); let lookup = new Lookup("smartyKey"); return client.sendFinancial(lookup).then((_response) => { - expect(lookup.response).to.deep.equal({}); + expect(lookup.response).to.deep.equal(new FinancialResponse({})); }); }); - it("returns an empty array when no geo suggestions are returned.", () => { + it("returns an empty response when no geo data is returned.", () => { let mockSender = new MockSenderWithResponse({}); let client = new Client(mockSender); let lookup = new Lookup("smartyKey"); return client.sendGeo(lookup).then((_response) => { - expect(lookup.response).to.deep.equal({}); + expect(lookup.response).to.deep.equal(new GeoResponse({})); }); }); - it("returns an empty array when no secondary suggestions are returned.", () => { + it("returns an empty response when no secondary data is returned.", () => { let mockSender = new MockSenderWithResponse({}); let client = new Client(mockSender); let lookup = new Lookup("smartyKey"); return client.sendSecondary(lookup).then((_response) => { - expect(lookup.response).to.deep.equal({}); + expect(lookup.response).to.deep.equal(new Response({})); }); }); - it("returns an empty array when no secondary count suggestions are returned.", () => { + it("returns an empty response when no secondary count data is returned.", () => { let mockSender = new MockSenderWithResponse({}); let client = new Client(mockSender); let lookup = new Lookup("smartyKey"); return client.sendSecondaryCount(lookup).then((_response) => { - expect(lookup.response).to.deep.equal({}); + expect(lookup.response).to.deep.equal(new Response({})); }); }); it("attaches response to a principal lookup.", function () { - const rawMockResponse = { + const rawMockPayload = { smarty_key: "a", data_set_name: "b", data_subset_name: "c", @@ -360,19 +360,19 @@ describe("A US Enrichment Client", function () { assessed_improvement_percent: "1", }, }; - let mockResponse = new Response(rawMockResponse); + let expectedResponse = new Response(rawMockPayload); - let mockSender = new MockSenderWithResponse(mockResponse); + let mockSender = new MockSenderWithResponse(rawMockPayload); let client = new Client(mockSender); let lookup = new Lookup("smartyKey"); return client.sendPrincipal(lookup).then((_response) => { - expect(lookup.response).to.deep.equal(mockResponse); + expect(lookup.response).to.deep.equal(expectedResponse); }); }); it("attaches response to a financial lookup.", function () { - const rawMockResponse = { + const rawMockPayload = { smarty_key: "a", data_set_name: "b", data_subset_name: "c", @@ -380,39 +380,41 @@ describe("A US Enrichment Client", function () { assessed_improvement_percent: "1", }, }; - let mockResponse = new FinancialResponse(rawMockResponse); + let expectedResponse = new FinancialResponse(rawMockPayload); - let mockSender = new MockSenderWithResponse(mockResponse); + let mockSender = new MockSenderWithResponse(rawMockPayload); let client = new Client(mockSender); let lookup = new Lookup("smartyKey"); return client.sendFinancial(lookup).then((_response) => { - expect(lookup.response).to.deep.equal(mockResponse); + expect(lookup.response).to.deep.equal(expectedResponse); }); }); it("attaches response to a geo lookup.", function () { - const rawMockResponse = { + const rawMockPayload = { smarty_key: "a", data_set_name: "b", - data_subset_name: "c", attributes: { - assessed_improvement_percent: "1", + census_block: { + accuracy: "high", + geoid: "12345", + }, }, }; - let mockResponse = new GeoResponse(rawMockResponse); + let expectedResponse = new GeoResponse(rawMockPayload); - let mockSender = new MockSenderWithResponse(mockResponse); + let mockSender = new MockSenderWithResponse(rawMockPayload); let client = new Client(mockSender); let lookup = new Lookup("smartyKey"); return client.sendGeo(lookup).then((_response) => { - expect(lookup.response).to.deep.equal(mockResponse); + expect(lookup.response).to.deep.equal(expectedResponse); }); }); it("attaches response to a secondary lookup.", function () { - const rawMockResponse = { + const rawMockPayload = { smarty_key: "a", data_set_name: "b", data_subset_name: "c", @@ -420,19 +422,19 @@ describe("A US Enrichment Client", function () { assessed_improvement_percent: "1", }, }; - let mockResponse = new Response(rawMockResponse); + let expectedResponse = new Response(rawMockPayload); - let mockSender = new MockSenderWithResponse(mockResponse); + let mockSender = new MockSenderWithResponse(rawMockPayload); let client = new Client(mockSender); let lookup = new Lookup("smartyKey"); return client.sendSecondary(lookup).then((_response) => { - expect(lookup.response).to.deep.equal(mockResponse); + expect(lookup.response).to.deep.equal(expectedResponse); }); }); it("attaches response to a secondary count lookup.", function () { - const rawMockResponse = { + const rawMockPayload = { smarty_key: "a", data_set_name: "b", data_subset_name: "c", @@ -440,14 +442,14 @@ describe("A US Enrichment Client", function () { assessed_improvement_percent: "1", }, }; - let mockResponse = new Response(rawMockResponse); + let expectedResponse = new Response(rawMockPayload); - let mockSender = new MockSenderWithResponse(mockResponse); + let mockSender = new MockSenderWithResponse(rawMockPayload); let client = new Client(mockSender); let lookup = new Lookup("smartyKey"); return client.sendSecondaryCount(lookup).then((_response) => { - expect(lookup.response).to.deep.equal(mockResponse); + expect(lookup.response).to.deep.equal(expectedResponse); }); }); }); From 071da4bee86c6466fb16b6caff557cad27336265 Mon Sep 17 00:00:00 2001 From: Ryan Cox Date: Tue, 3 Mar 2026 11:37:59 -0700 Subject: [PATCH 25/29] Replace Record with named interfaces, enable noPropertyAccessFromIndexSignature --- .../Client.ts | 4 +- .../Suggestion.ts | 35 +- src/international_postal_code/Client.ts | 6 +- src/international_postal_code/Result.ts | 38 +- src/international_street/Candidate.ts | 134 +- src/international_street/Client.ts | 10 +- src/us_autocomplete_pro/Client.ts | 4 +- src/us_autocomplete_pro/Suggestion.ts | 24 +- src/us_enrichment/Response.ts | 1125 ++++++++++++++++- src/us_extract/Address.ts | 27 +- src/us_extract/Client.ts | 14 +- src/us_extract/Result.ts | 15 +- src/us_reverse_geo/Client.ts | 5 +- src/us_reverse_geo/Response.ts | 10 +- src/us_reverse_geo/Result.ts | 25 +- src/us_street/Candidate.ts | 108 +- src/us_zipcode/Result.ts | 82 +- src/util/apiToSDKKeyMap.ts | 14 +- src/util/buildInputData.ts | 7 +- src/util/buildSmartyResponse.ts | 9 +- src/util/buildUsStreetInputData.ts | 3 +- src/util/sendBatch.ts | 6 +- .../international_postal_code/test_Lookup.ts | 2 +- .../international_postal_code/test_Result.ts | 6 +- tests/test_ExtractExample.ts | 2 +- tests/test_HttpSender.ts | 2 +- tests/us_autocomplete_pro/test_Client.ts | 4 +- tests/us_autocomplete_pro/test_Suggestion.ts | 4 +- tests/us_street/test_Candidate.ts | 12 +- tests/us_zipcode/test_Result.ts | 4 +- tsconfig.json | 1 + 31 files changed, 1582 insertions(+), 160 deletions(-) diff --git a/src/international_address_autocomplete/Client.ts b/src/international_address_autocomplete/Client.ts index 6dd28da..b85008a 100644 --- a/src/international_address_autocomplete/Client.ts +++ b/src/international_address_autocomplete/Client.ts @@ -1,6 +1,6 @@ import { UndefinedLookupError } from "../Errors.js"; import Request from "../Request.js"; -import Suggestion from "./Suggestion.js"; +import Suggestion, { RawIntlAutocompleteSuggestion } from "./Suggestion.js"; import buildInputData from "../util/buildInputData.js"; import apiToSDKKeyMap from "../util/apiToSDKKeyMap.js"; import { Sender } from "../types.js"; @@ -32,7 +32,7 @@ export default class Client { if (response.error) return reject(response.error); const payload = response.payload as { - candidates: Record[] | null; + candidates: RawIntlAutocompleteSuggestion[] | null; }; lookup.result = !payload || payload.candidates === null diff --git a/src/international_address_autocomplete/Suggestion.ts b/src/international_address_autocomplete/Suggestion.ts index 15a484d..bd1e33f 100644 --- a/src/international_address_autocomplete/Suggestion.ts +++ b/src/international_address_autocomplete/Suggestion.ts @@ -1,3 +1,16 @@ +export interface RawIntlAutocompleteSuggestion { + street?: string; + locality?: string; + administrative_area?: string; + administrative_area_short?: string; + administrative_area_long?: string; + postal_code?: string; + country_iso3?: string; + entries?: number; + address_text?: string; + address_id?: string; +} + export default class Suggestion { street: string; locality: string; @@ -10,16 +23,16 @@ export default class Suggestion { addressText: string; addressId: string; - constructor(responseData: Record) { - this.street = responseData.street; - this.locality = responseData.locality; - this.administrativeArea = responseData.administrative_area; - this.administrativeAreaShort = responseData.administrative_area_short; - this.administrativeAreaLong = responseData.administrative_area_long; - this.postalCode = responseData.postal_code; - this.countryIso3 = responseData.country_iso3; - this.entries = responseData.entries; - this.addressText = responseData.address_text; - this.addressId = responseData.address_id; + constructor(responseData: RawIntlAutocompleteSuggestion) { + this.street = responseData.street ?? ""; + this.locality = responseData.locality ?? ""; + this.administrativeArea = responseData.administrative_area ?? ""; + this.administrativeAreaShort = responseData.administrative_area_short ?? ""; + this.administrativeAreaLong = responseData.administrative_area_long ?? ""; + this.postalCode = responseData.postal_code ?? ""; + this.countryIso3 = responseData.country_iso3 ?? ""; + this.entries = responseData.entries ?? 0; + this.addressText = responseData.address_text ?? ""; + this.addressId = responseData.address_id ?? ""; } } diff --git a/src/international_postal_code/Client.ts b/src/international_postal_code/Client.ts index f6ca141..5d82092 100644 --- a/src/international_postal_code/Client.ts +++ b/src/international_postal_code/Client.ts @@ -1,5 +1,5 @@ import Request from "../Request.js"; -import Result from "./Result.js"; +import Result, { RawIntlPostalCodeResult } from "./Result.js"; import buildInputData from "../util/buildInputData.js"; import apiToSDKKeyMap from "../util/apiToSDKKeyMap.js"; import { UndefinedLookupError } from "../Errors.js"; @@ -34,8 +34,8 @@ export default class Client { function attachLookupResults(response: Response, lookup: Lookup): Lookup { if (response.payload && Array.isArray(response.payload)) { - lookup.result = response.payload.map( - (r: Record) => new Result(r), + lookup.result = (response.payload as RawIntlPostalCodeResult[]).map( + (r) => new Result(r), ); } else { lookup.result = []; diff --git a/src/international_postal_code/Result.ts b/src/international_postal_code/Result.ts index 5c979b2..9f26f3b 100644 --- a/src/international_postal_code/Result.ts +++ b/src/international_postal_code/Result.ts @@ -1,3 +1,17 @@ +export interface RawIntlPostalCodeResult { + input_id?: string; + administrative_area?: string; + super_administrative_area?: string; + sub_administrative_area?: string; + locality?: string; + dependent_locality?: string; + dependent_locality_name?: string; + double_dependent_locality?: string; + postal_code?: string; + postal_code_extra?: string; + country_iso_3?: string; +} + export default class Result { inputId: string; administrativeArea: string; @@ -11,17 +25,17 @@ export default class Result { postalCodeExtra: string; countryIso3: string; - constructor(responseData: Record) { - this.inputId = responseData.input_id; - this.administrativeArea = responseData.administrative_area; - this.superAdministrativeArea = responseData.super_administrative_area; - this.subAdministrativeArea = responseData.sub_administrative_area; - this.locality = responseData.locality; - this.dependentLocality = responseData.dependent_locality; - this.dependentLocalityName = responseData.dependent_locality_name; - this.doubleDependentLocality = responseData.double_dependent_locality; - this.postalCode = responseData.postal_code; - this.postalCodeExtra = responseData.postal_code_extra; - this.countryIso3 = responseData.country_iso_3; + constructor(responseData: RawIntlPostalCodeResult) { + this.inputId = responseData.input_id ?? ""; + this.administrativeArea = responseData.administrative_area ?? ""; + this.superAdministrativeArea = responseData.super_administrative_area ?? ""; + this.subAdministrativeArea = responseData.sub_administrative_area ?? ""; + this.locality = responseData.locality ?? ""; + this.dependentLocality = responseData.dependent_locality ?? ""; + this.dependentLocalityName = responseData.dependent_locality_name ?? ""; + this.doubleDependentLocality = responseData.double_dependent_locality ?? ""; + this.postalCode = responseData.postal_code ?? ""; + this.postalCodeExtra = responseData.postal_code_extra ?? ""; + this.countryIso3 = responseData.country_iso_3 ?? ""; } } diff --git a/src/international_street/Candidate.ts b/src/international_street/Candidate.ts index 43f3151..3def259 100644 --- a/src/international_street/Candidate.ts +++ b/src/international_street/Candidate.ts @@ -132,6 +132,112 @@ export interface IntlStreetMetadata { occupantUse: string | undefined; } +interface RawIntlStreetRawComponents { + country_iso_3?: string; + super_administrative_area?: string; + administrative_area?: string; + administrative_area_iso2?: string; + administrative_area_short?: string; + administrative_area_long?: string; + sub_administrative_area?: string; + dependent_locality?: string; + dependent_locality_name?: string; + double_dependent_locality?: string; + locality?: string; + postal_code?: string; + postal_code_short?: string; + postal_code_extra?: string; + premise?: string; + premise_extra?: string; + premise_prefix_number?: string; + premise_number?: string; + premise_type?: string; + thoroughfare?: string; + thoroughfare_predirection?: string; + thoroughfare_postdirection?: string; + thoroughfare_name?: string; + thoroughfare_trailing_type?: string; + thoroughfare_type?: string; + dependent_thoroughfare?: string; + dependent_thoroughfare_predirection?: string; + dependent_thoroughfare_postdirection?: string; + dependent_thoroughfare_name?: string; + dependent_thoroughfare_trailing_type?: string; + dependent_thoroughfare_type?: string; + building?: string; + building_leading_type?: string; + building_name?: string; + building_trailing_type?: string; + sub_building_type?: string; + sub_building_number?: string; + sub_building_name?: string; + sub_building?: string; + level_type?: string; + level_number?: string; + post_box?: string; + post_box_type?: string; + post_box_number?: string; + additional_content?: string; + delivery_installation?: string; + delivery_installation_type?: string; + delivery_installation_qualifier_name?: string; + route?: string; + route_number?: string; + route_type?: string; +} + +interface RawIntlChanges { + organization?: string; + address1?: string; + address2?: string; + address3?: string; + address4?: string; + address5?: string; + address6?: string; + address7?: string; + address8?: string; + address9?: string; + address10?: string; + address11?: string; + address12?: string; + components?: RawIntlStreetRawComponents; +} + +interface RawIntlStreetAnalysis { + verification_status?: string; + address_precision?: string; + max_address_precision?: string; + changes?: RawIntlChanges; +} + +interface RawIntlStreetMetadata { + latitude?: number; + longitude?: number; + geocode_precision?: string; + max_geocode_precision?: string; + address_format?: string; + occupant_use?: string; +} + +export interface RawIntlStreetCandidate { + organization?: string; + address1?: string; + address2?: string; + address3?: string; + address4?: string; + address5?: string; + address6?: string; + address7?: string; + address8?: string; + address9?: string; + address10?: string; + address11?: string; + address12?: string; + components?: RawIntlStreetRawComponents; + analysis?: RawIntlStreetAnalysis; + metadata?: RawIntlStreetMetadata; +} + export default class Candidate { organization: string; address1: string; @@ -150,20 +256,20 @@ export default class Candidate { analysis: IntlStreetAnalysis; metadata: IntlStreetMetadata; - constructor(responseData: Record) { - this.organization = responseData.organization; - this.address1 = responseData.address1; - this.address2 = responseData.address2; - this.address3 = responseData.address3; - this.address4 = responseData.address4; - this.address5 = responseData.address5; - this.address6 = responseData.address6; - this.address7 = responseData.address7; - this.address8 = responseData.address8; - this.address9 = responseData.address9; - this.address10 = responseData.address10; - this.address11 = responseData.address11; - this.address12 = responseData.address12; + constructor(responseData: RawIntlStreetCandidate) { + this.organization = responseData.organization ?? ""; + this.address1 = responseData.address1 ?? ""; + this.address2 = responseData.address2 ?? ""; + this.address3 = responseData.address3 ?? ""; + this.address4 = responseData.address4 ?? ""; + this.address5 = responseData.address5 ?? ""; + this.address6 = responseData.address6 ?? ""; + this.address7 = responseData.address7 ?? ""; + this.address8 = responseData.address8 ?? ""; + this.address9 = responseData.address9 ?? ""; + this.address10 = responseData.address10 ?? ""; + this.address11 = responseData.address11 ?? ""; + this.address12 = responseData.address12 ?? ""; this.components = {} as IntlStreetComponents; if (responseData.components !== undefined) { diff --git a/src/international_street/Client.ts b/src/international_street/Client.ts index 1fb1842..a1e70ef 100644 --- a/src/international_street/Client.ts +++ b/src/international_street/Client.ts @@ -1,6 +1,6 @@ import Request from "../Request.js"; import { UndefinedLookupError } from "../Errors.js"; -import Candidate from "./Candidate.js"; +import Candidate, { RawIntlStreetCandidate } from "./Candidate.js"; import buildInputData from "../util/buildInputData.js"; import apiToSDKKeyMap from "../util/apiToSDKKeyMap.js"; import { Sender, Response } from "../types.js"; @@ -34,11 +34,9 @@ export default class Client { function attachLookupCandidates(response: Response, lookup: Lookup): Lookup { if (response.payload) { - (response.payload as Record[]).forEach( - (rawCandidate: Record) => { - lookup.result.push(new Candidate(rawCandidate)); - }, - ); + (response.payload as RawIntlStreetCandidate[]).forEach((rawCandidate) => { + lookup.result.push(new Candidate(rawCandidate)); + }); } return lookup; diff --git a/src/us_autocomplete_pro/Client.ts b/src/us_autocomplete_pro/Client.ts index a4fc66f..a5efda6 100644 --- a/src/us_autocomplete_pro/Client.ts +++ b/src/us_autocomplete_pro/Client.ts @@ -1,6 +1,6 @@ import { UndefinedLookupError } from "../Errors.js"; import Request from "../Request.js"; -import Suggestion from "./Suggestion.js"; +import Suggestion, { RawUsAutocompleteSuggestion } from "./Suggestion.js"; import buildInputData from "../util/buildInputData.js"; import apiToSDKKeyMap from "../util/apiToSDKKeyMap.js"; import { Sender } from "../types.js"; @@ -28,7 +28,7 @@ export default class Client { if (response.error) return reject(response.error); const payload = response.payload as { - suggestions: Record[] | null; + suggestions: RawUsAutocompleteSuggestion[] | null; }; lookup.result = payload.suggestions === null diff --git a/src/us_autocomplete_pro/Suggestion.ts b/src/us_autocomplete_pro/Suggestion.ts index d7b3249..3daf4d8 100644 --- a/src/us_autocomplete_pro/Suggestion.ts +++ b/src/us_autocomplete_pro/Suggestion.ts @@ -1,3 +1,13 @@ +export interface RawUsAutocompleteSuggestion { + street_line?: string; + secondary?: string; + city?: string; + state?: string; + zipcode?: string; + entries?: number; + source?: string; +} + export default class Suggestion { streetLine: string; secondary: string; @@ -7,13 +17,13 @@ export default class Suggestion { entries: number; source: string | undefined; - constructor(responseData: Record) { - this.streetLine = responseData.street_line; - this.secondary = responseData.secondary; - this.city = responseData.city; - this.state = responseData.state; - this.zipcode = responseData.zipcode; - this.entries = responseData.entries; + constructor(responseData: RawUsAutocompleteSuggestion) { + this.streetLine = responseData.street_line ?? ""; + this.secondary = responseData.secondary ?? ""; + this.city = responseData.city ?? ""; + this.state = responseData.state ?? ""; + this.zipcode = responseData.zipcode ?? ""; + this.entries = responseData.entries ?? 0; if (responseData.source) { this.source = responseData.source; diff --git a/src/us_enrichment/Response.ts b/src/us_enrichment/Response.ts index 90370b5..a95fff0 100644 --- a/src/us_enrichment/Response.ts +++ b/src/us_enrichment/Response.ts @@ -1,15 +1,1091 @@ +export interface FinancialHistory { + codeTitleCompany: string | undefined; + instrumentDate: string | undefined; + interestRateType2: string | undefined; + lenderAddress: string | undefined; + lenderAddress2: string | undefined; + lenderCity: string | undefined; + lenderCity2: string | undefined; + lenderCode: string | undefined; + lenderCode2: string | undefined; + lenderFirstName: string | undefined; + lenderFirstName2: string | undefined; + lenderLastName: string | undefined; + lenderLastName2: string | undefined; + lenderName: string | undefined; + lenderName2: string | undefined; + lenderSellerCarryBack: string | undefined; + lenderSellerCarryBack2: string | undefined; + lenderState: string | undefined; + lenderState2: string | undefined; + lenderZip: string | undefined; + lenderZip2: string | undefined; + lenderZipExtended: string | undefined; + lenderZipExtended2: string | undefined; + mortgageAmount: string | undefined; + mortgageAmount2: string | undefined; + mortgageDueDate: string | undefined; + mortgageDueDate2: string | undefined; + mortgageInterestRate: string | undefined; + mortgageInterestRateType: string | undefined; + mortgageLenderCode: string | undefined; + mortgageRate: string | undefined; + mortgageRate2: string | undefined; + mortgageRecordingDate: string | undefined; + mortgageRecordingDate2: string | undefined; + mortgageTerm: string | undefined; + mortgageTerm2: string | undefined; + mortgageTermType: string | undefined; + mortgageTermType2: string | undefined; + mortgageType: string | undefined; + mortgageType2: string | undefined; + multiParcelFlag: string | undefined; + nameTitleCompany: string | undefined; + recordingDate: string | undefined; + transferAmount: string | undefined; +} + +interface RawFinancialHistory { + code_title_company?: string; + instrument_date?: string; + interest_rate_type_2?: string; + lender_address?: string; + lender_address_2?: string; + lender_city?: string; + lender_city_2?: string; + lender_code?: string; + lender_code_2?: string; + lender_first_name?: string; + lender_first_name_2?: string; + lender_last_name?: string; + lender_last_name_2?: string; + lender_name?: string; + lender_name_2?: string; + lender_seller_carry_back?: string; + lender_seller_carry_back_2?: string; + lender_state?: string; + lender_state_2?: string; + lender_zip?: string; + lender_zip_2?: string; + lender_zip_extended?: string; + lender_zip_extended_2?: string; + mortgage_amount?: string; + mortgage_amount_2?: string; + mortgage_due_date?: string; + mortgage_due_date_2?: string; + mortgage_interest_rate?: string; + mortgage_interest_rate_type?: string; + mortgage_lender_code?: string; + mortgage_rate?: string; + mortgage_rate_2?: string; + mortgage_recording_date?: string; + mortgage_recording_date_2?: string; + mortgage_term?: string; + mortgage_term_2?: string; + mortgage_term_type?: string; + mortgage_term_type_2?: string; + mortgage_type?: string; + mortgage_type_2?: string; + multi_parcel_flag?: string; + name_title_company?: string; + recording_date?: string; + transfer_amount?: string; +} + +export interface EnrichmentAttributes { + firstFloorSqft: string | undefined; + secondFloorSqft: string | undefined; + acres: string | undefined; + addressInfoPrivacy: string | undefined; + airConditioner: string | undefined; + arborPergola: string | undefined; + assessedImprovementPercent: string | undefined; + assessedImprovementValue: string | undefined; + assessedLandValue: string | undefined; + assessedValue: string | undefined; + assessorLastUpdate: string | undefined; + assessorTaxrollUpdate: string | undefined; + atticArea: string | undefined; + atticFlag: string | undefined; + balcony: string | undefined; + balconyArea: string | undefined; + basementSqft: string | undefined; + basementSqftFinished: string | undefined; + basementsqftUnfinished: string | undefined; + bathHouse: string | undefined; + bathHouseSqft: string | undefined; + bathroomsPartial: string | undefined; + bathroomsTotal: string | undefined; + bedrooms: string | undefined; + block1: string | undefined; + block2: string | undefined; + boatAccess: string | undefined; + boatHouse: string | undefined; + boatHouseSqft: string | undefined; + boatLift: string | undefined; + bonusRoom: string | undefined; + breakfastNook: string | undefined; + breezeway: string | undefined; + buildingDefinitionCode: string | undefined; + buildingSqft: string | undefined; + cabin: string | undefined; + cabinSqft: string | undefined; + canopy: string | undefined; + canopySqft: string | undefined; + carport: string | undefined; + carportSqft: string | undefined; + cbsaCode: string | undefined; + cbsaName: string | undefined; + cellar: string | undefined; + censusBlock: string | undefined; + censusTract: string | undefined; + censusBlockGroup: string | undefined; + censusFipsPlaceCode: string | undefined; + centralVacuum: string | undefined; + codeTitleCompany: string | undefined; + combinedStatisticalArea: string | undefined; + communityRec: string | undefined; + companyFlag: string | undefined; + congressionalDistrict: string | undefined; + constructionType: string | undefined; + contactCity: string | undefined; + contactCrrt: string | undefined; + contactFullAddress: string | undefined; + contactHouseNumber: string | undefined; + contactMailInfoFormat: string | undefined; + contactMailInfoPrivacy: string | undefined; + contactMailingCounty: string | undefined; + contactMailingFips: string | undefined; + contactPostDirection: string | undefined; + contactPreDirection: string | undefined; + contactState: string | undefined; + contactStreetName: string | undefined; + contactSuffix: string | undefined; + contactUnitDesignator: string | undefined; + contactValue: string | undefined; + contactZip: string | undefined; + contactZip4: string | undefined; + courtyard: string | undefined; + courtyardArea: string | undefined; + deck: string | undefined; + deckArea: string | undefined; + deedDocumentPage: string | undefined; + deedDocumentBook: string | undefined; + deedDocumentNumber: string | undefined; + deedOwnerFirstName: string | undefined; + deedOwnerFirstName2: string | undefined; + deedOwnerFirstName3: string | undefined; + deedOwnerFirstName4: string | undefined; + deedOwnerFullName: string | undefined; + deedOwnerFullName2: string | undefined; + deedOwnerFullName3: string | undefined; + deedOwnerFullName4: string | undefined; + deedOwnerLastName: string | undefined; + deedOwnerLastName2: string | undefined; + deedOwnerLastName3: string | undefined; + deedOwnerLastName4: string | undefined; + deedOwnerMiddleName: string | undefined; + deedOwnerMiddleName2: string | undefined; + deedOwnerMiddleName3: string | undefined; + deedOwnerMiddleName4: string | undefined; + deedOwnerSuffix: string | undefined; + deedOwnerSuffix2: string | undefined; + deedOwnerSuffix3: string | undefined; + deedOwnerSuffix4: string | undefined; + deedSaleDate: string | undefined; + deedSalePrice: string | undefined; + deedTransactionId: string | undefined; + depthLinearFootage: string | undefined; + disabledTaxExemption: string | undefined; + drivewaySqft: string | undefined; + drivewayType: string | undefined; + effectiveYearBuilt: string | undefined; + elevationFeet: string | undefined; + elevator: string | undefined; + equestrianArena: string | undefined; + escalator: string | undefined; + exerciseRoom: string | undefined; + exteriorWalls: string | undefined; + familyRoom: string | undefined; + fence: string | undefined; + fenceArea: string | undefined; + fipsCode: string | undefined; + fireResistanceCode: string | undefined; + fireSprinklersFlag: string | undefined; + fireplace: string | undefined; + fireplaceNumber: string | undefined; + firstName: string | undefined; + firstName2: string | undefined; + firstName3: string | undefined; + firstName4: string | undefined; + flooring: string | undefined; + foundation: string | undefined; + gameRoom: string | undefined; + garage: string | undefined; + garageSqft: string | undefined; + gazebo: string | undefined; + gazeboSqft: string | undefined; + golfCourse: string | undefined; + grainery: string | undefined; + grainerySqft: string | undefined; + greatRoom: string | undefined; + greenhouse: string | undefined; + greenhouseSqft: string | undefined; + grossSqft: string | undefined; + guesthouse: string | undefined; + guesthouseSqft: string | undefined; + handicapAccessibility: string | undefined; + heat: string | undefined; + heatFuelType: string | undefined; + hobbyRoom: string | undefined; + homeownerTaxExemption: string | undefined; + instrumentDate: string | undefined; + intercomSystem: string | undefined; + interestRateType2: string | undefined; + interiorStructure: string | undefined; + kennel: string | undefined; + kennelSqft: string | undefined; + landUseCode: string | undefined; + landUseGroup: string | undefined; + landUseStandard: string | undefined; + lastName: string | undefined; + lastName2: string | undefined; + lastName3: string | undefined; + lastName4: string | undefined; + latitude: string | undefined; + laundry: string | undefined; + leanTo: string | undefined; + leanToSqft: string | undefined; + legalDescription: string | undefined; + legalUnit: string | undefined; + lenderAddress: string | undefined; + lenderAddress2: string | undefined; + lenderCity: string | undefined; + lenderCity2: string | undefined; + lenderCode: string | undefined; + lenderCode2: string | undefined; + lenderFirstName: string | undefined; + lenderFirstName2: string | undefined; + lenderLastName: string | undefined; + lenderLastName2: string | undefined; + lenderName: string | undefined; + lenderName2: string | undefined; + lenderSellerCarryBack: string | undefined; + lenderSellerCarryBack2: string | undefined; + lenderState: string | undefined; + lenderState2: string | undefined; + lenderZip: string | undefined; + lenderZip2: string | undefined; + lenderZipExtended: string | undefined; + lenderZipExtended2: string | undefined; + loadingPlatform: string | undefined; + loadingPlatformSqft: string | undefined; + longitude: string | undefined; + lot1: string | undefined; + lot2: string | undefined; + lot3: string | undefined; + lotSqft: string | undefined; + marketImprovementPercent: string | undefined; + marketImprovementValue: string | undefined; + marketLandValue: string | undefined; + marketValueYear: string | undefined; + matchType: string | undefined; + mediaRoom: string | undefined; + metroDivision: string | undefined; + middleName: string | undefined; + middleName2: string | undefined; + middleName3: string | undefined; + middleName4: string | undefined; + milkhouse: string | undefined; + milkhouseSqft: string | undefined; + minorCivilDivisionCode: string | undefined; + minorCivilDivisionName: string | undefined; + mobileHomeHookup: string | undefined; + mortgageAmount: string | undefined; + mortgageAmount2: string | undefined; + mortgageDueDate: string | undefined; + mortgageDueDate2: string | undefined; + mortgageInterestRate: string | undefined; + mortgageInterestRateType: string | undefined; + mortgageLenderCode: string | undefined; + mortgageRate2: string | undefined; + mortgageRecordingDate: string | undefined; + mortgageRecordingDate2: string | undefined; + mortgageTerm: string | undefined; + mortgageTerm2: string | undefined; + mortgageTermType: string | undefined; + mortgageTermType2: string | undefined; + mortgageType: string | undefined; + mortgageType2: string | undefined; + msaCode: string | undefined; + msaName: string | undefined; + mudRoom: string | undefined; + multiParcelFlag: string | undefined; + nameTitleCompany: string | undefined; + neighborhoodCode: string | undefined; + numberOfBuildings: string | undefined; + office: string | undefined; + officeSqft: string | undefined; + otherTaxExemption: string | undefined; + outdoorKitchenFireplace: string | undefined; + overheadDoor: string | undefined; + ownerFullName: string | undefined; + ownerFullName2: string | undefined; + ownerFullName3: string | undefined; + ownerFullName4: string | undefined; + ownerOccupancyStatus: string | undefined; + ownershipTransferDate: string | undefined; + ownershipTransferDocNumber: string | undefined; + ownershipTransferTransactionId: string | undefined; + ownershipType: string | undefined; + ownershipType2: string | undefined; + ownershipVestingRelationCode: string | undefined; + parcelAccountNumber: string | undefined; + parcelMapBook: string | undefined; + parcelMapPage: string | undefined; + parcelNumberAlternate: string | undefined; + parcelNumberFormatted: string | undefined; + parcelNumberPrevious: string | undefined; + parcelNumberYearAdded: string | undefined; + parcelNumberYearChange: string | undefined; + parcelRawNumber: string | undefined; + parcelShellRecord: string | undefined; + parkingSpaces: string | undefined; + patioArea: string | undefined; + phaseName: string | undefined; + plumbingFixturesCount: string | undefined; + poleStruct: string | undefined; + poleStructSqft: string | undefined; + pond: string | undefined; + pool: string | undefined; + poolArea: string | undefined; + poolhouse: string | undefined; + poolhouseSqft: string | undefined; + porch: string | undefined; + porchArea: string | undefined; + poultryHouse: string | undefined; + poultryHouseSqft: string | undefined; + previousAssessedValue: string | undefined; + priorSaleAmount: string | undefined; + priorSaleDate: string | undefined; + propertyAddressCarrierRouteCode: string | undefined; + propertyAddressCity: string | undefined; + propertyAddressFull: string | undefined; + propertyAddressHouseNumber: string | undefined; + propertyAddressPostDirection: string | undefined; + propertyAddressPreDirection: string | undefined; + propertyAddressState: string | undefined; + propertyAddressStreetName: string | undefined; + propertyAddressStreetSuffix: string | undefined; + propertyAddressUnitDesignator: string | undefined; + propertyAddressUnitValue: string | undefined; + propertyAddressZip4: string | undefined; + propertyAddressZipcode: string | undefined; + publicationDate: string | undefined; + quarter: string | undefined; + quarterQuarter: string | undefined; + quonset: string | undefined; + quonsetSqft: string | undefined; + range: string | undefined; + recordingDate: string | undefined; + roofCover: string | undefined; + roofFrame: string | undefined; + rooms: string | undefined; + rvParking: string | undefined; + safeRoom: string | undefined; + saleAmount: string | undefined; + saleDate: string | undefined; + sauna: string | undefined; + section: string | undefined; + securityAlarm: string | undefined; + seniorTaxExemption: string | undefined; + sewerType: string | undefined; + shed: string | undefined; + shedSqft: string | undefined; + silo: string | undefined; + siloSqft: string | undefined; + sittingRoom: string | undefined; + situsCounty: string | undefined; + situsState: string | undefined; + soundSystem: string | undefined; + sportsCourt: string | undefined; + sprinklers: string | undefined; + stable: string | undefined; + stableSqft: string | undefined; + storageBuilding: string | undefined; + storageBuildingSqft: string | undefined; + storiesNumber: string | undefined; + stormShelter: string | undefined; + stormShutter: string | undefined; + structureStyle: string | undefined; + study: string | undefined; + subdivision: string | undefined; + suffix: string | undefined; + suffix2: string | undefined; + suffix3: string | undefined; + suffix4: string | undefined; + sunroom: string | undefined; + taxAssessYear: string | undefined; + taxBilledAmount: string | undefined; + taxDelinquentYear: string | undefined; + taxFiscalYear: string | undefined; + taxJurisdiction: string | undefined; + taxRateArea: string | undefined; + tennisCourt: string | undefined; + topographyCode: string | undefined; + totalMarketValue: string | undefined; + township: string | undefined; + tractNumber: string | undefined; + transferAmount: string | undefined; + trustDescription: string | undefined; + unitCount: string | undefined; + upperFloorsSqft: string | undefined; + utility: string | undefined; + utilityBuilding: string | undefined; + utilityBuildingSqft: string | undefined; + utilitySqft: string | undefined; + veteranTaxExemption: string | undefined; + viewDescription: string | undefined; + waterFeature: string | undefined; + waterServiceType: string | undefined; + wetBar: string | undefined; + widowTaxExemption: string | undefined; + widthLinearFootage: string | undefined; + wineCellar: string | undefined; + financialHistory: FinancialHistory[]; + yearBuilt: string | undefined; + zoning: string | undefined; +} + +interface RawEnrichmentAttributes { + "1st_floor_sqft"?: string; + "2nd_floor_sqft"?: string; + acres?: string; + address_info_privacy?: string; + air_conditioner?: string; + arbor_pergola?: string; + assessed_improvement_percent?: string; + assessed_improvement_value?: string; + assessed_land_value?: string; + assessed_value?: string; + assessor_last_update?: string; + assessor_taxroll_update?: string; + attic_area?: string; + attic_flag?: string; + balcony?: string; + balcony_area?: string; + basement_sqft?: string; + basement_sqft_finished?: string; + basement_sqft_unfinished?: string; + bath_house?: string; + bath_house_sqft?: string; + bathrooms_partial?: string; + bathrooms_total?: string; + bedrooms?: string; + block_1?: string; + block_2?: string; + boat_access?: string; + boat_house?: string; + boat_house_sqft?: string; + boat_lift?: string; + bonus_room?: string; + breakfast_nook?: string; + breezeway?: string; + building_definition?: string; + building_sqft?: string; + cabin?: string; + cabin_sqft?: string; + canopy?: string; + canopy_sqft?: string; + carport?: string; + carport_sqft?: string; + cbsa_code?: string; + cbsa_name?: string; + cellar?: string; + census_block?: string; + census_tract?: string; + census_block_group?: string; + census_fips_place_code?: string; + central_vacuum?: string; + code_title_company?: string; + combined_statistical_area?: string; + community_rec?: string; + company_flag?: string; + congressional_district?: string; + construction_type?: string; + contact_city?: string; + contact_crrt?: string; + contact_full_address?: string; + contact_house_number?: string; + contact_main_info_format?: string; + contact_mail_info_privacy?: string; + contact_mailing_county?: string; + contact_mailing_fips?: string; + contact_post_direction?: string; + contact_pre_direction?: string; + contact_state?: string; + contact_street_name?: string; + contact_suffix?: string; + contact_unit_designator?: string; + contact_value?: string; + contact_zip?: string; + contact_zip4?: string; + courtyard?: string; + courtyard_area?: string; + deck?: string; + deck_area?: string; + deed_document_page?: string; + deed_document_book?: string; + deed_document_number?: string; + deed_owner_first_name?: string; + deed_owner_first_name2?: string; + deed_owner_first_name3?: string; + deed_owner_first_name4?: string; + deed_owner_full_name?: string; + deed_owner_full_name2?: string; + deed_owner_full_name3?: string; + deed_owner_full_name4?: string; + deed_owner_last_name?: string; + deed_owner_last_name2?: string; + deed_owner_last_name3?: string; + deed_owner_last_name4?: string; + deed_owner_middle_name?: string; + deed_owner_middle_name2?: string; + deed_owner_middle_name3?: string; + deed_owner_middle_name4?: string; + deed_owner_suffix?: string; + deed_owner_suffix2?: string; + deed_owner_suffix3?: string; + deed_owner_suffix4?: string; + deed_sale_date?: string; + deed_sale_price?: string; + deed_transaction_id?: string; + depth_linear_footage?: string; + disabled_tax_exemption?: string; + driveway_sqft?: string; + driveway_type?: string; + effective_year_built?: string; + elevation_feet?: string; + elevator?: string; + equestrian_arena?: string; + escalator?: string; + exercise_room?: string; + exterior_walls?: string; + family_room?: string; + fence?: string; + fence_area?: string; + fips_code?: string; + fire_resistance_code?: string; + fire_sprinkler_flag?: string; + fireplace?: string; + fireplace_number?: string; + first_name?: string; + first_name2?: string; + first_name3?: string; + first_name4?: string; + flooring?: string; + foundation?: string; + game_room?: string; + garage?: string; + garage_sqft?: string; + gazebo?: string; + gazebo_sqft?: string; + golf_course?: string; + grainery?: string; + grainery_sqft?: string; + great_room?: string; + greenhouse?: string; + greenhouse_sqft?: string; + gross_sqft?: string; + guesthouse?: string; + guesthouse_sqft?: string; + handicap_accessibility?: string; + heat?: string; + heat_fuel_type?: string; + hobby_room?: string; + homeowner_tax_exemption?: string; + instrument_date?: string; + intercom_system?: string; + interest_rate_type_2?: string; + interior_structure?: string; + kennel?: string; + kennel_sqft?: string; + land_use_code?: string; + land_use_group?: string; + land_use_standard?: string; + last_name?: string; + last_name_2?: string; + last_name_3?: string; + last_name_4?: string; + latitude?: string; + laundry?: string; + lean_to?: string; + lean_to_sqft?: string; + legal_description?: string; + legal_unit?: string; + lender_address?: string; + lender_address_2?: string; + lender_city?: string; + lender_city_2?: string; + lender_code?: string; + lender_code_2?: string; + lender_first_name?: string; + lender_first_name_2?: string; + lender_last_name?: string; + lender_last_name_2?: string; + lender_name?: string; + lender_name_2?: string; + lender_seller_carry_back?: string; + lender_seller_carry_back_2?: string; + lender_state?: string; + lender_state_2?: string; + lender_zip?: string; + lender_zip_2?: string; + lender_zip_extended?: string; + lender_zip_extended_2?: string; + loading_platform?: string; + loading_platform_sqft?: string; + longitude?: string; + lot_1?: string; + lot_2?: string; + lot_3?: string; + lot_sqft?: string; + market_improvement_percent?: string; + market_improvement_value?: string; + market_land_value?: string; + market_value_year?: string; + match_type?: string; + media_room?: string; + metro_division?: string; + middle_name?: string; + middle_name_2?: string; + middle_name_3?: string; + middle_name_4?: string; + milkhouse?: string; + milkhouse_sqft?: string; + minor_civil_division_code?: string; + minor_civil_division_name?: string; + mobile_home_hookup?: string; + mortgage_amount?: string; + mortgage_amount_2?: string; + mortgage_due_date?: string; + mortgage_due_date_2?: string; + mortgage_interest_rate?: string; + mortgage_interest_rate_type?: string; + mortgage_lender_code?: string; + mortgage_rate_2?: string; + mortgage_recording_date?: string; + mortgage_recording_date_2?: string; + mortgage_term?: string; + mortgage_term_2?: string; + mortgage_term_type?: string; + mortgage_term_type_2?: string; + mortgage_type?: string; + mortgage_type_2?: string; + msa_code?: string; + msa_name?: string; + mud_room?: string; + multi_parcel_flag?: string; + name_title_company?: string; + neighborhood_code?: string; + number_of_buildings?: string; + office?: string; + office_sqft?: string; + other_tax_exemption?: string; + outdoor_kitchen_fireplace?: string; + overhead_door?: string; + owner_full_name?: string; + owner_full_name_2?: string; + owner_full_name_3?: string; + owner_full_name_4?: string; + owner_occupancy_status?: string; + ownership_transfer_date?: string; + ownership_transfer_doc_number?: string; + ownership_transfer_transaction_id?: string; + ownership_type?: string; + ownership_type_2?: string; + ownership_vesting_relation_code?: string; + parcel_account_number?: string; + parcel_map_book?: string; + parcel_map_page?: string; + parcel_number_alternate?: string; + parcel_number_formatted?: string; + parcel_number_previous?: string; + parcel_number_year_added?: string; + parcel_number_year_change?: string; + parcel_raw_number?: string; + parcel_shell_record?: string; + parking_spaces?: string; + patio_area?: string; + phase_name?: string; + plumbing_fixtures_count?: string; + pole_struct?: string; + pole_struct_sqft?: string; + pond?: string; + pool?: string; + pool_area?: string; + poolhouse?: string; + poolhouse_sqft?: string; + porch?: string; + porch_area?: string; + poultry_house?: string; + poultry_house_sqft?: string; + previous_assessed_value?: string; + prior_sale_amount?: string; + prior_sale_date?: string; + property_address_carrier_route_code?: string; + property_address_city?: string; + property_address_full?: string; + property_address_house_number?: string; + property_address_post_direction?: string; + property_address_pre_direction?: string; + property_address_state?: string; + property_address_street_name?: string; + property_address_street_suffix?: string; + property_address_unit_designator?: string; + property_address_unit_value?: string; + property_address_zip_4?: string; + property_address_zipcode?: string; + publication_date?: string; + quarter?: string; + quarter_quarter?: string; + quonset?: string; + quonset_sqft?: string; + range?: string; + recording_date?: string; + roof_cover?: string; + roof_frame?: string; + rooms?: string; + rv_parking?: string; + safe_room?: string; + sale_amount?: string; + sale_date?: string; + sauna?: string; + section?: string; + security_alarm?: string; + senior_tax_exemption?: string; + sewer_type?: string; + shed?: string; + shed_sqft?: string; + silo?: string; + silo_sqft?: string; + sitting_room?: string; + situs_county?: string; + situs_state?: string; + sound_system?: string; + sports_court?: string; + sprinklers?: string; + stable?: string; + stable_sqft?: string; + storage_building?: string; + storage_buildling_sqft?: string; + stories_number?: string; + storm_shelter?: string; + storm_shutter?: string; + structure_style?: string; + study?: string; + subdivision?: string; + suffix?: string; + suffix_2?: string; + suffix_3?: string; + suffix_4?: string; + sunroom?: string; + tax_assess_year?: string; + tax_billed_amount?: string; + tax_delinquent_year?: string; + tax_fiscal_year?: string; + tax_jurisdiction?: string; + tax_rate_area?: string; + tennis_court?: string; + topography_code?: string; + total_market_value?: string; + township?: string; + tract_number?: string; + transfer_amount?: string; + trust_description?: string; + unit_count?: string; + upper_floors_sqft?: string; + utility?: string; + utility_building?: string; + utility_building_sqft?: string; + utility_sqft?: string; + veteran_tax_exemption?: string; + view_description?: string; + water_feature?: string; + water_service_type?: string; + wet_bar?: string; + widow_tax_exemption?: string; + width_linear_footage?: string; + wine_cellar?: string; + financial_history?: RawFinancialHistory[]; + year_built?: string; + zoning?: string; +} + +interface RawEnrichmentResponse { + smarty_key?: string; + data_set_name?: string; + data_subset_name?: string; + attributes?: RawEnrichmentAttributes; +} + +export interface FinancialAttributes { + assessedImprovementPercent: string | undefined; + assessedImprovementValue: string | undefined; + assessedLandValue: string | undefined; + assessedValue: string | undefined; + assessorLastUpdate: string | undefined; + assessorTaxrollUpdate: string | undefined; + contactCity: string | undefined; + contactCrrt: string | undefined; + contactFullAddress: string | undefined; + contactHouseNumber: string | undefined; + contactMailInfoFormat: string | undefined; + contactMailInfoPrivacy: string | undefined; + contactMailingCounty: string | undefined; + contactMailingFips: string | undefined; + contactPostDirection: string | undefined; + contactPreDirection: string | undefined; + contactState: string | undefined; + contactStreetName: string | undefined; + contactSuffix: string | undefined; + contactUnitDesignator: string | undefined; + contactValue: string | undefined; + contactZip: string | undefined; + contactZip4: string | undefined; + deedDocumentPage: string | undefined; + deedDocumentBook: string | undefined; + deedDocumentNumber: string | undefined; + deedOwnerFirstName: string | undefined; + deedOwnerFirstName2: string | undefined; + deedOwnerFirstName3: string | undefined; + deedOwnerFirstName4: string | undefined; + deedOwnerFullName: string | undefined; + deedOwnerFullName2: string | undefined; + deedOwnerFullName3: string | undefined; + deedOwnerFullName4: string | undefined; + deedOwnerLastName: string | undefined; + deedOwnerLastName2: string | undefined; + deedOwnerLastName3: string | undefined; + deedOwnerLastName4: string | undefined; + deedOwnerMiddleName: string | undefined; + deedOwnerMiddleName2: string | undefined; + deedOwnerMiddleName3: string | undefined; + deedOwnerMiddleName4: string | undefined; + deedOwnerSuffix: string | undefined; + deedOwnerSuffix2: string | undefined; + deedOwnerSuffix3: string | undefined; + deedOwnerSuffix4: string | undefined; + deedSaleDate: string | undefined; + deedSalePrice: string | undefined; + deedTransactionId: string | undefined; + disabledTaxExemption: string | undefined; + homeownerTaxExemption: string | undefined; + marketImprovementPercent: string | undefined; + marketImprovementValue: string | undefined; + marketLandValue: string | undefined; + marketValueYear: string | undefined; + matchType: string | undefined; + otherTaxExemption: string | undefined; + ownershipTransferDate: string | undefined; + ownershipTransferDocNumber: string | undefined; + ownershipTransferTransactionId: string | undefined; + ownershipType: string | undefined; + ownershipType2: string | undefined; + previousAssessedValue: string | undefined; + priorSaleAmount: string | undefined; + priorSaleDate: string | undefined; + saleAmount: string | undefined; + saleDate: string | undefined; + seniorTaxExemption: string | undefined; + taxAssessYear: string | undefined; + taxBilledAmount: string | undefined; + taxDelinquentYear: string | undefined; + taxFiscalYear: string | undefined; + taxRateArea: string | undefined; + totalMarketValue: string | undefined; + trustDescription: string | undefined; + veteranTaxExemption: string | undefined; + widowTaxExemption: string | undefined; + financialHistory: FinancialHistory[]; +} + +interface RawFinancialAttributes { + assessed_improvement_percent?: string; + assessed_improvement_value?: string; + assessed_land_value?: string; + assessed_value?: string; + assessor_last_update?: string; + assessor_taxroll_update?: string; + contact_city?: string; + contact_crrt?: string; + contact_full_address?: string; + contact_house_number?: string; + contact_main_info_format?: string; + contact_mail_info_privacy?: string; + contact_mailing_county?: string; + contact_mailing_fips?: string; + contact_post_direction?: string; + contact_pre_direction?: string; + contact_state?: string; + contact_street_name?: string; + contact_suffix?: string; + contact_unit_designator?: string; + contact_value?: string; + contact_zip?: string; + contact_zip4?: string; + deed_document_page?: string; + deed_document_book?: string; + deed_document_number?: string; + deed_owner_first_name?: string; + deed_owner_first_name2?: string; + deed_owner_first_name3?: string; + deed_owner_first_name4?: string; + deed_owner_full_name?: string; + deed_owner_full_name2?: string; + deed_owner_full_name3?: string; + deed_owner_full_name4?: string; + deed_owner_last_name?: string; + deed_owner_last_name2?: string; + deed_owner_last_name3?: string; + deed_owner_last_name4?: string; + deed_owner_middle_name?: string; + deed_owner_middle_name2?: string; + deed_owner_middle_name3?: string; + deed_owner_middle_name4?: string; + deed_owner_suffix?: string; + deed_owner_suffix2?: string; + deed_owner_suffix3?: string; + deed_owner_suffix4?: string; + deed_sale_date?: string; + deed_sale_price?: string; + deed_transaction_id?: string; + disabled_tax_exemption?: string; + homeowner_tax_exemption?: string; + market_improvement_percent?: string; + market_improvement_value?: string; + market_land_value?: string; + market_value_year?: string; + match_type?: string; + other_tax_exemption?: string; + ownership_transfer_date?: string; + ownership_transfer_doc_number?: string; + ownership_transfer_transaction_id?: string; + ownership_type?: string; + ownership_type_2?: string; + previous_assessed_value?: string; + prior_sale_amount?: string; + prior_sale_date?: string; + sale_amount?: string; + sale_date?: string; + senior_tax_exemption?: string; + tax_assess_year?: string; + tax_billed_amount?: string; + tax_delinquent_year?: string; + tax_fiscal_year?: string; + tax_rate_area?: string; + total_market_value?: string; + trust_description?: string; + veteran_tax_exemption?: string; + widow_tax_exemption?: string; + financial_history?: RawFinancialHistory[]; +} + +interface RawFinancialResponse { + smarty_key?: string; + data_set_name?: string; + data_subset_name?: string; + attributes?: RawFinancialAttributes; +} + +export interface GeoCensusBlock { + accuracy: string | undefined; + geoid: string | undefined; +} + +export interface GeoCensusCountyDivision { + accuracy: string | undefined; + code: string | undefined; + name: string | undefined; +} + +export interface GeoCensusTract { + code: string | undefined; +} + +export interface GeoCoreBasedStatArea { + code: string | undefined; + name: string | undefined; +} + +export interface GeoPlace { + accuracy: string | undefined; + code: string | undefined; + name: string | undefined; + type: string | undefined; +} + +export interface GeoAttributes { + censusBlock: GeoCensusBlock; + censusCountyDivision: GeoCensusCountyDivision; + censusTract: GeoCensusTract; + coreBasedStatArea: GeoCoreBasedStatArea; + place: GeoPlace; +} + +interface RawGeoCensusBlock { + accuracy?: string; + geoid?: string; +} + +interface RawGeoCensusCountyDivision { + accuracy?: string; + code?: string; + name?: string; +} + +interface RawGeoCensusTract { + code?: string; +} + +interface RawGeoCoreBasedStatArea { + code?: string; + name?: string; +} + +interface RawGeoPlace { + accuracy?: string; + code?: string; + name?: string; + type?: string; +} + +interface RawGeoAttributes { + census_block?: RawGeoCensusBlock; + census_county_division?: RawGeoCensusCountyDivision; + census_tract?: RawGeoCensusTract; + core_based_stat_area?: RawGeoCoreBasedStatArea; + place?: RawGeoPlace; +} + +interface RawGeoResponse { + smarty_key?: string; + data_set_name?: string; + attributes?: RawGeoAttributes; +} + export class Response { smartyKey: string; dataSetName: string; dataSubsetName: string; - attributes: Record; + attributes: EnrichmentAttributes; - constructor(responseData: Record) { - this.smartyKey = responseData.smarty_key; - this.dataSetName = responseData.data_set_name; - this.dataSubsetName = responseData.data_subset_name; + constructor(responseData: RawEnrichmentResponse) { + this.smartyKey = responseData.smarty_key ?? ""; + this.dataSetName = responseData.data_set_name ?? ""; + this.dataSubsetName = responseData.data_subset_name ?? ""; - this.attributes = {}; + this.attributes = {} as EnrichmentAttributes; if (responseData.attributes) { this.attributes.firstFloorSqft = responseData.attributes["1st_floor_sqft"]; this.attributes.secondFloorSqft = responseData.attributes["2nd_floor_sqft"]; @@ -128,7 +1204,7 @@ export class Response { this.attributes.familyRoom = responseData.attributes.family_room; this.attributes.financialHistory = !responseData.attributes.financial_history ? [] - : responseData.attributes.financial_history.map((history: Record) => { + : responseData.attributes.financial_history.map((history): FinancialHistory => { return { codeTitleCompany: history.code_title_company, instrumentDate: history.instrument_date, @@ -443,14 +1519,14 @@ export class FinancialResponse { smartyKey: string; dataSetName: string; dataSubsetName: string; - attributes: Record; + attributes: FinancialAttributes; - constructor(responseData: Record) { - this.smartyKey = responseData.smarty_key; - this.dataSetName = responseData.data_set_name; - this.dataSubsetName = responseData.data_subset_name; + constructor(responseData: RawFinancialResponse) { + this.smartyKey = responseData.smarty_key ?? ""; + this.dataSetName = responseData.data_set_name ?? ""; + this.dataSubsetName = responseData.data_subset_name ?? ""; - this.attributes = {}; + this.attributes = {} as FinancialAttributes; if (responseData.attributes) { this.attributes.assessedImprovementPercent = responseData.attributes.assessed_improvement_percent; @@ -503,10 +1579,9 @@ export class FinancialResponse { this.attributes.deedSalePrice = responseData.attributes.deed_sale_price; this.attributes.deedTransactionId = responseData.attributes.deed_transaction_id; this.attributes.disabledTaxExemption = responseData.attributes.disabled_tax_exemption; - this.attributes.financialHistory = !responseData.attributes.financial_history ? [] - : responseData.attributes.financial_history.map((history: Record) => { + : responseData.attributes.financial_history.map((history): FinancialHistory => { return { codeTitleCompany: history.code_title_company, instrumentDate: history.instrument_date, @@ -590,22 +1665,22 @@ export class FinancialResponse { export class GeoResponse { smartyKey: string; dataSetName: string; - attributes: Record; + attributes: GeoAttributes; - constructor(responseData: Record) { - this.smartyKey = responseData.smarty_key; - this.dataSetName = responseData.data_set_name; + constructor(responseData: RawGeoResponse) { + this.smartyKey = responseData.smarty_key ?? ""; + this.dataSetName = responseData.data_set_name ?? ""; - this.attributes = {}; + this.attributes = {} as GeoAttributes; if (responseData.attributes) { - const censusBlock: Record = {}; + const censusBlock: GeoCensusBlock = {} as GeoCensusBlock; if (responseData.attributes.census_block) { censusBlock.accuracy = responseData.attributes.census_block.accuracy; censusBlock.geoid = responseData.attributes.census_block.geoid; } this.attributes.censusBlock = censusBlock; - const censusCountyDivision: Record = {}; + const censusCountyDivision: GeoCensusCountyDivision = {} as GeoCensusCountyDivision; if (responseData.attributes.census_county_division) { censusCountyDivision.accuracy = responseData.attributes.census_county_division.accuracy; @@ -614,20 +1689,20 @@ export class GeoResponse { } this.attributes.censusCountyDivision = censusCountyDivision; - const censusTract: Record = {}; + const censusTract: GeoCensusTract = {} as GeoCensusTract; if (responseData.attributes.census_tract) { censusTract.code = responseData.attributes.census_tract.code; } this.attributes.censusTract = censusTract; - const coreBasedStatArea: Record = {}; + const coreBasedStatArea: GeoCoreBasedStatArea = {} as GeoCoreBasedStatArea; if (responseData.attributes.core_based_stat_area) { coreBasedStatArea.code = responseData.attributes.core_based_stat_area.code; coreBasedStatArea.name = responseData.attributes.core_based_stat_area.name; } this.attributes.coreBasedStatArea = coreBasedStatArea; - const place: Record = {}; + const place: GeoPlace = {} as GeoPlace; if (responseData.attributes.place) { place.accuracy = responseData.attributes.place.accuracy; place.code = responseData.attributes.place.code; diff --git a/src/us_extract/Address.ts b/src/us_extract/Address.ts index 43b978e..ed1c87b 100644 --- a/src/us_extract/Address.ts +++ b/src/us_extract/Address.ts @@ -1,4 +1,13 @@ -import Candidate from "../us_street/Candidate.js"; +import Candidate, { RawUsStreetCandidate } from "../us_street/Candidate.js"; + +export interface RawExtractAddress { + text?: string; + verified?: boolean; + line?: number; + start?: number; + end?: number; + api_output?: RawUsStreetCandidate[]; +} export default class Address { text: string; @@ -8,16 +17,14 @@ export default class Address { end: number; candidates: Candidate[]; - constructor(responseData: Record) { - this.text = responseData.text; - this.verified = responseData.verified; - this.line = responseData.line; - this.start = responseData.start; - this.end = responseData.end; + constructor(responseData: RawExtractAddress) { + this.text = responseData.text ?? ""; + this.verified = responseData.verified ?? false; + this.line = responseData.line ?? 0; + this.start = responseData.start ?? 0; + this.end = responseData.end ?? 0; this.candidates = responseData.api_output - ? responseData.api_output.map( - (rawAddress: Record) => new Candidate(rawAddress), - ) + ? responseData.api_output.map((rawAddress) => new Candidate(rawAddress)) : []; } } diff --git a/src/us_extract/Client.ts b/src/us_extract/Client.ts index 602d276..cc97ade 100644 --- a/src/us_extract/Client.ts +++ b/src/us_extract/Client.ts @@ -1,6 +1,7 @@ import { UndefinedLookupError } from "../Errors.js"; import Request from "../Request.js"; import Result from "./Result.js"; +import { RawExtractAddress } from "./Address.js"; import buildInputData from "../util/buildInputData.js"; import apiToSDKKeyMap from "../util/apiToSDKKeyMap.js"; import { Sender } from "../types.js"; @@ -8,6 +9,15 @@ import Lookup from "./Lookup.js"; const keyTranslationFormat = apiToSDKKeyMap.usExtract; +interface RawExtractMeta { + lines?: number; + unicode?: boolean; + address_count?: number; + verified_count?: number; + bytes?: number; + character_count?: number; +} + export default class Client { private sender: Sender; @@ -29,8 +39,8 @@ export default class Client { lookup.result = new Result( response.payload as { - meta: Record; - addresses: Record[]; + meta: RawExtractMeta; + addresses: RawExtractAddress[]; }, ); resolve(lookup); diff --git a/src/us_extract/Result.ts b/src/us_extract/Result.ts index 0571e85..16e33ba 100644 --- a/src/us_extract/Result.ts +++ b/src/us_extract/Result.ts @@ -1,4 +1,4 @@ -import Address from "./Address.js"; +import Address, { RawExtractAddress } from "./Address.js"; export interface ExtractMeta { lines: number | undefined; @@ -9,6 +9,15 @@ export interface ExtractMeta { characterCount: number | undefined; } +interface RawExtractMeta { + lines?: number; + unicode?: boolean; + address_count?: number; + verified_count?: number; + bytes?: number; + character_count?: number; +} + export default class Result { meta: ExtractMeta; addresses: Address[]; @@ -17,8 +26,8 @@ export default class Result { meta, addresses, }: { - meta: Record; - addresses: Record[]; + meta: RawExtractMeta; + addresses: RawExtractAddress[]; }) { this.meta = { lines: meta.lines, diff --git a/src/us_reverse_geo/Client.ts b/src/us_reverse_geo/Client.ts index e466f37..c38a8ed 100644 --- a/src/us_reverse_geo/Client.ts +++ b/src/us_reverse_geo/Client.ts @@ -1,5 +1,6 @@ import Request from "../Request.js"; import Response from "./Response.js"; +import { RawReverseGeoResult } from "./Result.js"; import buildInputData from "../util/buildInputData.js"; import apiToSDKKeyMap from "../util/apiToSDKKeyMap.js"; import { UndefinedLookupError } from "../Errors.js"; @@ -33,7 +34,9 @@ export default class Client { }); function attachLookupResults(response: SdkResponse, lookup: Lookup): Lookup { - lookup.response = new Response(response.payload as Record); + lookup.response = new Response( + response.payload as { results: RawReverseGeoResult[] }, + ); return lookup; } diff --git a/src/us_reverse_geo/Response.ts b/src/us_reverse_geo/Response.ts index dbe01e1..393faa4 100644 --- a/src/us_reverse_geo/Response.ts +++ b/src/us_reverse_geo/Response.ts @@ -1,13 +1,17 @@ -import Result from "./Result.js"; +import Result, { RawReverseGeoResult } from "./Result.js"; + +interface RawReverseGeoResponse { + results: RawReverseGeoResult[]; +} export default class Response { results: Result[]; - constructor(responseData?: Record) { + constructor(responseData?: RawReverseGeoResponse) { this.results = []; if (responseData) - responseData.results.forEach((rawResult: Record) => { + responseData.results.forEach((rawResult: RawReverseGeoResult) => { this.results.push(new Result(rawResult)); }); } diff --git a/src/us_reverse_geo/Result.ts b/src/us_reverse_geo/Result.ts index 3cb9452..045aed6 100644 --- a/src/us_reverse_geo/Result.ts +++ b/src/us_reverse_geo/Result.ts @@ -13,13 +13,34 @@ export interface ReverseGeoCoordinate { license: string | undefined; } +interface RawReverseGeoAddress { + street?: string; + city?: string; + state_abbreviation?: string; + zipcode?: string; + source?: string; +} + +interface RawReverseGeoCoordinate { + latitude?: number; + longitude?: number; + accuracy?: string; + license?: number; +} + +export interface RawReverseGeoResult { + distance?: number; + address?: RawReverseGeoAddress; + coordinate?: RawReverseGeoCoordinate; +} + export default class Result { distance: number; address: ReverseGeoAddress; coordinate: ReverseGeoCoordinate; - constructor(responseData: Record) { - this.distance = responseData.distance; + constructor(responseData: RawReverseGeoResult) { + this.distance = responseData.distance ?? 0; this.address = {} as ReverseGeoAddress; if (responseData.address) { diff --git a/src/us_street/Candidate.ts b/src/us_street/Candidate.ts index 0f00982..c002fd9 100644 --- a/src/us_street/Candidate.ts +++ b/src/us_street/Candidate.ts @@ -74,6 +74,96 @@ export interface UsStreetAnalysis { components: AnalysisComponents; } +interface RawUsStreetComponents { + urbanization?: string; + primary_number?: string; + street_name?: string; + street_predirection?: string; + street_postdirection?: string; + street_suffix?: string; + secondary_number?: string; + secondary_designator?: string; + extra_secondary_number?: string; + extra_secondary_designator?: string; + pmb_designator?: string; + pmb_number?: string; + city_name?: string; + default_city_name?: string; + state_abbreviation?: string; + zipcode?: string; + plus4_code?: string; + delivery_point?: string; + delivery_point_check_digit?: string; +} + +interface RawUsStreetMetadata { + record_type?: string; + zip_type?: string; + county_fips?: string; + county_name?: string; + carrier_route?: string; + congressional_district?: string; + building_default_indicator?: string; + rdi?: string; + elot_sequence?: string; + elot_sort?: string; + latitude?: number; + longitude?: number; + coordinate_license?: number; + precision?: string; + time_zone?: string; + utc_offset?: number; + dst?: boolean; + ews_match?: boolean; +} + +interface RawUsStreetAnalysisComponents { + primary_number?: string; + street_predirection?: string; + street_name?: string; + street_postdirection?: string; + street_suffix?: string; + secondary_number?: string; + secondary_designator?: string; + extra_secondary_number?: string; + extra_secondary_designator?: string; + city_name?: string; + state_abbreviation?: string; + zipcode?: string; + plus4_code?: string; + urbanization?: string; +} + +interface RawUsStreetAnalysis { + dpv_match_code?: string; + dpv_footnotes?: string; + dpv_cmra?: string; + dpv_vacant?: string; + dpv_no_stat?: string; + active?: string; + ews_match?: boolean; + footnotes?: string; + lacslink_code?: string; + lacslink_indicator?: string; + suitelink_match?: boolean; + enhanced_match?: string; + components?: RawUsStreetAnalysisComponents; +} + +export interface RawUsStreetCandidate { + input_index?: number; + candidate_index?: number; + addressee?: string; + delivery_line_1?: string; + delivery_line_2?: string; + last_line?: string; + delivery_point_barcode?: string; + smarty_key?: string; + components?: RawUsStreetComponents; + metadata?: RawUsStreetMetadata; + analysis?: RawUsStreetAnalysis; +} + export default class Candidate { inputIndex: number; candidateIndex: number; @@ -87,15 +177,15 @@ export default class Candidate { metadata: UsStreetMetadata; analysis: UsStreetAnalysis; - constructor(responseData: Record) { - this.inputIndex = responseData.input_index; - this.candidateIndex = responseData.candidate_index; - this.addressee = responseData.addressee; - this.deliveryLine1 = responseData.delivery_line_1; - this.deliveryLine2 = responseData.delivery_line_2; - this.lastLine = responseData.last_line; - this.deliveryPointBarcode = responseData.delivery_point_barcode; - this.smartyKey = responseData.smarty_key; + constructor(responseData: RawUsStreetCandidate) { + this.inputIndex = responseData.input_index ?? 0; + this.candidateIndex = responseData.candidate_index ?? 0; + this.addressee = responseData.addressee ?? ""; + this.deliveryLine1 = responseData.delivery_line_1 ?? ""; + this.deliveryLine2 = responseData.delivery_line_2 ?? ""; + this.lastLine = responseData.last_line ?? ""; + this.deliveryPointBarcode = responseData.delivery_point_barcode ?? ""; + this.smartyKey = responseData.smarty_key ?? ""; this.components = {} as UsStreetComponents; if (responseData.components !== undefined) { diff --git a/src/us_zipcode/Result.ts b/src/us_zipcode/Result.ts index 0701785..56ec6d8 100644 --- a/src/us_zipcode/Result.ts +++ b/src/us_zipcode/Result.ts @@ -26,6 +26,42 @@ export interface ZipcodeEntry { alternateCounties: AlternateCounty[]; } +interface RawAlternateCounty { + county_fips?: string; + county_name?: string; + state_abbreviation?: string; + state?: string; +} + +interface RawCityState { + city?: string; + state_abbreviation?: string; + state?: string; + mailable_city?: boolean; +} + +interface RawZipcode { + zipcode?: string; + zipcode_type?: string; + default_city?: string; + county_fips?: string; + county_name?: string; + latitude?: number; + longitude?: number; + precision?: string; + state_abbreviation?: string; + state?: string; + alternate_counties?: RawAlternateCounty[]; +} + +export interface RawZipcodeResult { + input_index?: number; + status?: string; + reason?: string; + city_states?: RawCityState[]; + zipcodes?: RawZipcode[]; +} + export default class Result { inputIndex: number; status: string | undefined; @@ -34,46 +70,46 @@ export default class Result { cities: CityEntry[]; zipcodes: ZipcodeEntry[]; - constructor(responseData: Record) { - this.inputIndex = responseData.input_index; + constructor(responseData: RawZipcodeResult) { + this.inputIndex = responseData.input_index ?? 0; this.status = responseData.status; this.reason = responseData.reason; this.valid = this.status === undefined && this.reason === undefined; this.cities = !responseData.city_states ? [] - : responseData.city_states.map((city: Record): CityEntry => { + : responseData.city_states.map((city): CityEntry => { return { - city: city.city, - stateAbbreviation: city.state_abbreviation, - state: city.state, - mailableCity: city.mailable_city, + city: city.city ?? "", + stateAbbreviation: city.state_abbreviation ?? "", + state: city.state ?? "", + mailableCity: city.mailable_city ?? false, }; }); this.zipcodes = !responseData.zipcodes ? [] - : responseData.zipcodes.map((zipcode: Record): ZipcodeEntry => { + : responseData.zipcodes.map((zipcode): ZipcodeEntry => { return { - zipcode: zipcode.zipcode, - zipcodeType: zipcode.zipcode_type, - defaultCity: zipcode.default_city, - countyFips: zipcode.county_fips, - countyName: zipcode.county_name, - latitude: zipcode.latitude, - longitude: zipcode.longitude, - precision: zipcode.precision, - stateAbbreviation: zipcode.state_abbreviation, - state: zipcode.state, + zipcode: zipcode.zipcode ?? "", + zipcodeType: zipcode.zipcode_type ?? "", + defaultCity: zipcode.default_city ?? "", + countyFips: zipcode.county_fips ?? "", + countyName: zipcode.county_name ?? "", + latitude: zipcode.latitude ?? 0, + longitude: zipcode.longitude ?? 0, + precision: zipcode.precision ?? "", + stateAbbreviation: zipcode.state_abbreviation ?? "", + state: zipcode.state ?? "", alternateCounties: !zipcode.alternate_counties ? [] : zipcode.alternate_counties.map( - (county: Record): AlternateCounty => { + (county): AlternateCounty => { return { - countyFips: county.county_fips, - countyName: county.county_name, - stateAbbreviation: county.state_abbreviation, - state: county.state, + countyFips: county.county_fips ?? "", + countyName: county.county_name ?? "", + stateAbbreviation: county.state_abbreviation ?? "", + state: county.state ?? "", }; }, ), diff --git a/src/util/apiToSDKKeyMap.ts b/src/util/apiToSDKKeyMap.ts index bb62bb5..33af33f 100644 --- a/src/util/apiToSDKKeyMap.ts +++ b/src/util/apiToSDKKeyMap.ts @@ -1,4 +1,16 @@ -const apiToSDKKeyMap: Record> = { +interface ApiToSDKKeyMap { + usStreet: Record; + usAutocompletePro: Record; + usZipcode: Record; + internationalStreet: Record; + internationalAddressAutocomplete: Record; + usReverseGeo: Record; + usExtract: Record; + usEnrichment: Record; + internationalPostalCode: Record; +} + +const apiToSDKKeyMap: ApiToSDKKeyMap = { usStreet: { street: "street", street2: "street2", diff --git a/src/util/buildInputData.ts b/src/util/buildInputData.ts index a9892bc..b295daf 100644 --- a/src/util/buildInputData.ts +++ b/src/util/buildInputData.ts @@ -1,7 +1,12 @@ import InputData from "../InputData.js"; +interface LookupLike { + customParameters?: Record; + [key: string]: any; +} + export default function buildInputData( - lookup: Record, + lookup: LookupLike, keyTranslationFormat: Record, ): Record { const inputData = new InputData(lookup); diff --git a/src/util/buildSmartyResponse.ts b/src/util/buildSmartyResponse.ts index 3078096..b2f1e12 100644 --- a/src/util/buildSmartyResponse.ts +++ b/src/util/buildSmartyResponse.ts @@ -1,6 +1,13 @@ import Response from "../Response.js"; -export function buildSmartyResponse(response?: Record, error?: Error): Response { +interface AxiosLikeResponse { + status: number; + data?: object[] | object | string | null | undefined; + error?: any; + headers?: Record | undefined; +} + +export function buildSmartyResponse(response?: AxiosLikeResponse, error?: Error): Response { if (response) return new Response(response.status, response.data, response.error, response.headers); return new Response(0, null, error); diff --git a/src/util/buildUsStreetInputData.ts b/src/util/buildUsStreetInputData.ts index fb670c8..6e2f6b4 100644 --- a/src/util/buildUsStreetInputData.ts +++ b/src/util/buildUsStreetInputData.ts @@ -1,9 +1,10 @@ import buildInputData from "./buildInputData.js"; import apiToSDKKeyMap from "./apiToSDKKeyMap.js"; +import Lookup from "../us_street/Lookup.js"; const keyTranslationFormat = apiToSDKKeyMap.usStreet; -export default function buildUsStreetInputData(lookup: Record): Record { +export default function buildUsStreetInputData(lookup: Lookup): Record { // Apply default match strategy and candidates logic per Go SDK behavior let effectiveMatch = lookup.match; let effectiveCandidates = lookup.maxCandidates; diff --git a/src/util/sendBatch.ts b/src/util/sendBatch.ts index 352eac6..ccac4ee 100644 --- a/src/util/sendBatch.ts +++ b/src/util/sendBatch.ts @@ -9,7 +9,7 @@ export default function sendBatch( sender: Sender, Result: new (data: any) => { inputIndex: number }, keyTranslationFormat: Record | null, - customBuildInputData?: (lookup: Record) => Record, + customBuildInputData?: (lookup: any) => Record, ): Promise { if (batch.isEmpty()) throw new BatchEmptyError(); @@ -32,9 +32,9 @@ export default function sendBatch( function generateRequestPayload(batch: Batch): Record[] { return batch.lookups.map((lookup) => { if (customBuildInputData) { - return customBuildInputData(lookup as Record); + return customBuildInputData(lookup); } - return buildInputData(lookup as Record, keyTranslationFormat!); + return buildInputData(lookup, keyTranslationFormat!); }); } diff --git a/tests/international_postal_code/test_Lookup.ts b/tests/international_postal_code/test_Lookup.ts index 2314109..98a86ee 100644 --- a/tests/international_postal_code/test_Lookup.ts +++ b/tests/international_postal_code/test_Lookup.ts @@ -18,6 +18,6 @@ describe("An International Postal Code lookup", function () { let lookup = new Lookup("Brazil", "02516-040"); lookup.addCustomParameter("test", "value"); - expect(lookup.customParameters.test).to.equal("value"); + expect(lookup.customParameters["test"]).to.equal("value"); }); }); diff --git a/tests/international_postal_code/test_Result.ts b/tests/international_postal_code/test_Result.ts index 3f1226c..9f723d3 100644 --- a/tests/international_postal_code/test_Result.ts +++ b/tests/international_postal_code/test_Result.ts @@ -42,9 +42,9 @@ describe("An International Postal Code result", function () { const result = new Result(sampleResponse); - expect(result.inputId).to.equal(undefined); - expect(result.superAdministrativeArea).to.equal(undefined); - expect(result.postalCodeExtra).to.equal(undefined); + expect(result.inputId).to.equal(""); + expect(result.superAdministrativeArea).to.equal(""); + expect(result.postalCodeExtra).to.equal(""); expect(result.administrativeArea).to.equal("SP"); expect(result.locality).to.equal("São Paulo"); expect(result.postalCode).to.equal("02516-040"); diff --git a/tests/test_ExtractExample.ts b/tests/test_ExtractExample.ts index d747694..ae100af 100644 --- a/tests/test_ExtractExample.ts +++ b/tests/test_ExtractExample.ts @@ -1,5 +1,5 @@ import { expect } from "chai"; -import * as SmartySDK from "../dist/esm/index.mjs"; +import * as SmartySDK from "../index.js"; describe("Extract example test", () => { const authId = ""; diff --git a/tests/test_HttpSender.ts b/tests/test_HttpSender.ts index cbfa971..e69cf3a 100644 --- a/tests/test_HttpSender.ts +++ b/tests/test_HttpSender.ts @@ -49,7 +49,7 @@ describe("An Axios implementation of a HTTP sender", function () { it("adds parameters to the HTTP request config.", function () { let request = new Request(""); let sender = new HttpSender(); - request.parameters.test = "1"; + request.parameters["test"] = "1"; let requestConfig = sender.buildRequestConfig(request); expect(requestConfig.hasOwnProperty("params")).to.equal(true); diff --git a/tests/us_autocomplete_pro/test_Client.ts b/tests/us_autocomplete_pro/test_Client.ts index 7c3c36a..6af06f0 100644 --- a/tests/us_autocomplete_pro/test_Client.ts +++ b/tests/us_autocomplete_pro/test_Client.ts @@ -96,12 +96,12 @@ describe("A US Autocomplete Pro Client", function () { it("attaches suggestions from a response to a lookup.", function () { const responseData = { - streetLine: "a", + street_line: "a", secondary: "b", city: "c", state: "d", zipcode: "e", - entries: "f", + entries: 6, }; let mockExpectedPayload = { suggestions: [responseData] }; let mockSender = new MockSenderWithResponse(mockExpectedPayload); diff --git a/tests/us_autocomplete_pro/test_Suggestion.ts b/tests/us_autocomplete_pro/test_Suggestion.ts index 94c4723..009aea7 100644 --- a/tests/us_autocomplete_pro/test_Suggestion.ts +++ b/tests/us_autocomplete_pro/test_Suggestion.ts @@ -9,7 +9,7 @@ describe("A US Autocomplete Pro Suggestion", function () { city: "c", state: "d", zipcode: "e", - entries: "f", + entries: 6, }; let suggestion = new Suggestion(mockSuggestion); @@ -18,6 +18,6 @@ describe("A US Autocomplete Pro Suggestion", function () { expect(suggestion.city).to.equal("c"); expect(suggestion.state).to.equal("d"); expect(suggestion.zipcode).to.equal("e"); - expect(suggestion.entries).to.equal("f"); + expect(suggestion.entries).to.equal(6); }); }); diff --git a/tests/us_street/test_Candidate.ts b/tests/us_street/test_Candidate.ts index d8d99de..580bd93 100644 --- a/tests/us_street/test_Candidate.ts +++ b/tests/us_street/test_Candidate.ts @@ -50,8 +50,8 @@ describe("A match candidate", function () { precision: "38", time_zone: "39", utc_offset: 40.0, - dst: "41", - ews_match: "47", + dst: true, + ews_match: true, }, analysis: { dpv_match_code: "42", @@ -62,7 +62,7 @@ describe("A match candidate", function () { footnotes: "48", lacslink_code: "49", lacslink_indicator: "50", - suitelink_match: "51", + suitelink_match: true, dpv_no_stat: "52", enhanced_match: "53", components: { @@ -130,8 +130,8 @@ describe("A match candidate", function () { expect(candidate.metadata.precision).to.equal("38"); expect(candidate.metadata.timeZone).to.equal("39"); expect(candidate.metadata.utcOffset).to.equal(40.0); - expect(candidate.metadata.obeysDst).to.equal("41"); - expect(candidate.metadata.isEwsMatch).to.equal("47"); + expect(candidate.metadata.obeysDst).to.equal(true); + expect(candidate.metadata.isEwsMatch).to.equal(true); expect(candidate.analysis.dpvMatchCode).to.equal("42"); expect(candidate.analysis.dpvFootnotes).to.equal("43"); @@ -141,7 +141,7 @@ describe("A match candidate", function () { expect(candidate.analysis.footnotes).to.equal("48"); expect(candidate.analysis.lacsLinkCode).to.equal("49"); expect(candidate.analysis.lacsLinkIndicator).to.equal("50"); - expect(candidate.analysis.isSuiteLinkMatch).to.equal("51"); + expect(candidate.analysis.isSuiteLinkMatch).to.equal(true); expect(candidate.analysis.noStat).to.equal("52"); expect(candidate.analysis.enhancedMatch).to.equal("53"); diff --git a/tests/us_zipcode/test_Result.ts b/tests/us_zipcode/test_Result.ts index e0a1c77..81bf493 100644 --- a/tests/us_zipcode/test_Result.ts +++ b/tests/us_zipcode/test_Result.ts @@ -10,7 +10,7 @@ describe("A US Zipcode result", function () { city: "1", state_abbreviation: "2", state: "3", - mailable_city: "4", + mailable_city: true, }, ], zipcodes: [ @@ -45,7 +45,7 @@ describe("A US Zipcode result", function () { expect(result.cities[0].city).to.equal("1"); expect(result.cities[0].stateAbbreviation).to.equal("2"); expect(result.cities[0].state).to.equal("3"); - expect(result.cities[0].mailableCity).to.equal("4"); + expect(result.cities[0].mailableCity).to.equal(true); expect(result.zipcodes[0].zipcode).to.equal("5"); expect(result.zipcodes[0].zipcodeType).to.equal("6"); diff --git a/tsconfig.json b/tsconfig.json index 8aeb2fd..f08e793 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -9,6 +9,7 @@ }, "alwaysStrict": true, "exactOptionalPropertyTypes": true, + "noPropertyAccessFromIndexSignature": true, "noImplicitAny": true, "noImplicitReturns": true, "noImplicitOverride": true, From aa3288a535ba5ffef76cb673b1fe1f75a6a90339 Mon Sep 17 00:00:00 2001 From: Ryan Cox Date: Tue, 3 Mar 2026 15:48:24 -0700 Subject: [PATCH 26/29] A little more strict on the types. --- index.ts | 4 + src/international_street/Lookup.ts | 7 +- src/us_autocomplete_pro/Lookup.ts | 4 +- src/us_reverse_geo/Result.ts | 7 +- src/us_street/Candidate.ts | 136 ++++++++++++++++++---------- src/us_street/Lookup.ts | 16 ++-- tests/us_reverse_geo/test_Client.ts | 1 + tests/us_street/test_Candidate.ts | 86 ++++++++++++------ 8 files changed, 173 insertions(+), 88 deletions(-) diff --git a/index.ts b/index.ts index e44c95b..cca3b77 100644 --- a/index.ts +++ b/index.ts @@ -38,6 +38,10 @@ import ResultInternationalPostalCode from "./src/international_postal_code/Resul export type { Request, Response, Sender, Sleeper, Signer } from "./src/types.js"; export { SmartyError } from "./src/Errors.js"; +export type { MatchStrategy, OutputFormat, CountySource } from "./src/us_street/Lookup.js"; +export type { CoordinateLicense, MatchInfo } from "./src/us_street/Candidate.js"; +export type { Geolocation } from "./src/us_autocomplete_pro/Lookup.js"; +export type { Language, Geocode } from "./src/international_street/Lookup.js"; export const core = { Batch, diff --git a/src/international_street/Lookup.ts b/src/international_street/Lookup.ts index e32ae29..201e50a 100644 --- a/src/international_street/Lookup.ts +++ b/src/international_street/Lookup.ts @@ -1,6 +1,9 @@ import Candidate from "./Candidate.js"; import { UnprocessableEntityError } from "../Errors.js"; +export type Language = "native" | "latin" | (string & {}); +export type Geocode = "true" | (string & {}); + const messages = { countryRequired: "Country field is required.", freeformOrAddress1Required: "Either freeform or address1 is required.", @@ -35,8 +38,8 @@ export default class Lookup { locality: string | undefined; administrativeArea: string | undefined; postalCode: string | undefined; - geocode: string | undefined; - language: string | undefined; + geocode: Geocode | undefined; + language: Language | undefined; inputId: string | undefined; customParameters: Record; diff --git a/src/us_autocomplete_pro/Lookup.ts b/src/us_autocomplete_pro/Lookup.ts index 53a4e8f..05298fa 100644 --- a/src/us_autocomplete_pro/Lookup.ts +++ b/src/us_autocomplete_pro/Lookup.ts @@ -1,5 +1,7 @@ import Suggestion from "./Suggestion.js"; +export type Geolocation = "city" | "none" | (string & {}); + export default class Lookup { result: Suggestion[]; search: string | undefined; @@ -13,7 +15,7 @@ export default class Lookup { preferStates: string[]; preferZIPCodes: string[]; preferRatio: number | undefined; - preferGeolocation: string | undefined; + preferGeolocation: Geolocation | undefined; source: string | undefined; customParameters: Record; diff --git a/src/us_reverse_geo/Result.ts b/src/us_reverse_geo/Result.ts index 045aed6..519f6b6 100644 --- a/src/us_reverse_geo/Result.ts +++ b/src/us_reverse_geo/Result.ts @@ -1,16 +1,19 @@ +import type { CoordinateLicense } from "../us_street/Candidate.js"; + export interface ReverseGeoAddress { street: string | undefined; city: string | undefined; stateAbbreviation: string | undefined; zipcode: string | undefined; source: string | undefined; + smartyKey: string | undefined; } export interface ReverseGeoCoordinate { latitude: number | undefined; longitude: number | undefined; accuracy: string | undefined; - license: string | undefined; + license: CoordinateLicense | undefined; } interface RawReverseGeoAddress { @@ -19,6 +22,7 @@ interface RawReverseGeoAddress { state_abbreviation?: string; zipcode?: string; source?: string; + smarty_key?: string; } interface RawReverseGeoCoordinate { @@ -49,6 +53,7 @@ export default class Result { this.address.stateAbbreviation = responseData.address.state_abbreviation; this.address.zipcode = responseData.address.zipcode; this.address.source = responseData.address.source; + this.address.smartyKey = responseData.address.smarty_key; } this.coordinate = {} as ReverseGeoCoordinate; diff --git a/src/us_street/Candidate.ts b/src/us_street/Candidate.ts index c002fd9..f3463d2 100644 --- a/src/us_street/Candidate.ts +++ b/src/us_street/Candidate.ts @@ -1,3 +1,10 @@ +export type CoordinateLicense = "SmartyStreets" | "SmartyStreets Proprietary" | (string & {}); + +export interface MatchInfo { + status: string | undefined; + change: string[] | undefined; +} + export interface UsStreetComponents { urbanization: string | undefined; primaryNumber: string | undefined; @@ -33,7 +40,7 @@ export interface UsStreetMetadata { elotSort: string | undefined; latitude: number | undefined; longitude: number | undefined; - coordinateLicense: string | undefined; + coordinateLicense: CoordinateLicense | undefined; precision: string | undefined; timeZone: string | undefined; utcOffset: number | undefined; @@ -42,20 +49,20 @@ export interface UsStreetMetadata { } export interface AnalysisComponents { - primaryNumber: string | undefined; - streetPredirection: string | undefined; - streetName: string | undefined; - streetPostdirection: string | undefined; - streetSuffix: string | undefined; - secondaryNumber: string | undefined; - secondaryDesignator: string | undefined; - extraSecondaryNumber: string | undefined; - extraSecondaryDesignator: string | undefined; - cityName: string | undefined; - stateAbbreviation: string | undefined; - zipCode: string | undefined; - plus4Code: string | undefined; - urbanization: string | undefined; + primaryNumber: MatchInfo; + streetPredirection: MatchInfo; + streetName: MatchInfo; + streetPostdirection: MatchInfo; + streetSuffix: MatchInfo; + secondaryNumber: MatchInfo; + secondaryDesignator: MatchInfo; + extraSecondaryNumber: MatchInfo; + extraSecondaryDesignator: MatchInfo; + cityName: MatchInfo; + stateAbbreviation: MatchInfo; + zipCode: MatchInfo; + plus4Code: MatchInfo; + urbanization: MatchInfo; } export interface UsStreetAnalysis { @@ -117,21 +124,26 @@ interface RawUsStreetMetadata { ews_match?: boolean; } +interface RawMatchInfo { + status?: string; + change?: string[]; +} + interface RawUsStreetAnalysisComponents { - primary_number?: string; - street_predirection?: string; - street_name?: string; - street_postdirection?: string; - street_suffix?: string; - secondary_number?: string; - secondary_designator?: string; - extra_secondary_number?: string; - extra_secondary_designator?: string; - city_name?: string; - state_abbreviation?: string; - zipcode?: string; - plus4_code?: string; - urbanization?: string; + primary_number?: RawMatchInfo; + street_predirection?: RawMatchInfo; + street_name?: RawMatchInfo; + street_postdirection?: RawMatchInfo; + street_suffix?: RawMatchInfo; + secondary_number?: RawMatchInfo; + secondary_designator?: RawMatchInfo; + extra_secondary_number?: RawMatchInfo; + extra_secondary_designator?: RawMatchInfo; + city_name?: RawMatchInfo; + state_abbreviation?: RawMatchInfo; + zipcode?: RawMatchInfo; + plus4_code?: RawMatchInfo; + urbanization?: RawMatchInfo; } interface RawUsStreetAnalysis { @@ -151,6 +163,7 @@ interface RawUsStreetAnalysis { } export interface RawUsStreetCandidate { + input_id?: string; input_index?: number; candidate_index?: number; addressee?: string; @@ -165,6 +178,7 @@ export interface RawUsStreetCandidate { } export default class Candidate { + inputId: string; inputIndex: number; candidateIndex: number; addressee: string; @@ -178,6 +192,7 @@ export default class Candidate { analysis: UsStreetAnalysis; constructor(responseData: RawUsStreetCandidate) { + this.inputId = responseData.input_id ?? ""; this.inputIndex = responseData.input_index ?? 0; this.candidateIndex = responseData.candidate_index ?? 0; this.addressee = responseData.addressee ?? ""; @@ -254,27 +269,48 @@ export default class Candidate { this.analysis.enhancedMatch = responseData.analysis.enhanced_match; this.analysis.components = {} as AnalysisComponents; if (responseData.analysis.components !== undefined) { - this.analysis.components.primaryNumber = responseData.analysis.components.primary_number; - this.analysis.components.streetPredirection = - responseData.analysis.components.street_predirection; - this.analysis.components.streetName = responseData.analysis.components.street_name; - this.analysis.components.streetPostdirection = - responseData.analysis.components.street_postdirection; - this.analysis.components.streetSuffix = responseData.analysis.components.street_suffix; - this.analysis.components.secondaryNumber = - responseData.analysis.components.secondary_number; - this.analysis.components.secondaryDesignator = - responseData.analysis.components.secondary_designator; - this.analysis.components.extraSecondaryNumber = - responseData.analysis.components.extra_secondary_number; - this.analysis.components.extraSecondaryDesignator = - responseData.analysis.components.extra_secondary_designator; - this.analysis.components.cityName = responseData.analysis.components.city_name; - this.analysis.components.stateAbbreviation = - responseData.analysis.components.state_abbreviation; - this.analysis.components.zipCode = responseData.analysis.components.zipcode; - this.analysis.components.plus4Code = responseData.analysis.components.plus4_code; - this.analysis.components.urbanization = responseData.analysis.components.urbanization; + const toMatchInfo = (raw?: RawMatchInfo): MatchInfo => ({ + status: raw?.status, + change: raw?.change, + }); + this.analysis.components.primaryNumber = toMatchInfo( + responseData.analysis.components.primary_number, + ); + this.analysis.components.streetPredirection = toMatchInfo( + responseData.analysis.components.street_predirection, + ); + this.analysis.components.streetName = toMatchInfo( + responseData.analysis.components.street_name, + ); + this.analysis.components.streetPostdirection = toMatchInfo( + responseData.analysis.components.street_postdirection, + ); + this.analysis.components.streetSuffix = toMatchInfo( + responseData.analysis.components.street_suffix, + ); + this.analysis.components.secondaryNumber = toMatchInfo( + responseData.analysis.components.secondary_number, + ); + this.analysis.components.secondaryDesignator = toMatchInfo( + responseData.analysis.components.secondary_designator, + ); + this.analysis.components.extraSecondaryNumber = toMatchInfo( + responseData.analysis.components.extra_secondary_number, + ); + this.analysis.components.extraSecondaryDesignator = toMatchInfo( + responseData.analysis.components.extra_secondary_designator, + ); + this.analysis.components.cityName = toMatchInfo(responseData.analysis.components.city_name); + this.analysis.components.stateAbbreviation = toMatchInfo( + responseData.analysis.components.state_abbreviation, + ); + this.analysis.components.zipCode = toMatchInfo(responseData.analysis.components.zipcode); + this.analysis.components.plus4Code = toMatchInfo( + responseData.analysis.components.plus4_code, + ); + this.analysis.components.urbanization = toMatchInfo( + responseData.analysis.components.urbanization, + ); } } } diff --git a/src/us_street/Lookup.ts b/src/us_street/Lookup.ts index 9f86576..c904200 100644 --- a/src/us_street/Lookup.ts +++ b/src/us_street/Lookup.ts @@ -1,5 +1,9 @@ import Candidate from "./Candidate.js"; +export type MatchStrategy = "strict" | "invalid" | "enhanced" | (string & {}); +export type OutputFormat = "default" | "project-usa" | (string & {}); +export type CountySource = "postal" | "geographic" | (string & {}); + export default class Lookup { street: string | undefined; street2: string | undefined; @@ -10,11 +14,11 @@ export default class Lookup { lastLine: string | undefined; addressee: string | undefined; urbanization: string | undefined; - match: string | undefined; + match: MatchStrategy | undefined; maxCandidates: number | undefined; inputId: string | undefined; - format: string | undefined; - countySource: string | undefined; + format: OutputFormat | undefined; + countySource: CountySource | undefined; result: Candidate[]; customParameters: Record; @@ -28,11 +32,11 @@ export default class Lookup { lastLine?: string, addressee?: string, urbanization?: string, - match?: string, + match?: MatchStrategy, maxCandidates?: number, inputId?: string, - format?: string, - countySource?: string, + format?: OutputFormat, + countySource?: CountySource, ) { this.street = street; this.street2 = street2; diff --git a/tests/us_reverse_geo/test_Client.ts b/tests/us_reverse_geo/test_Client.ts index ad45d49..80cebc1 100644 --- a/tests/us_reverse_geo/test_Client.ts +++ b/tests/us_reverse_geo/test_Client.ts @@ -42,6 +42,7 @@ describe("A US Reverse Geo client", function () { stateAbbreviation: "UT", zipcode: "84606", source: "postal", + smartyKey: undefined, }, }, ], diff --git a/tests/us_street/test_Candidate.ts b/tests/us_street/test_Candidate.ts index 580bd93..1563bf2 100644 --- a/tests/us_street/test_Candidate.ts +++ b/tests/us_street/test_Candidate.ts @@ -66,20 +66,20 @@ describe("A match candidate", function () { dpv_no_stat: "52", enhanced_match: "53", components: { - primary_number: "54", - street_predirection: "55", - street_name: "56", - street_postdirection: "57", - street_suffix: "58", - secondary_number: "59", - secondary_designator: "60", - extra_secondary_number: "61", - extra_secondary_designator: "62", - city_name: "63", - state_abbreviation: "64", - zipcode: "65", - plus4_code: "66", - urbanization: "67", + primary_number: { status: "54", change: ["a"] }, + street_predirection: { status: "55", change: ["b"] }, + street_name: { status: "56", change: ["c"] }, + street_postdirection: { status: "57", change: ["d"] }, + street_suffix: { status: "58", change: ["e"] }, + secondary_number: { status: "59", change: ["f"] }, + secondary_designator: { status: "60", change: ["g"] }, + extra_secondary_number: { status: "61", change: ["h"] }, + extra_secondary_designator: { status: "62", change: ["i"] }, + city_name: { status: "63", change: ["j"] }, + state_abbreviation: { status: "64", change: ["k"] }, + zipcode: { status: "65", change: ["l"] }, + plus4_code: { status: "66", change: ["m"] }, + urbanization: { status: "67", change: ["n"] }, }, }, }; @@ -145,19 +145,49 @@ describe("A match candidate", function () { expect(candidate.analysis.noStat).to.equal("52"); expect(candidate.analysis.enhancedMatch).to.equal("53"); - expect(candidate.analysis.components.primaryNumber).to.equal("54"); - expect(candidate.analysis.components.streetPredirection).to.equal("55"); - expect(candidate.analysis.components.streetName).to.equal("56"); - expect(candidate.analysis.components.streetPostdirection).to.equal("57"); - expect(candidate.analysis.components.streetSuffix).to.equal("58"); - expect(candidate.analysis.components.secondaryNumber).to.equal("59"); - expect(candidate.analysis.components.secondaryDesignator).to.equal("60"); - expect(candidate.analysis.components.extraSecondaryNumber).to.equal("61"); - expect(candidate.analysis.components.extraSecondaryDesignator).to.equal("62"); - expect(candidate.analysis.components.cityName).to.equal("63"); - expect(candidate.analysis.components.stateAbbreviation).to.equal("64"); - expect(candidate.analysis.components.zipCode).to.equal("65"); - expect(candidate.analysis.components.plus4Code).to.equal("66"); - expect(candidate.analysis.components.urbanization).to.equal("67"); + expect(candidate.analysis.components.primaryNumber).to.deep.equal({ + status: "54", + change: ["a"], + }); + expect(candidate.analysis.components.streetPredirection).to.deep.equal({ + status: "55", + change: ["b"], + }); + expect(candidate.analysis.components.streetName).to.deep.equal({ status: "56", change: ["c"] }); + expect(candidate.analysis.components.streetPostdirection).to.deep.equal({ + status: "57", + change: ["d"], + }); + expect(candidate.analysis.components.streetSuffix).to.deep.equal({ + status: "58", + change: ["e"], + }); + expect(candidate.analysis.components.secondaryNumber).to.deep.equal({ + status: "59", + change: ["f"], + }); + expect(candidate.analysis.components.secondaryDesignator).to.deep.equal({ + status: "60", + change: ["g"], + }); + expect(candidate.analysis.components.extraSecondaryNumber).to.deep.equal({ + status: "61", + change: ["h"], + }); + expect(candidate.analysis.components.extraSecondaryDesignator).to.deep.equal({ + status: "62", + change: ["i"], + }); + expect(candidate.analysis.components.cityName).to.deep.equal({ status: "63", change: ["j"] }); + expect(candidate.analysis.components.stateAbbreviation).to.deep.equal({ + status: "64", + change: ["k"], + }); + expect(candidate.analysis.components.zipCode).to.deep.equal({ status: "65", change: ["l"] }); + expect(candidate.analysis.components.plus4Code).to.deep.equal({ status: "66", change: ["m"] }); + expect(candidate.analysis.components.urbanization).to.deep.equal({ + status: "67", + change: ["n"], + }); }); }); From f18c6e1a6a7b66e361db670e0a3f6f10410a9181 Mon Sep 17 00:00:00 2001 From: Ryan Cox Date: Tue, 3 Mar 2026 15:53:27 -0700 Subject: [PATCH 27/29] Run prettier. --- src/StatusCodeSender.ts | 4 +--- .../Client.ts | 4 +--- src/international_postal_code/Client.ts | 4 +--- src/us_autocomplete_pro/Client.ts | 4 +--- src/us_enrichment/Response.ts | 3 +-- src/us_extract/Result.ts | 8 +------- src/us_reverse_geo/Client.ts | 4 +--- src/us_zipcode/Result.ts | 18 ++++++++---------- tests/fixtures/mock_senders.ts | 11 ++--------- 9 files changed, 17 insertions(+), 43 deletions(-) diff --git a/src/StatusCodeSender.ts b/src/StatusCodeSender.ts index c1c1dca..f32b301 100644 --- a/src/StatusCodeSender.ts +++ b/src/StatusCodeSender.ts @@ -36,9 +36,7 @@ export default class StatusCodeSender { const payload = error.payload as { errors?: { message?: string }[]; } | null; - error.error = new DefaultError( - payload?.errors?.[0]?.message, - ); + error.error = new DefaultError(payload?.errors?.[0]?.message); } } reject(error); diff --git a/src/international_address_autocomplete/Client.ts b/src/international_address_autocomplete/Client.ts index b85008a..10ede64 100644 --- a/src/international_address_autocomplete/Client.ts +++ b/src/international_address_autocomplete/Client.ts @@ -37,9 +37,7 @@ export default class Client { lookup.result = !payload || payload.candidates === null ? [] - : payload.candidates.map( - (suggestion) => new Suggestion(suggestion), - ); + : payload.candidates.map((suggestion) => new Suggestion(suggestion)); resolve(lookup); }) .catch(reject); diff --git a/src/international_postal_code/Client.ts b/src/international_postal_code/Client.ts index 5d82092..f453c00 100644 --- a/src/international_postal_code/Client.ts +++ b/src/international_postal_code/Client.ts @@ -34,9 +34,7 @@ export default class Client { function attachLookupResults(response: Response, lookup: Lookup): Lookup { if (response.payload && Array.isArray(response.payload)) { - lookup.result = (response.payload as RawIntlPostalCodeResult[]).map( - (r) => new Result(r), - ); + lookup.result = (response.payload as RawIntlPostalCodeResult[]).map((r) => new Result(r)); } else { lookup.result = []; } diff --git a/src/us_autocomplete_pro/Client.ts b/src/us_autocomplete_pro/Client.ts index a5efda6..390528c 100644 --- a/src/us_autocomplete_pro/Client.ts +++ b/src/us_autocomplete_pro/Client.ts @@ -33,9 +33,7 @@ export default class Client { lookup.result = payload.suggestions === null ? [] - : payload.suggestions.map( - (suggestion) => new Suggestion(suggestion), - ); + : payload.suggestions.map((suggestion) => new Suggestion(suggestion)); resolve(lookup); }) .catch(reject); diff --git a/src/us_enrichment/Response.ts b/src/us_enrichment/Response.ts index a95fff0..9775a7f 100644 --- a/src/us_enrichment/Response.ts +++ b/src/us_enrichment/Response.ts @@ -1682,8 +1682,7 @@ export class GeoResponse { const censusCountyDivision: GeoCensusCountyDivision = {} as GeoCensusCountyDivision; if (responseData.attributes.census_county_division) { - censusCountyDivision.accuracy = - responseData.attributes.census_county_division.accuracy; + censusCountyDivision.accuracy = responseData.attributes.census_county_division.accuracy; censusCountyDivision.code = responseData.attributes.census_county_division.code; censusCountyDivision.name = responseData.attributes.census_county_division.name; } diff --git a/src/us_extract/Result.ts b/src/us_extract/Result.ts index 16e33ba..e5fb2a2 100644 --- a/src/us_extract/Result.ts +++ b/src/us_extract/Result.ts @@ -22,13 +22,7 @@ export default class Result { meta: ExtractMeta; addresses: Address[]; - constructor({ - meta, - addresses, - }: { - meta: RawExtractMeta; - addresses: RawExtractAddress[]; - }) { + constructor({ meta, addresses }: { meta: RawExtractMeta; addresses: RawExtractAddress[] }) { this.meta = { lines: meta.lines, unicode: meta.unicode, diff --git a/src/us_reverse_geo/Client.ts b/src/us_reverse_geo/Client.ts index c38a8ed..d2118bf 100644 --- a/src/us_reverse_geo/Client.ts +++ b/src/us_reverse_geo/Client.ts @@ -34,9 +34,7 @@ export default class Client { }); function attachLookupResults(response: SdkResponse, lookup: Lookup): Lookup { - lookup.response = new Response( - response.payload as { results: RawReverseGeoResult[] }, - ); + lookup.response = new Response(response.payload as { results: RawReverseGeoResult[] }); return lookup; } diff --git a/src/us_zipcode/Result.ts b/src/us_zipcode/Result.ts index 56ec6d8..5d704d9 100644 --- a/src/us_zipcode/Result.ts +++ b/src/us_zipcode/Result.ts @@ -103,16 +103,14 @@ export default class Result { state: zipcode.state ?? "", alternateCounties: !zipcode.alternate_counties ? [] - : zipcode.alternate_counties.map( - (county): AlternateCounty => { - return { - countyFips: county.county_fips ?? "", - countyName: county.county_name ?? "", - stateAbbreviation: county.state_abbreviation ?? "", - state: county.state ?? "", - }; - }, - ), + : zipcode.alternate_counties.map((county): AlternateCounty => { + return { + countyFips: county.county_fips ?? "", + countyName: county.county_name ?? "", + stateAbbreviation: county.state_abbreviation ?? "", + state: county.state ?? "", + }; + }), }; }); } diff --git a/tests/fixtures/mock_senders.ts b/tests/fixtures/mock_senders.ts index 6b4e614..4ab6ed2 100644 --- a/tests/fixtures/mock_senders.ts +++ b/tests/fixtures/mock_senders.ts @@ -29,10 +29,7 @@ export class MockSenderWithResponse { private expectedPayload: object[] | object | string | null; private expectedError: Error | null; - constructor( - expectedPayload: object[] | object | string | null, - expectedError?: Error | null, - ) { + constructor(expectedPayload: object[] | object | string | null, expectedError?: Error | null) { this.expectedPayload = expectedPayload; this.expectedError = expectedError ?? null; } @@ -50,11 +47,7 @@ export class MockSenderWithStatusCodesAndHeaders { error: string | undefined; currentStatusCodeIndex: number; - constructor( - statusCodes: number[], - headers?: Record, - error?: string, - ) { + constructor(statusCodes: number[], headers?: Record, error?: string) { this.statusCodes = statusCodes; this.headers = headers; this.error = error; From b1311db51f8699a66a26501178aea528c8cba83c Mon Sep 17 00:00:00 2001 From: Ryan Cox Date: Tue, 3 Mar 2026 16:14:33 -0700 Subject: [PATCH 28/29] Updated README --- README.md | 145 +++++++++++++++++++++++++++++++++++++++++++++++++++ Readme.md | 11 ---- package.json | 2 +- 3 files changed, 146 insertions(+), 12 deletions(-) create mode 100644 README.md delete mode 100644 Readme.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..25a5f5f --- /dev/null +++ b/README.md @@ -0,0 +1,145 @@ +#### SMARTY DISCLAIMER: Subject to the terms of the associated license agreement, this software is freely available for your use. This software is FREE, AS IN PUPPIES, and is a gift. Enjoy your new responsibility. This means that while we may consider enhancement requests, we may or may not choose to entertain requests at our sole and absolute discretion. + + +# Smarty JavaScript SDK + +The official JavaScript/TypeScript SDK for accessing [Smarty](https://www.smarty.com) address validation APIs. Works in both Node.js and browser environments. + +[![npm](https://img.shields.io/npm/v/smartystreets-javascript-sdk)](https://www.npmjs.com/package/smartystreets-javascript-sdk) +[![license](https://img.shields.io/npm/l/smartystreets-javascript-sdk)](LICENSE.md) + +## Installation + +```bash +npm install smartystreets-javascript-sdk +``` + +## Quick Start: US Street Address Validation + +```javascript +import SmartySDK from "smartystreets-javascript-sdk"; + +const credentials = new SmartySDK.core.StaticCredentials( + process.env.SMARTY_AUTH_ID, + process.env.SMARTY_AUTH_TOKEN, +); +const client = new SmartySDK.core.ClientBuilder(credentials).buildUsStreetApiClient(); + +const lookup = new SmartySDK.usStreet.Lookup(); +lookup.street = "1600 Amphitheatre Parkway"; +lookup.city = "Mountain View"; +lookup.state = "CA"; + +const response = await client.send(lookup); +console.log(response.lookups[0].result); +``` + +## Quick Start: US Autocomplete Pro + +```javascript +const client = new SmartySDK.core.ClientBuilder(credentials).buildUsAutocompleteProClient(); + +const lookup = new SmartySDK.usAutocompletePro.Lookup("4770 Lincoln"); +lookup.maxResults = 10; +lookup.preferStates = ["IL"]; + +const response = await client.send(lookup); +console.log(response.result); // Array of address suggestions +``` + +## Supported APIs + +| API | Module | Build Method | Example | +| --- | --- | --- | --- | +| [US Street](https://www.smarty.com/docs/cloud/us-street-api) | `usStreet` | `buildUsStreetApiClient()` | [example](examples/us_street.mjs) | +| [US Zipcode](https://www.smarty.com/docs/cloud/us-zipcode-api) | `usZipcode` | `buildUsZipcodeClient()` | [example](examples/us_zipcode.mjs) | +| [US Autocomplete Pro](https://www.smarty.com/docs/cloud/us-autocomplete-pro-api) | `usAutocompletePro` | `buildUsAutocompleteProClient()` | [example](examples/us_autocomplete_pro.mjs) | +| [US Extract](https://www.smarty.com/docs/cloud/us-extract-api) | `usExtract` | `buildUsExtractClient()` | [example](examples/us_extract.mjs) | +| [US Enrichment](https://www.smarty.com/docs/cloud/us-address-enrichment-api) | `usEnrichment` | `buildUsEnrichmentClient()` | [example](examples/us_enrichment.mjs) | +| [US Reverse Geocoding](https://www.smarty.com/docs/cloud/us-reverse-geo-api) | `usReverseGeo` | `buildUsReverseGeoClient()` | [example](examples/us_reverse_geo.mjs) | +| [International Street](https://www.smarty.com/docs/cloud/international-street-api) | `internationalStreet` | `buildInternationalStreetClient()` | [example](examples/international_street.mjs) | +| [International Autocomplete](https://www.smarty.com/docs/cloud/international-address-autocomplete-api) | `internationalAddressAutocomplete` | `buildInternationalAddressAutocompleteClient()` | [example](examples/international_address_autocomplete.mjs) | +| [International Postal Code](https://www.smarty.com/docs/cloud/international-postal-code-api) | `internationalPostalCode` | `buildInternationalPostalCodeClient()` | [example](examples/international_postal_code.mjs) | + +## Authentication + +Three credential types are available: + +- **`StaticCredentials(authId, authToken)`** — Server-side authentication using auth-id and auth-token. +- **`SharedCredentials(key)`** — Client-side (browser) authentication using an embedded key. Does not support batch (POST) requests. +- **`BasicAuthCredentials(authId, authToken)`** — HTTP Basic Auth. + +## Common Patterns + +### Batch Requests + +Send up to 100 lookups in a single request (not available with `SharedCredentials`): + +```javascript +const batch = new SmartySDK.core.Batch(); +batch.add(lookup1); +batch.add(lookup2); + +const response = await client.send(batch); +``` + +### Error Handling + +All API errors extend `SmartyError`: + +```javascript +import { SmartyError } from "smartystreets-javascript-sdk"; + +try { + const response = await client.send(lookup); +} catch (err) { + if (err instanceof SmartyError) { + console.error("API error:", err.message); + } +} +``` + +### Retry and Timeout + +```javascript +const client = new SmartySDK.core.ClientBuilder(credentials) + .withMaxRetries(10) + .withMaxTimeout(30000) + .buildUsStreetApiClient(); +``` + +### Proxy + +```javascript +const client = new SmartySDK.core.ClientBuilder(credentials) + .withProxy("proxy.example.com", 8080, "https") + .buildUsStreetApiClient(); +``` + +### Custom Headers + +```javascript +const client = new SmartySDK.core.ClientBuilder(credentials) + .withCustomHeaders({ "X-Custom-Header": "value" }) + .buildUsStreetApiClient(); +``` + +## TypeScript + +The SDK is written in TypeScript and ships with full type declarations. All types are available as named exports: + +```typescript +import SmartySDK, { type MatchStrategy, type SmartyError } from "smartystreets-javascript-sdk"; + +const lookup = new SmartySDK.usStreet.Lookup(); +lookup.street = "1600 Amphitheatre Parkway"; +lookup.match = "enhanced" satisfies MatchStrategy; +``` + +## Documentation + +Full API documentation is available at [smarty.com/docs/sdk/javascript](https://www.smarty.com/docs/sdk/javascript). + +## License + +[Apache 2.0](LICENSE.md) diff --git a/Readme.md b/Readme.md deleted file mode 100644 index 48f33d0..0000000 --- a/Readme.md +++ /dev/null @@ -1,11 +0,0 @@ -#### SMARTY DISCLAIMER: Subject to the terms of the associated license agreement, this software is freely available for your use. This software is FREE, AS IN PUPPIES, and is a gift. Enjoy your new responsibility. This means that while we may consider enhancement requests, we may or may not choose to entertain requests at our sole and absolute discretion. - -# Smarty JavaScript SDK - -The official client libraries for accessing Smarty APIs with JavaScript. - -[![asciicast](https://asciinema.org/a/189101.png)](https://asciinema.org/a/189101) - -You may have noticed this page is curiously sparse. Don't panic, there's [documentation](https://www.smarty.com/docs/sdk/javascript) as well as working [examples](examples) over on our website. - -[Apache 2.0 License](LICENSE) diff --git a/package.json b/package.json index 34a4391..a73b6d9 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ ], "files": [ "dist", - "README.md", + "README.md", "LICENSE" ], "main": "dist/cjs/index.cjs", From f5a1e4f76790fc2de717a908b5eb6c47d796ffd0 Mon Sep 17 00:00:00 2001 From: Ryan Cox Date: Mon, 9 Mar 2026 11:42:57 -0600 Subject: [PATCH 29/29] Always send match=strict in US Street API requests Previously the SDK suppressed the match parameter when set to "strict", relying on the API's default behavior. Now match is always sent explicitly, aligning with the Go SDK behavior. --- src/util/buildUsStreetInputData.ts | 5 ---- tests/us_street/test_Client.ts | 38 ++++++++++++++++++++++++++++-- 2 files changed, 36 insertions(+), 7 deletions(-) diff --git a/src/util/buildUsStreetInputData.ts b/src/util/buildUsStreetInputData.ts index 6e2f6b4..172c8fc 100644 --- a/src/util/buildUsStreetInputData.ts +++ b/src/util/buildUsStreetInputData.ts @@ -14,11 +14,6 @@ export default function buildUsStreetInputData(lookup: Lookup): Record