lance-ts 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +195 -0
- package/dist/index.cjs +162 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +77 -0
- package/dist/index.d.ts +76 -8
- package/dist/index.js +121 -8
- package/dist/index.js.map +1 -1
- package/package.json +28 -21
- package/dist/batch-address.d.ts +0 -31
- package/dist/batch-address.d.ts.map +0 -1
- package/dist/batch-address.js +0 -70
- package/dist/batch-address.js.map +0 -1
- package/dist/batch-address.test.d.ts +0 -2
- package/dist/batch-address.test.d.ts.map +0 -1
- package/dist/batch-address.test.js +0 -98
- package/dist/batch-address.test.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/one-line-address.d.ts +0 -45
- package/dist/one-line-address.d.ts.map +0 -1
- package/dist/one-line-address.js +0 -64
- package/dist/one-line-address.js.map +0 -1
- package/dist/one-line-address.test.d.ts +0 -2
- package/dist/one-line-address.test.d.ts.map +0 -1
- package/dist/one-line-address.test.js +0 -112
- package/dist/one-line-address.test.js.map +0 -1
package/README.md
ADDED
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
# lance-ts
|
|
2
|
+
|
|
3
|
+
**Opinionated TypeScript client for the U.S. Census Geocoder API.**
|
|
4
|
+
|
|
5
|
+
Turn U.S. addresses into latitude/longitude coordinates using the free, no-key-required [Census Bureau Geocoder](https://geocoding.geo.census.gov/geocoder/) — with full TypeScript types and zero external HTTP dependencies.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Use Case:
|
|
10
|
+
|
|
11
|
+
If you're working with U.S. address data, the Census Geocoder is an extremely viable, completely free API. Backed by the official MAF/TIGER address database, and covering virtually every U.S. address, it has no posted rate limits and no API key.
|
|
12
|
+
|
|
13
|
+
### The Issue:
|
|
14
|
+
|
|
15
|
+
The raw API response is verbose and awkward to work with.
|
|
16
|
+
Below is the simplest possible response; a single one-line address match:
|
|
17
|
+
```json
|
|
18
|
+
{"result": {
|
|
19
|
+
"input": {
|
|
20
|
+
"address": {"address": "4600 Silver Hill Rd, Washington, DC 20233"},
|
|
21
|
+
"benchmark": {
|
|
22
|
+
"isDefault": true,
|
|
23
|
+
"benchmarkDescription": "Public Address Ranges - Current Benchmark",
|
|
24
|
+
"id": "4",
|
|
25
|
+
"benchmarkName": "Public_AR_Current"
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"addressMatches": [{
|
|
29
|
+
"tigerLine": {
|
|
30
|
+
"side": "L",
|
|
31
|
+
"tigerLineId": "76355984"
|
|
32
|
+
},
|
|
33
|
+
"coordinates": {
|
|
34
|
+
"x": -76.92748724230096,
|
|
35
|
+
"y": 38.84601622386617
|
|
36
|
+
},
|
|
37
|
+
"addressComponents": {
|
|
38
|
+
"zip": "20233",
|
|
39
|
+
"streetName": "SILVER HILL",
|
|
40
|
+
"preType": "",
|
|
41
|
+
"city": "WASHINGTON",
|
|
42
|
+
"preDirection": "",
|
|
43
|
+
"suffixDirection": "",
|
|
44
|
+
"fromAddress": "4600",
|
|
45
|
+
"state": "DC",
|
|
46
|
+
"suffixType": "RD",
|
|
47
|
+
"toAddress": "4700",
|
|
48
|
+
"suffixQualifier": "",
|
|
49
|
+
"preQualifier": ""
|
|
50
|
+
},
|
|
51
|
+
"matchedAddress": "4600 SILVER HILL RD, WASHINGTON, DC, 20233"
|
|
52
|
+
}]
|
|
53
|
+
}}
|
|
54
|
+
```
|
|
55
|
+
For applications that require lightweight & simple coordinate responses, `lance-ts` provides a clean, strongly-typed interface so you can go from address → coordinates in one call.
|
|
56
|
+
|
|
57
|
+
- 🆓 **Free** — no API key, no account, no rate limits
|
|
58
|
+
- 🏛️ **Official Data** — calls the U.S. Census Bureau Geocoder
|
|
59
|
+
- 📦 **Lightweight** — no HTTP library dependencies; uses node-native `fetch`
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## Installation
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
# pnpm (recommended)
|
|
67
|
+
pnpm add lance-ts
|
|
68
|
+
|
|
69
|
+
# npm
|
|
70
|
+
npm install lance-ts
|
|
71
|
+
|
|
72
|
+
# yarn
|
|
73
|
+
yarn add lance-ts
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Requires **Node.js 18+** (for native `fetch`).
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## Quick Start
|
|
81
|
+
|
|
82
|
+
```ts
|
|
83
|
+
import { geocode } from "lance-ts";
|
|
84
|
+
|
|
85
|
+
const result = await geocodeOneLineAddress(
|
|
86
|
+
"1600 Pennsylvania Avenue NW, Washington, DC 20500"
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
if (result) {
|
|
90
|
+
console.log(result.coordinates.x); // 38.8987...
|
|
91
|
+
console.log(result.coordinates.y); // -77.0353...
|
|
92
|
+
console.log(result.matchedAddress); // "1600 Pennsylvania..."
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## API
|
|
99
|
+
|
|
100
|
+
### `geocode(address: string): Promise<GeocodeResult | null>`
|
|
101
|
+
|
|
102
|
+
Geocodes a single one-line U.S. address. Returns `null` if no match is found.
|
|
103
|
+
|
|
104
|
+
```ts
|
|
105
|
+
const result = await geocode("350 Fifth Avenue, New York, NY 10118");
|
|
106
|
+
// → { lat: 40.7484, lng: -73.9856, matchedAddress: "350 5TH AVE, NEW YORK, NY, 10118" }
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
**Parameters**
|
|
110
|
+
|
|
111
|
+
| Name | Type | Description |
|
|
112
|
+
|-----------|----------|------------------------------------------|
|
|
113
|
+
| `address` | `string` | A U.S. address in one-line format |
|
|
114
|
+
|
|
115
|
+
**Returns:** `Promise<GeocodeResult | null>`
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
### `GeocodeResult`
|
|
120
|
+
|
|
121
|
+
```ts
|
|
122
|
+
type GeocodeResult = {
|
|
123
|
+
lat: number;
|
|
124
|
+
lng: number;
|
|
125
|
+
matchedAddress: string;
|
|
126
|
+
};
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## How It Works
|
|
132
|
+
|
|
133
|
+
`lance-ts` sends your address to the Census Bureau's public REST endpoint:
|
|
134
|
+
|
|
135
|
+
```
|
|
136
|
+
https://geocoding.geo.census.gov/geocoder/locations/onelineaddress
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
The response is parsed and normalized — extracting the matched coordinates and canonical address from the Census Bureau's nested JSON structure — and returned as a clean, typed object.
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## Development
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
# Install dependencies
|
|
147
|
+
pnpm install
|
|
148
|
+
|
|
149
|
+
# Run tests
|
|
150
|
+
pnpm test
|
|
151
|
+
|
|
152
|
+
# Run tests with UI
|
|
153
|
+
pnpm test --ui
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Project Structure
|
|
157
|
+
|
|
158
|
+
```
|
|
159
|
+
lance-ts/
|
|
160
|
+
├── src/ # TypeScript source
|
|
161
|
+
├── dist/ # Compiled output (generated)
|
|
162
|
+
├── tsconfig.json
|
|
163
|
+
└── package.json
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
This project uses a strict `tsconfig.json` setup including:
|
|
167
|
+
|
|
168
|
+
- `strict: true`
|
|
169
|
+
- `noUncheckedIndexedAccess: true`
|
|
170
|
+
- `exactOptionalPropertyTypes: true`
|
|
171
|
+
- `verbatimModuleSyntax: true`
|
|
172
|
+
- `moduleResolution: "nodenext"`
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
## Limitations
|
|
177
|
+
|
|
178
|
+
- U.S. addresses only
|
|
179
|
+
- Coordinate results are **interpolated** from TIGER address ranges, not rooftop-precise
|
|
180
|
+
- Batch geocoding (up to 10,000 addresses) is not yet implemented
|
|
181
|
+
- Reverse geocoding (coordinates → address) is not yet implemented
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
## Resources
|
|
186
|
+
|
|
187
|
+
- [Census Geocoder Web Interface](https://geocoding.geo.census.gov/geocoder/)
|
|
188
|
+
- [Census Geocoder API Docs](https://www.census.gov/programs-surveys/geography/technical-documentation/complete-technical-documentation/census-geocoder.html)
|
|
189
|
+
- [MAF/TIGER Database Overview](https://www.census.gov/geographies/mapping-files/time-series/geo/tiger-line-file.html)
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
## License
|
|
194
|
+
|
|
195
|
+
ISC © [matt-the-thew](https://github.com/matt-the-thew)
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var index_exports = {};
|
|
32
|
+
__export(index_exports, {
|
|
33
|
+
BatchAddressGeocoder: () => BatchAddressGeocoder,
|
|
34
|
+
geocodeOneLineAddress: () => geocodeOneLineAddress,
|
|
35
|
+
geocodeOneLineAddressAll: () => geocodeOneLineAddressAll
|
|
36
|
+
});
|
|
37
|
+
module.exports = __toCommonJS(index_exports);
|
|
38
|
+
|
|
39
|
+
// src/one-line-address.ts
|
|
40
|
+
async function geocodeOneLineAddress(address) {
|
|
41
|
+
const params = new URLSearchParams({
|
|
42
|
+
address,
|
|
43
|
+
benchmark: "Public_AR_Current",
|
|
44
|
+
format: "json"
|
|
45
|
+
});
|
|
46
|
+
const url = `https://geocoding.geo.census.gov/geocoder/locations/onelineaddress?${params}`;
|
|
47
|
+
const response = await fetch(url);
|
|
48
|
+
if (!response.ok) throw new Error(`HTTP error: ${response.status}`);
|
|
49
|
+
const data = await response.json();
|
|
50
|
+
const matches = data.result?.addressMatches;
|
|
51
|
+
if (!matches?.length) {
|
|
52
|
+
console.log(`No matches found for: ${address}`);
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
if (matches?.length > 1) {
|
|
56
|
+
console.warn(`Multiple address matches found for ${address}`);
|
|
57
|
+
for (const match of matches) {
|
|
58
|
+
console.warn(`[WARNING}: multimple matched addresses for: ${match.matchedAddress}
|
|
59
|
+
Coordinates:
|
|
60
|
+
X: ${match.coordinates["x"]}
|
|
61
|
+
Y: ${match.coordinates["y"]}
|
|
62
|
+
Consider geocodeOneLineAddressAll()`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (matches[0]) {
|
|
66
|
+
return {
|
|
67
|
+
coordinates: matches[0].coordinates,
|
|
68
|
+
matchedAddress: matches[0].matchedAddress
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
async function geocodeOneLineAddressAll(address) {
|
|
73
|
+
const params = new URLSearchParams({
|
|
74
|
+
address,
|
|
75
|
+
benchmark: "Public_AR_Current",
|
|
76
|
+
format: "json"
|
|
77
|
+
});
|
|
78
|
+
const url = `https://geocoding.geo.census.gov/geocoder/locations/onelineaddress?${params}`;
|
|
79
|
+
const response = await fetch(url);
|
|
80
|
+
if (!response.ok) throw new Error(`HTTP error: ${response.status}`);
|
|
81
|
+
const data = await response.json();
|
|
82
|
+
const matches = data.result?.addressMatches;
|
|
83
|
+
if (!matches?.length) {
|
|
84
|
+
console.log(`No matches found for: ${address}`);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
return matches;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// src/batch-address.ts
|
|
91
|
+
var fs = __toESM(require("fs"), 1);
|
|
92
|
+
var path = __toESM(require("path"), 1);
|
|
93
|
+
var import_meta = {};
|
|
94
|
+
var BatchAddressGeocoder = class {
|
|
95
|
+
// Set geocoder endpoint
|
|
96
|
+
url = "https://geocoding.geo.census.gov/geocoder/locations/addressbatch";
|
|
97
|
+
inputFilePath;
|
|
98
|
+
outputFilePath = "batch_coordinates.csv";
|
|
99
|
+
constructor(inputFilePath, outputFilePath) {
|
|
100
|
+
this.inputFilePath = inputFilePath;
|
|
101
|
+
if (outputFilePath) this.outputFilePath = outputFilePath;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Finds relative path for a file name
|
|
105
|
+
* @param {string} localFilePath
|
|
106
|
+
* @returns {string | undefined} the realtive file path, if exists
|
|
107
|
+
* @throws {Error} if unable to find relative path
|
|
108
|
+
*/
|
|
109
|
+
_parseFilePath(localFilePath) {
|
|
110
|
+
let parsedFilePath;
|
|
111
|
+
try {
|
|
112
|
+
parsedFilePath = path.join(import_meta.dirname, localFilePath);
|
|
113
|
+
} catch (error) {
|
|
114
|
+
throw new Error(`Error parsing file path: ${error}`);
|
|
115
|
+
}
|
|
116
|
+
return parsedFilePath ? parsedFilePath : void 0;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Generates FormData from a file, according to census geocoder specs
|
|
120
|
+
* @param {string} filePath
|
|
121
|
+
* @returns {FormData} Formatted form data, converting the file into a {Blob}
|
|
122
|
+
*/
|
|
123
|
+
_createFormData(filePath) {
|
|
124
|
+
const fileBuffer = fs.readFileSync(filePath);
|
|
125
|
+
if (!fileBuffer) throw new Error(`Unable to read file ${filePath}`);
|
|
126
|
+
const blob = new Blob([fileBuffer], { type: "text/plain" });
|
|
127
|
+
const formData = new FormData();
|
|
128
|
+
formData.append("addressFile", blob, path.basename(filePath));
|
|
129
|
+
formData.append("benchmark", "Public_AR_Current");
|
|
130
|
+
formData.append("returntype", "location");
|
|
131
|
+
return formData;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Sends generated FormData from blob-ified {@link inputFilePath} to Census Geocoder endpoint,
|
|
135
|
+
* and writes response to a local file based on {@link outputFilePath}.
|
|
136
|
+
* @returns {void}
|
|
137
|
+
*/
|
|
138
|
+
async geocodeBatch() {
|
|
139
|
+
const formData = this._createFormData(
|
|
140
|
+
this.inputFilePath
|
|
141
|
+
);
|
|
142
|
+
if (!formData)
|
|
143
|
+
throw new Error(
|
|
144
|
+
`Error creating FormData from ${this.inputFilePath}`
|
|
145
|
+
);
|
|
146
|
+
const response = await fetch(this.url, {
|
|
147
|
+
method: "POST",
|
|
148
|
+
body: formData
|
|
149
|
+
});
|
|
150
|
+
if (!response.ok) throw new Error(`HTTP Error: ${response.status}`);
|
|
151
|
+
const responseText = await response.text();
|
|
152
|
+
fs.writeFileSync(this.outputFilePath, responseText);
|
|
153
|
+
console.log(`Saved to ${this.outputFilePath}`);
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
157
|
+
0 && (module.exports = {
|
|
158
|
+
BatchAddressGeocoder,
|
|
159
|
+
geocodeOneLineAddress,
|
|
160
|
+
geocodeOneLineAddressAll
|
|
161
|
+
});
|
|
162
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/one-line-address.ts","../src/batch-address.ts"],"sourcesContent":["/**\n * @file Library entry point for one-line and batch geocoding functions\n * @module lance-ts\n * @author Matthew Morton\n * @see {@link https://github.com/matt-the-thew/lance-ts}\n */\nexport * from \"./one-line-address.js\";\nexport * from \"./batch-address.js\";\n","/**\n * Interface for lat/lng coordinates\n * @interface CensusCoordinates\n */\nexport interface CensusCoordinates {\n x: number;\n y: number;\n}\n\n/**\n * Interface for a single coordinate pair as {@type CensusCoordinates}\n * and the associated matched address, as {@type string}\n * @interface OneLineAddressMatch\n */\nexport interface OneLineAddressMatch {\n coordinates: CensusCoordinates;\n matchedAddress: string;\n}\n\n/**\n * Interface representing an array of {@type OneLineAddressMatch}\n * @interface OneLineAddressResult\n */\nexport interface OneLineAddressResult {\n addressMatches: OneLineAddressMatch[];\n}\n\n/**\n * Interface for the optional result, of type {@type OneLineAddressResult}\n */\nexport interface OneLineAddressResponse {\n result?: OneLineAddressResult;\n}\n\n/**\n * Returns the first result from whatever address matches it receives\n * @param address {string}\n * @returns {OneLineAddressMatch}\n * @throws {Error} if response status is not 200 OK\n */\nexport async function geocodeOneLineAddress(\n address: string,\n): Promise<OneLineAddressMatch | undefined> {\n //format parameters to use latest census data\n const params = new URLSearchParams({\n address,\n benchmark: \"Public_AR_Current\",\n format: \"json\",\n });\n\n const url = `https://geocoding.geo.census.gov/geocoder/locations/onelineaddress?${params}`;\n const response: Response = await fetch(url);\n if (!response.ok) throw new Error(`HTTP error: ${response.status}`);\n\n // Retreives array of coordinates and string of matched addresses from API res\n const data = (await response.json()) as OneLineAddressResponse;\n const matches = data.result?.addressMatches;\n\n if (!matches?.length) {\n console.log(`No matches found for: ${address}`);\n return;\n }\n\n // warns if multiple matched addresses exist for a single address\n if (matches?.length > 1) {\n console.warn(`Multiple address matches found for ${address}`);\n for (const match of matches) {\n console.warn(`[WARNING}: multimple matched addresses for: ${match.matchedAddress}\n Coordinates:\n X: ${match.coordinates[\"x\"]}\n Y: ${match.coordinates[\"y\"]}\n Consider geocodeOneLineAddressAll()`);\n }\n }\n\n if (matches[0]) {\n return {\n coordinates: matches[0].coordinates,\n matchedAddress: matches[0].matchedAddress,\n };\n }\n}\n\n/**\n * Returns entire array of {@type OneLineAddressMatch}\n * @param {string} address - The address to submit to the census geocoder\n * @returns {OneLineAddressMatch[]} | undefined\n * @throws {Error} if response status is not OK\n */\nexport async function geocodeOneLineAddressAll(\n address: string,\n): Promise<OneLineAddressMatch[] | undefined> {\n //format parameters to use latest census data\n const params = new URLSearchParams({\n address,\n benchmark: \"Public_AR_Current\",\n format: \"json\",\n });\n\n const url = `https://geocoding.geo.census.gov/geocoder/locations/onelineaddress?${params}`;\n const response: Response = await fetch(url);\n if (!response.ok) throw new Error(`HTTP error: ${response.status}`);\n\n // Retreives array of coordinates and string of matched addresses from API res\n const data = (await response.json()) as OneLineAddressResponse;\n const matches = data.result?.addressMatches;\n\n if (!matches?.length) {\n console.log(`No matches found for: ${address}`);\n return;\n }\n\n return matches;\n}\n","import * as fs from \"node:fs\";\nimport * as path from \"path\";\n\n/**\n * Batch geocoder session handler\n * @param {string} inputFilePath\n * @param {string} outputFilePath - @default\n */\nexport class BatchAddressGeocoder {\n // Set geocoder endpoint\n url = \"https://geocoding.geo.census.gov/geocoder/locations/addressbatch\";\n\n inputFilePath: string;\n outputFilePath: string = \"batch_coordinates.csv\";\n\n constructor(inputFilePath: string, outputFilePath?: string) {\n this.inputFilePath = inputFilePath;\n if (outputFilePath) this.outputFilePath = outputFilePath;\n }\n\n /**\n * Finds relative path for a file name\n * @param {string} localFilePath\n * @returns {string | undefined} the realtive file path, if exists\n * @throws {Error} if unable to find relative path\n */\n _parseFilePath(localFilePath: string): string | undefined {\n // create absolute directory name for fs methods\n let parsedFilePath: string;\n try {\n parsedFilePath = path.join(import.meta.dirname, localFilePath);\n } catch (error) {\n throw new Error(`Error parsing file path: ${error}`);\n }\n\n return parsedFilePath ? parsedFilePath : undefined;\n }\n\n /**\n * Generates FormData from a file, according to census geocoder specs\n * @param {string} filePath\n * @returns {FormData} Formatted form data, converting the file into a {Blob}\n */\n _createFormData(filePath: string): FormData | undefined {\n const fileBuffer = fs.readFileSync(filePath);\n if (!fileBuffer) throw new Error(`Unable to read file ${filePath}`);\n\n const blob = new Blob([fileBuffer], { type: \"text/plain\" });\n const formData = new FormData();\n\n formData.append(\"addressFile\", blob, path.basename(filePath));\n formData.append(\"benchmark\", \"Public_AR_Current\");\n formData.append(\"returntype\", \"location\");\n\n return formData;\n }\n\n /**\n * Sends generated FormData from blob-ified {@link inputFilePath} to Census Geocoder endpoint,\n * and writes response to a local file based on {@link outputFilePath}.\n * @returns {void}\n */\n async geocodeBatch(): Promise<void> {\n const formData: FormData | undefined = this._createFormData(\n this.inputFilePath,\n );\n if (!formData)\n throw new Error(\n `Error creating FormData from ${this.inputFilePath}`,\n );\n const response = await fetch(this.url, {\n method: \"POST\",\n body: formData,\n });\n if (!response.ok) throw new Error(`HTTP Error: ${response.status}`);\n const responseText = await response.text();\n\n fs.writeFileSync(this.outputFilePath, responseText);\n console.log(`Saved to ${this.outputFilePath}`);\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interface for lat/lng coordinates
|
|
3
|
+
* @interface CensusCoordinates
|
|
4
|
+
*/
|
|
5
|
+
interface CensusCoordinates {
|
|
6
|
+
x: number;
|
|
7
|
+
y: number;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Interface for a single coordinate pair as {@type CensusCoordinates}
|
|
11
|
+
* and the associated matched address, as {@type string}
|
|
12
|
+
* @interface OneLineAddressMatch
|
|
13
|
+
*/
|
|
14
|
+
interface OneLineAddressMatch {
|
|
15
|
+
coordinates: CensusCoordinates;
|
|
16
|
+
matchedAddress: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Interface representing an array of {@type OneLineAddressMatch}
|
|
20
|
+
* @interface OneLineAddressResult
|
|
21
|
+
*/
|
|
22
|
+
interface OneLineAddressResult {
|
|
23
|
+
addressMatches: OneLineAddressMatch[];
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Interface for the optional result, of type {@type OneLineAddressResult}
|
|
27
|
+
*/
|
|
28
|
+
interface OneLineAddressResponse {
|
|
29
|
+
result?: OneLineAddressResult;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Returns the first result from whatever address matches it receives
|
|
33
|
+
* @param address {string}
|
|
34
|
+
* @returns {OneLineAddressMatch}
|
|
35
|
+
* @throws {Error} if response status is not 200 OK
|
|
36
|
+
*/
|
|
37
|
+
declare function geocodeOneLineAddress(address: string): Promise<OneLineAddressMatch | undefined>;
|
|
38
|
+
/**
|
|
39
|
+
* Returns entire array of {@type OneLineAddressMatch}
|
|
40
|
+
* @param {string} address - The address to submit to the census geocoder
|
|
41
|
+
* @returns {OneLineAddressMatch[]} | undefined
|
|
42
|
+
* @throws {Error} if response status is not OK
|
|
43
|
+
*/
|
|
44
|
+
declare function geocodeOneLineAddressAll(address: string): Promise<OneLineAddressMatch[] | undefined>;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Batch geocoder session handler
|
|
48
|
+
* @param {string} inputFilePath
|
|
49
|
+
* @param {string} outputFilePath - @default
|
|
50
|
+
*/
|
|
51
|
+
declare class BatchAddressGeocoder {
|
|
52
|
+
url: string;
|
|
53
|
+
inputFilePath: string;
|
|
54
|
+
outputFilePath: string;
|
|
55
|
+
constructor(inputFilePath: string, outputFilePath?: string);
|
|
56
|
+
/**
|
|
57
|
+
* Finds relative path for a file name
|
|
58
|
+
* @param {string} localFilePath
|
|
59
|
+
* @returns {string | undefined} the realtive file path, if exists
|
|
60
|
+
* @throws {Error} if unable to find relative path
|
|
61
|
+
*/
|
|
62
|
+
_parseFilePath(localFilePath: string): string | undefined;
|
|
63
|
+
/**
|
|
64
|
+
* Generates FormData from a file, according to census geocoder specs
|
|
65
|
+
* @param {string} filePath
|
|
66
|
+
* @returns {FormData} Formatted form data, converting the file into a {Blob}
|
|
67
|
+
*/
|
|
68
|
+
_createFormData(filePath: string): FormData | undefined;
|
|
69
|
+
/**
|
|
70
|
+
* Sends generated FormData from blob-ified {@link inputFilePath} to Census Geocoder endpoint,
|
|
71
|
+
* and writes response to a local file based on {@link outputFilePath}.
|
|
72
|
+
* @returns {void}
|
|
73
|
+
*/
|
|
74
|
+
geocodeBatch(): Promise<void>;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export { BatchAddressGeocoder, type CensusCoordinates, type OneLineAddressMatch, type OneLineAddressResponse, type OneLineAddressResult, geocodeOneLineAddress, geocodeOneLineAddressAll };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,77 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* @
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
2
|
+
* Interface for lat/lng coordinates
|
|
3
|
+
* @interface CensusCoordinates
|
|
4
|
+
*/
|
|
5
|
+
interface CensusCoordinates {
|
|
6
|
+
x: number;
|
|
7
|
+
y: number;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Interface for a single coordinate pair as {@type CensusCoordinates}
|
|
11
|
+
* and the associated matched address, as {@type string}
|
|
12
|
+
* @interface OneLineAddressMatch
|
|
13
|
+
*/
|
|
14
|
+
interface OneLineAddressMatch {
|
|
15
|
+
coordinates: CensusCoordinates;
|
|
16
|
+
matchedAddress: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Interface representing an array of {@type OneLineAddressMatch}
|
|
20
|
+
* @interface OneLineAddressResult
|
|
21
|
+
*/
|
|
22
|
+
interface OneLineAddressResult {
|
|
23
|
+
addressMatches: OneLineAddressMatch[];
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Interface for the optional result, of type {@type OneLineAddressResult}
|
|
27
|
+
*/
|
|
28
|
+
interface OneLineAddressResponse {
|
|
29
|
+
result?: OneLineAddressResult;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Returns the first result from whatever address matches it receives
|
|
33
|
+
* @param address {string}
|
|
34
|
+
* @returns {OneLineAddressMatch}
|
|
35
|
+
* @throws {Error} if response status is not 200 OK
|
|
36
|
+
*/
|
|
37
|
+
declare function geocodeOneLineAddress(address: string): Promise<OneLineAddressMatch | undefined>;
|
|
38
|
+
/**
|
|
39
|
+
* Returns entire array of {@type OneLineAddressMatch}
|
|
40
|
+
* @param {string} address - The address to submit to the census geocoder
|
|
41
|
+
* @returns {OneLineAddressMatch[]} | undefined
|
|
42
|
+
* @throws {Error} if response status is not OK
|
|
43
|
+
*/
|
|
44
|
+
declare function geocodeOneLineAddressAll(address: string): Promise<OneLineAddressMatch[] | undefined>;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Batch geocoder session handler
|
|
48
|
+
* @param {string} inputFilePath
|
|
49
|
+
* @param {string} outputFilePath - @default
|
|
50
|
+
*/
|
|
51
|
+
declare class BatchAddressGeocoder {
|
|
52
|
+
url: string;
|
|
53
|
+
inputFilePath: string;
|
|
54
|
+
outputFilePath: string;
|
|
55
|
+
constructor(inputFilePath: string, outputFilePath?: string);
|
|
56
|
+
/**
|
|
57
|
+
* Finds relative path for a file name
|
|
58
|
+
* @param {string} localFilePath
|
|
59
|
+
* @returns {string | undefined} the realtive file path, if exists
|
|
60
|
+
* @throws {Error} if unable to find relative path
|
|
61
|
+
*/
|
|
62
|
+
_parseFilePath(localFilePath: string): string | undefined;
|
|
63
|
+
/**
|
|
64
|
+
* Generates FormData from a file, according to census geocoder specs
|
|
65
|
+
* @param {string} filePath
|
|
66
|
+
* @returns {FormData} Formatted form data, converting the file into a {Blob}
|
|
67
|
+
*/
|
|
68
|
+
_createFormData(filePath: string): FormData | undefined;
|
|
69
|
+
/**
|
|
70
|
+
* Sends generated FormData from blob-ified {@link inputFilePath} to Census Geocoder endpoint,
|
|
71
|
+
* and writes response to a local file based on {@link outputFilePath}.
|
|
72
|
+
* @returns {void}
|
|
73
|
+
*/
|
|
74
|
+
geocodeBatch(): Promise<void>;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export { BatchAddressGeocoder, type CensusCoordinates, type OneLineAddressMatch, type OneLineAddressResponse, type OneLineAddressResult, geocodeOneLineAddress, geocodeOneLineAddressAll };
|
package/dist/index.js
CHANGED
|
@@ -1,9 +1,122 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
// src/one-line-address.ts
|
|
2
|
+
async function geocodeOneLineAddress(address) {
|
|
3
|
+
const params = new URLSearchParams({
|
|
4
|
+
address,
|
|
5
|
+
benchmark: "Public_AR_Current",
|
|
6
|
+
format: "json"
|
|
7
|
+
});
|
|
8
|
+
const url = `https://geocoding.geo.census.gov/geocoder/locations/onelineaddress?${params}`;
|
|
9
|
+
const response = await fetch(url);
|
|
10
|
+
if (!response.ok) throw new Error(`HTTP error: ${response.status}`);
|
|
11
|
+
const data = await response.json();
|
|
12
|
+
const matches = data.result?.addressMatches;
|
|
13
|
+
if (!matches?.length) {
|
|
14
|
+
console.log(`No matches found for: ${address}`);
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
if (matches?.length > 1) {
|
|
18
|
+
console.warn(`Multiple address matches found for ${address}`);
|
|
19
|
+
for (const match of matches) {
|
|
20
|
+
console.warn(`[WARNING}: multimple matched addresses for: ${match.matchedAddress}
|
|
21
|
+
Coordinates:
|
|
22
|
+
X: ${match.coordinates["x"]}
|
|
23
|
+
Y: ${match.coordinates["y"]}
|
|
24
|
+
Consider geocodeOneLineAddressAll()`);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
if (matches[0]) {
|
|
28
|
+
return {
|
|
29
|
+
coordinates: matches[0].coordinates,
|
|
30
|
+
matchedAddress: matches[0].matchedAddress
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
async function geocodeOneLineAddressAll(address) {
|
|
35
|
+
const params = new URLSearchParams({
|
|
36
|
+
address,
|
|
37
|
+
benchmark: "Public_AR_Current",
|
|
38
|
+
format: "json"
|
|
39
|
+
});
|
|
40
|
+
const url = `https://geocoding.geo.census.gov/geocoder/locations/onelineaddress?${params}`;
|
|
41
|
+
const response = await fetch(url);
|
|
42
|
+
if (!response.ok) throw new Error(`HTTP error: ${response.status}`);
|
|
43
|
+
const data = await response.json();
|
|
44
|
+
const matches = data.result?.addressMatches;
|
|
45
|
+
if (!matches?.length) {
|
|
46
|
+
console.log(`No matches found for: ${address}`);
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
return matches;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// src/batch-address.ts
|
|
53
|
+
import * as fs from "fs";
|
|
54
|
+
import * as path from "path";
|
|
55
|
+
var BatchAddressGeocoder = class {
|
|
56
|
+
// Set geocoder endpoint
|
|
57
|
+
url = "https://geocoding.geo.census.gov/geocoder/locations/addressbatch";
|
|
58
|
+
inputFilePath;
|
|
59
|
+
outputFilePath = "batch_coordinates.csv";
|
|
60
|
+
constructor(inputFilePath, outputFilePath) {
|
|
61
|
+
this.inputFilePath = inputFilePath;
|
|
62
|
+
if (outputFilePath) this.outputFilePath = outputFilePath;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Finds relative path for a file name
|
|
66
|
+
* @param {string} localFilePath
|
|
67
|
+
* @returns {string | undefined} the realtive file path, if exists
|
|
68
|
+
* @throws {Error} if unable to find relative path
|
|
69
|
+
*/
|
|
70
|
+
_parseFilePath(localFilePath) {
|
|
71
|
+
let parsedFilePath;
|
|
72
|
+
try {
|
|
73
|
+
parsedFilePath = path.join(import.meta.dirname, localFilePath);
|
|
74
|
+
} catch (error) {
|
|
75
|
+
throw new Error(`Error parsing file path: ${error}`);
|
|
76
|
+
}
|
|
77
|
+
return parsedFilePath ? parsedFilePath : void 0;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Generates FormData from a file, according to census geocoder specs
|
|
81
|
+
* @param {string} filePath
|
|
82
|
+
* @returns {FormData} Formatted form data, converting the file into a {Blob}
|
|
83
|
+
*/
|
|
84
|
+
_createFormData(filePath) {
|
|
85
|
+
const fileBuffer = fs.readFileSync(filePath);
|
|
86
|
+
if (!fileBuffer) throw new Error(`Unable to read file ${filePath}`);
|
|
87
|
+
const blob = new Blob([fileBuffer], { type: "text/plain" });
|
|
88
|
+
const formData = new FormData();
|
|
89
|
+
formData.append("addressFile", blob, path.basename(filePath));
|
|
90
|
+
formData.append("benchmark", "Public_AR_Current");
|
|
91
|
+
formData.append("returntype", "location");
|
|
92
|
+
return formData;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Sends generated FormData from blob-ified {@link inputFilePath} to Census Geocoder endpoint,
|
|
96
|
+
* and writes response to a local file based on {@link outputFilePath}.
|
|
97
|
+
* @returns {void}
|
|
98
|
+
*/
|
|
99
|
+
async geocodeBatch() {
|
|
100
|
+
const formData = this._createFormData(
|
|
101
|
+
this.inputFilePath
|
|
102
|
+
);
|
|
103
|
+
if (!formData)
|
|
104
|
+
throw new Error(
|
|
105
|
+
`Error creating FormData from ${this.inputFilePath}`
|
|
106
|
+
);
|
|
107
|
+
const response = await fetch(this.url, {
|
|
108
|
+
method: "POST",
|
|
109
|
+
body: formData
|
|
110
|
+
});
|
|
111
|
+
if (!response.ok) throw new Error(`HTTP Error: ${response.status}`);
|
|
112
|
+
const responseText = await response.text();
|
|
113
|
+
fs.writeFileSync(this.outputFilePath, responseText);
|
|
114
|
+
console.log(`Saved to ${this.outputFilePath}`);
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
export {
|
|
118
|
+
BatchAddressGeocoder,
|
|
119
|
+
geocodeOneLineAddress,
|
|
120
|
+
geocodeOneLineAddressAll
|
|
121
|
+
};
|
|
9
122
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"
|
|
1
|
+
{"version":3,"sources":["../src/one-line-address.ts","../src/batch-address.ts"],"sourcesContent":["/**\n * Interface for lat/lng coordinates\n * @interface CensusCoordinates\n */\nexport interface CensusCoordinates {\n x: number;\n y: number;\n}\n\n/**\n * Interface for a single coordinate pair as {@type CensusCoordinates}\n * and the associated matched address, as {@type string}\n * @interface OneLineAddressMatch\n */\nexport interface OneLineAddressMatch {\n coordinates: CensusCoordinates;\n matchedAddress: string;\n}\n\n/**\n * Interface representing an array of {@type OneLineAddressMatch}\n * @interface OneLineAddressResult\n */\nexport interface OneLineAddressResult {\n addressMatches: OneLineAddressMatch[];\n}\n\n/**\n * Interface for the optional result, of type {@type OneLineAddressResult}\n */\nexport interface OneLineAddressResponse {\n result?: OneLineAddressResult;\n}\n\n/**\n * Returns the first result from whatever address matches it receives\n * @param address {string}\n * @returns {OneLineAddressMatch}\n * @throws {Error} if response status is not 200 OK\n */\nexport async function geocodeOneLineAddress(\n address: string,\n): Promise<OneLineAddressMatch | undefined> {\n //format parameters to use latest census data\n const params = new URLSearchParams({\n address,\n benchmark: \"Public_AR_Current\",\n format: \"json\",\n });\n\n const url = `https://geocoding.geo.census.gov/geocoder/locations/onelineaddress?${params}`;\n const response: Response = await fetch(url);\n if (!response.ok) throw new Error(`HTTP error: ${response.status}`);\n\n // Retreives array of coordinates and string of matched addresses from API res\n const data = (await response.json()) as OneLineAddressResponse;\n const matches = data.result?.addressMatches;\n\n if (!matches?.length) {\n console.log(`No matches found for: ${address}`);\n return;\n }\n\n // warns if multiple matched addresses exist for a single address\n if (matches?.length > 1) {\n console.warn(`Multiple address matches found for ${address}`);\n for (const match of matches) {\n console.warn(`[WARNING}: multimple matched addresses for: ${match.matchedAddress}\n Coordinates:\n X: ${match.coordinates[\"x\"]}\n Y: ${match.coordinates[\"y\"]}\n Consider geocodeOneLineAddressAll()`);\n }\n }\n\n if (matches[0]) {\n return {\n coordinates: matches[0].coordinates,\n matchedAddress: matches[0].matchedAddress,\n };\n }\n}\n\n/**\n * Returns entire array of {@type OneLineAddressMatch}\n * @param {string} address - The address to submit to the census geocoder\n * @returns {OneLineAddressMatch[]} | undefined\n * @throws {Error} if response status is not OK\n */\nexport async function geocodeOneLineAddressAll(\n address: string,\n): Promise<OneLineAddressMatch[] | undefined> {\n //format parameters to use latest census data\n const params = new URLSearchParams({\n address,\n benchmark: \"Public_AR_Current\",\n format: \"json\",\n });\n\n const url = `https://geocoding.geo.census.gov/geocoder/locations/onelineaddress?${params}`;\n const response: Response = await fetch(url);\n if (!response.ok) throw new Error(`HTTP error: ${response.status}`);\n\n // Retreives array of coordinates and string of matched addresses from API res\n const data = (await response.json()) as OneLineAddressResponse;\n const matches = data.result?.addressMatches;\n\n if (!matches?.length) {\n console.log(`No matches found for: ${address}`);\n return;\n }\n\n return matches;\n}\n","import * as fs from \"node:fs\";\nimport * as path from \"path\";\n\n/**\n * Batch geocoder session handler\n * @param {string} inputFilePath\n * @param {string} outputFilePath - @default\n */\nexport class BatchAddressGeocoder {\n // Set geocoder endpoint\n url = \"https://geocoding.geo.census.gov/geocoder/locations/addressbatch\";\n\n inputFilePath: string;\n outputFilePath: string = \"batch_coordinates.csv\";\n\n constructor(inputFilePath: string, outputFilePath?: string) {\n this.inputFilePath = inputFilePath;\n if (outputFilePath) this.outputFilePath = outputFilePath;\n }\n\n /**\n * Finds relative path for a file name\n * @param {string} localFilePath\n * @returns {string | undefined} the realtive file path, if exists\n * @throws {Error} if unable to find relative path\n */\n _parseFilePath(localFilePath: string): string | undefined {\n // create absolute directory name for fs methods\n let parsedFilePath: string;\n try {\n parsedFilePath = path.join(import.meta.dirname, localFilePath);\n } catch (error) {\n throw new Error(`Error parsing file path: ${error}`);\n }\n\n return parsedFilePath ? parsedFilePath : undefined;\n }\n\n /**\n * Generates FormData from a file, according to census geocoder specs\n * @param {string} filePath\n * @returns {FormData} Formatted form data, converting the file into a {Blob}\n */\n _createFormData(filePath: string): FormData | undefined {\n const fileBuffer = fs.readFileSync(filePath);\n if (!fileBuffer) throw new Error(`Unable to read file ${filePath}`);\n\n const blob = new Blob([fileBuffer], { type: \"text/plain\" });\n const formData = new FormData();\n\n formData.append(\"addressFile\", blob, path.basename(filePath));\n formData.append(\"benchmark\", \"Public_AR_Current\");\n formData.append(\"returntype\", \"location\");\n\n return formData;\n }\n\n /**\n * Sends generated FormData from blob-ified {@link inputFilePath} to Census Geocoder endpoint,\n * and writes response to a local file based on {@link outputFilePath}.\n * @returns {void}\n */\n async geocodeBatch(): Promise<void> {\n const formData: FormData | undefined = this._createFormData(\n this.inputFilePath,\n );\n if (!formData)\n throw new Error(\n `Error creating FormData from ${this.inputFilePath}`,\n );\n const response = await fetch(this.url, {\n method: \"POST\",\n body: formData,\n });\n if (!response.ok) throw new Error(`HTTP Error: ${response.status}`);\n const responseText = await response.text();\n\n fs.writeFileSync(this.outputFilePath, responseText);\n console.log(`Saved to ${this.outputFilePath}`);\n }\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,37 +1,44 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lance-ts",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "Lat/
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "Lat/Long from National Census Endpoint. An opinionated, blazingingly fast geocoding library.",
|
|
5
5
|
"type": "module",
|
|
6
|
-
"
|
|
6
|
+
"module": "./dist/index.mjs",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
7
8
|
"exports": {
|
|
8
9
|
".": {
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
-
"require": "./dist/
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js",
|
|
12
|
+
"require": "./dist/index.cjs"
|
|
12
13
|
}
|
|
13
14
|
},
|
|
14
|
-
"files": [
|
|
15
|
-
"dist"
|
|
16
|
-
],
|
|
17
15
|
"scripts": {
|
|
18
16
|
"test": "vitest",
|
|
19
|
-
"
|
|
20
|
-
"
|
|
17
|
+
"test:ui": "vitest --ui",
|
|
18
|
+
"type-check": "tsc --noEmit",
|
|
19
|
+
"build": "tsup",
|
|
20
|
+
"clean": "rm -rf ./dist"
|
|
21
21
|
},
|
|
22
|
-
"
|
|
23
|
-
|
|
22
|
+
"files": [
|
|
23
|
+
"dist"
|
|
24
|
+
],
|
|
25
|
+
"keywords": [
|
|
26
|
+
"geocoding",
|
|
27
|
+
"gps",
|
|
28
|
+
"geography",
|
|
29
|
+
"geospatial",
|
|
30
|
+
"coordinates"
|
|
31
|
+
],
|
|
32
|
+
"author": "Matthew Morton <mmortondev@gmail.com>",
|
|
24
33
|
"license": "ISC",
|
|
25
|
-
"packageManager": "pnpm@
|
|
34
|
+
"packageManager": "pnpm@11.5.2",
|
|
26
35
|
"devDependencies": {
|
|
27
|
-
"@types/node": "^25.9.
|
|
28
|
-
"@vitest/ui": "4.1.
|
|
36
|
+
"@types/node": "^25.9.2",
|
|
37
|
+
"@vitest/ui": "4.1.8",
|
|
38
|
+
"memfs": "^4.57.6",
|
|
29
39
|
"publint": "^0.3.21",
|
|
30
40
|
"tsup": "^8.5.1",
|
|
31
|
-
"typescript": "^6.0.3"
|
|
32
|
-
|
|
33
|
-
"dependencies": {
|
|
34
|
-
"memfs": "^4.57.2",
|
|
35
|
-
"vitest": "^4.1.7"
|
|
41
|
+
"typescript": "^6.0.3",
|
|
42
|
+
"vitest": "^4.1.8"
|
|
36
43
|
}
|
|
37
44
|
}
|
package/dist/batch-address.d.ts
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Batch geocoder session handler
|
|
3
|
-
* @param {string} inputFilePath
|
|
4
|
-
* @param {string} outputFilePath - @default
|
|
5
|
-
*/
|
|
6
|
-
export declare class BatchAddressGeocoder {
|
|
7
|
-
url: string;
|
|
8
|
-
inputFilePath: string;
|
|
9
|
-
outputFilePath: string;
|
|
10
|
-
constructor(inputFilePath: string, outputFilePath?: string);
|
|
11
|
-
/**
|
|
12
|
-
* Finds relative path for a file name
|
|
13
|
-
* @param {string} localFilePath
|
|
14
|
-
* @returns {string | undefined} the realtive file path, if exists
|
|
15
|
-
* @throws {Error} if unable to find relative path
|
|
16
|
-
*/
|
|
17
|
-
_parseFilePath(localFilePath: string): string | undefined;
|
|
18
|
-
/**
|
|
19
|
-
* Generates FormData from a file, according to census geocoder specs
|
|
20
|
-
* @param {string} filePath
|
|
21
|
-
* @returns {FormData} Formatted form data, converting the file into a {Blob}
|
|
22
|
-
*/
|
|
23
|
-
_createFormData(filePath: string): FormData | undefined;
|
|
24
|
-
/**
|
|
25
|
-
* Sends generated FormData from blob-ified {@link inputFilePath} to Census Geocoder endpoint,
|
|
26
|
-
* and writes response to a local file based on {@link outputFilePath}.
|
|
27
|
-
* @returns {void}
|
|
28
|
-
*/
|
|
29
|
-
geocodeBatch(): Promise<void>;
|
|
30
|
-
}
|
|
31
|
-
//# sourceMappingURL=batch-address.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"batch-address.d.ts","sourceRoot":"","sources":["../src/batch-address.ts"],"names":[],"mappings":"AAKA;;;;GAIG;AACH,qBAAa,oBAAoB;IAE/B,GAAG,SAAsE;IAEzE,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAA2B;gBAErC,aAAa,EAAE,MAAM,EAAE,cAAc,CAAC,EAAE,MAAM;IAK1D;;;;;OAKG;IACH,cAAc,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAYzD;;;;OAIG;IACH,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS;IAcvD;;;;OAIG;IACG,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;CAkBpC"}
|
package/dist/batch-address.js
DELETED
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import * as fs from "node:fs";
|
|
2
|
-
import * as path from "path";
|
|
3
|
-
/**
|
|
4
|
-
* Batch geocoder session handler
|
|
5
|
-
* @param {string} inputFilePath
|
|
6
|
-
* @param {string} outputFilePath - @default
|
|
7
|
-
*/
|
|
8
|
-
export class BatchAddressGeocoder {
|
|
9
|
-
constructor(inputFilePath, outputFilePath) {
|
|
10
|
-
// Set geocoder endpoint
|
|
11
|
-
this.url = "https://geocoding.geo.census.gov/geocoder/locations/addressbatch";
|
|
12
|
-
this.outputFilePath = "batch_coordinates.csv";
|
|
13
|
-
this.inputFilePath = inputFilePath;
|
|
14
|
-
if (outputFilePath)
|
|
15
|
-
this.outputFilePath = outputFilePath;
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* Finds relative path for a file name
|
|
19
|
-
* @param {string} localFilePath
|
|
20
|
-
* @returns {string | undefined} the realtive file path, if exists
|
|
21
|
-
* @throws {Error} if unable to find relative path
|
|
22
|
-
*/
|
|
23
|
-
_parseFilePath(localFilePath) {
|
|
24
|
-
// create absolute directory name for fs methods
|
|
25
|
-
let parsedFilePath;
|
|
26
|
-
try {
|
|
27
|
-
parsedFilePath = path.join(import.meta.dirname, localFilePath);
|
|
28
|
-
}
|
|
29
|
-
catch (error) {
|
|
30
|
-
throw new Error(`Error parsing file path: ${error}`);
|
|
31
|
-
}
|
|
32
|
-
return parsedFilePath ? parsedFilePath : undefined;
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* Generates FormData from a file, according to census geocoder specs
|
|
36
|
-
* @param {string} filePath
|
|
37
|
-
* @returns {FormData} Formatted form data, converting the file into a {Blob}
|
|
38
|
-
*/
|
|
39
|
-
_createFormData(filePath) {
|
|
40
|
-
const fileBuffer = fs.readFileSync(filePath);
|
|
41
|
-
if (!fileBuffer)
|
|
42
|
-
throw new Error(`Unable to read file ${filePath}`);
|
|
43
|
-
const blob = new Blob([fileBuffer], { type: "text/plain" });
|
|
44
|
-
const formData = new FormData();
|
|
45
|
-
formData.append("addressFile", blob, path.basename(filePath));
|
|
46
|
-
formData.append("benchmark", "Public_AR_Current");
|
|
47
|
-
formData.append("returntype", "location");
|
|
48
|
-
return formData;
|
|
49
|
-
}
|
|
50
|
-
/**
|
|
51
|
-
* Sends generated FormData from blob-ified {@link inputFilePath} to Census Geocoder endpoint,
|
|
52
|
-
* and writes response to a local file based on {@link outputFilePath}.
|
|
53
|
-
* @returns {void}
|
|
54
|
-
*/
|
|
55
|
-
async geocodeBatch() {
|
|
56
|
-
const formData = this._createFormData(this.inputFilePath);
|
|
57
|
-
if (!formData)
|
|
58
|
-
throw new Error(`Error creating FormData from ${this.inputFilePath}`);
|
|
59
|
-
const response = await fetch(this.url, {
|
|
60
|
-
method: "POST",
|
|
61
|
-
body: formData,
|
|
62
|
-
});
|
|
63
|
-
if (!response.ok)
|
|
64
|
-
throw new Error(`HTTP Error: ${response.status}`);
|
|
65
|
-
const responseText = await response.text();
|
|
66
|
-
fs.writeFileSync(this.outputFilePath, responseText);
|
|
67
|
-
console.log(`Saved to ${this.outputFilePath}`);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
//# sourceMappingURL=batch-address.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"batch-address.js","sourceRoot":"","sources":["../src/batch-address.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAI7B;;;;GAIG;AACH,MAAM,OAAO,oBAAoB;IAO/B,YAAY,aAAqB,EAAE,cAAuB;QAN1D,wBAAwB;QACxB,QAAG,GAAG,kEAAkE,CAAC;QAGzE,mBAAc,GAAW,uBAAuB,CAAC;QAG/C,IAAI,CAAC,aAAa,GAAG,aAAa,CAAC;QACnC,IAAI,cAAc;YAAE,IAAI,CAAC,cAAc,GAAG,cAAc,CAAC;IAC3D,CAAC;IAED;;;;;OAKG;IACH,cAAc,CAAC,aAAqB;QAClC,gDAAgD;QAChD,IAAI,cAAsB,CAAC;QAC3B,IAAI,CAAC;YACH,cAAc,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;QACjE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CAAC,4BAA4B,KAAK,EAAE,CAAC,CAAC;QACvD,CAAC;QAED,OAAO,cAAc,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,SAAS,CAAC;IACrD,CAAC;IAED;;;;OAIG;IACH,eAAe,CAAC,QAAgB;QAC9B,MAAM,UAAU,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;QAC7C,IAAI,CAAC,UAAU;YAAE,MAAM,IAAI,KAAK,CAAC,uBAAuB,QAAQ,EAAE,CAAC,CAAC;QAEpE,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,CAAC,UAAU,CAAC,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC,CAAC;QAC5D,MAAM,QAAQ,GAAG,IAAI,QAAQ,EAAE,CAAC;QAEhC,QAAQ,CAAC,MAAM,CAAC,aAAa,EAAE,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;QAC9D,QAAQ,CAAC,MAAM,CAAC,WAAW,EAAE,mBAAmB,CAAC,CAAC;QAClD,QAAQ,CAAC,MAAM,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC;QAE1C,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,YAAY;QAChB,MAAM,QAAQ,GAAyB,IAAI,CAAC,eAAe,CACzD,IAAI,CAAC,aAAa,CACnB,CAAC;QACF,IAAI,CAAC,QAAQ;YACX,MAAM,IAAI,KAAK,CACb,gCAAgC,IAAI,CAAC,aAAa,EAAE,CACrD,CAAC;QACJ,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE;YACrC,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,QAAQ;SACf,CAAC,CAAC;QACH,IAAI,CAAC,QAAQ,CAAC,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,eAAe,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;QACpE,MAAM,YAAY,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QAE3C,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,cAAc,EAAE,YAAY,CAAC,CAAC;QACpD,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,CAAC,cAAc,EAAE,CAAC,CAAC;IACjD,CAAC;CACF"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"batch-address.test.d.ts","sourceRoot":"","sources":["../src/batch-address.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
2
|
-
import { fs, vol } from "memfs";
|
|
3
|
-
import * as path from "path";
|
|
4
|
-
vi.mock("node:fs", async () => {
|
|
5
|
-
const { fs } = await import("memfs");
|
|
6
|
-
return fs;
|
|
7
|
-
});
|
|
8
|
-
//import BatchAddressGeocoder AFTER fs is mocked
|
|
9
|
-
//so it initializes pointed at mocked module
|
|
10
|
-
import { BatchAddressGeocoder } from "./batch-address.js";
|
|
11
|
-
describe("BatchAddressGeocoder", () => {
|
|
12
|
-
let geocoder;
|
|
13
|
-
// set up memfs dir and file
|
|
14
|
-
const mockFilePath = "/out/mockfile.csv";
|
|
15
|
-
// mock function to replace fetch
|
|
16
|
-
const fetchMock = vi.fn();
|
|
17
|
-
// set test class function
|
|
18
|
-
beforeEach(() => {
|
|
19
|
-
// make fetch mock func globally available
|
|
20
|
-
vi.stubGlobal("fetch", fetchMock);
|
|
21
|
-
// reset the state of in-memory fs
|
|
22
|
-
vol.reset();
|
|
23
|
-
//generate entire filetree
|
|
24
|
-
vol.mkdirSync("/out", { recursive: true });
|
|
25
|
-
//initialize geocoder
|
|
26
|
-
geocoder = new BatchAddressGeocoder("");
|
|
27
|
-
});
|
|
28
|
-
afterEach(() => {
|
|
29
|
-
vi.unstubAllGlobals();
|
|
30
|
-
vi.resetAllMocks();
|
|
31
|
-
});
|
|
32
|
-
it("initializes with the correct endpoint", () => {
|
|
33
|
-
expect(geocoder.url).toEqual("https://geocoding.geo.census.gov/geocoder/locations/addressbatch");
|
|
34
|
-
});
|
|
35
|
-
describe("_parseFilePath", () => {
|
|
36
|
-
it("correctly parses the absolute file path", () => {
|
|
37
|
-
//generate mockFile
|
|
38
|
-
vol.writeFileSync(mockFilePath, "this is some data");
|
|
39
|
-
//point geocoder at mock file
|
|
40
|
-
geocoder.inputFilePath = mockFilePath;
|
|
41
|
-
// get absolute path from BatchAddressGeocoder
|
|
42
|
-
const parsedPath = geocoder._parseFilePath(geocoder.inputFilePath);
|
|
43
|
-
// it should exist
|
|
44
|
-
expect(parsedPath);
|
|
45
|
-
if (parsedPath) {
|
|
46
|
-
// it should be absolute
|
|
47
|
-
expect(path.isAbsolute(parsedPath));
|
|
48
|
-
}
|
|
49
|
-
});
|
|
50
|
-
});
|
|
51
|
-
describe("_createFormData", async () => {
|
|
52
|
-
it("generates accurate form data", async () => {
|
|
53
|
-
//initialize and write to mock file
|
|
54
|
-
const mockFilePath = "/mockfile.csv";
|
|
55
|
-
vol.writeFileSync(mockFilePath, "this is some data");
|
|
56
|
-
//point geocoder at mocked file
|
|
57
|
-
geocoder.inputFilePath = mockFilePath;
|
|
58
|
-
// generate form data
|
|
59
|
-
const formData = geocoder._createFormData(geocoder.inputFilePath);
|
|
60
|
-
// the file field should exist
|
|
61
|
-
expect(formData.get("addressFile")).toBeDefined();
|
|
62
|
-
// it should generate a blob
|
|
63
|
-
const fileField = formData.get("addressFile");
|
|
64
|
-
expect(fileField).toBeInstanceOf(Blob);
|
|
65
|
-
// it should hold data
|
|
66
|
-
expect(fileField.size).toBeGreaterThan(0);
|
|
67
|
-
// it should be text/plain
|
|
68
|
-
expect(fileField.type).toBe("text/plain");
|
|
69
|
-
// content should be accurate
|
|
70
|
-
const text = await fileField.text();
|
|
71
|
-
expect(text).toBe("this is some data");
|
|
72
|
-
});
|
|
73
|
-
});
|
|
74
|
-
describe("geocodeBatch", async () => {
|
|
75
|
-
it("returns correct data in .csv format", async () => {
|
|
76
|
-
const fetchSpy = vi.spyOn(global, "fetch");
|
|
77
|
-
//initialize and write to mock file
|
|
78
|
-
vol.writeFileSync(mockFilePath, "FIELD 1, FIELD 2, FIELD 3, FIELD 4");
|
|
79
|
-
const geocoder = new BatchAddressGeocoder(mockFilePath, "/out/output.csv");
|
|
80
|
-
const geocodeBatchSpy = vi.spyOn(geocoder, "geocodeBatch");
|
|
81
|
-
//mock file blob response
|
|
82
|
-
fetchMock.mockResolvedValue({
|
|
83
|
-
ok: true,
|
|
84
|
-
status: 200,
|
|
85
|
-
text: () => Promise.resolve("FIELD 1, FIELD 2, FIELD 3, FIELD 4"),
|
|
86
|
-
});
|
|
87
|
-
await geocoder.geocodeBatch();
|
|
88
|
-
//geocode function should be called once
|
|
89
|
-
expect(geocodeBatchSpy).toHaveBeenCalledOnce();
|
|
90
|
-
//output file should exist
|
|
91
|
-
expect(fs.existsSync("/out/output.csv")).toBeTruthy;
|
|
92
|
-
//fetch should have been called once
|
|
93
|
-
expect(fetchSpy).toHaveBeenCalledOnce();
|
|
94
|
-
expect(fs.readFileSync("/out/output.csv", "utf-8")).toContain("FIELD 1, FIELD 2, FIELD 3, FIELD 4");
|
|
95
|
-
});
|
|
96
|
-
});
|
|
97
|
-
});
|
|
98
|
-
//# sourceMappingURL=batch-address.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"batch-address.test.js","sourceRoot":"","sources":["../src/batch-address.test.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,cAAc,uBAAuB,CAAC;AACtC,cAAc,oBAAoB,CAAC"}
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Interface for lat/lng coordinates
|
|
3
|
-
* @interface CensusCoordinates
|
|
4
|
-
*/
|
|
5
|
-
export interface CensusCoordinates {
|
|
6
|
-
x: number;
|
|
7
|
-
y: number;
|
|
8
|
-
}
|
|
9
|
-
/**
|
|
10
|
-
* Interface for a single coordinate pair as {@type CensusCoordinates}
|
|
11
|
-
* and the associated matched address, as {@type string}
|
|
12
|
-
* @interface OneLineAddressMatch
|
|
13
|
-
*/
|
|
14
|
-
export interface OneLineAddressMatch {
|
|
15
|
-
coordinates: CensusCoordinates;
|
|
16
|
-
matchedAddress: string;
|
|
17
|
-
}
|
|
18
|
-
/**
|
|
19
|
-
* Interface representing an array of {@type OneLineAddressMatch}
|
|
20
|
-
* @interface OneLineAddressResult
|
|
21
|
-
*/
|
|
22
|
-
export interface OneLineAddressResult {
|
|
23
|
-
addressMatches: OneLineAddressMatch[];
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* Interface for the optional result, of type {@type OneLineAddressResult}
|
|
27
|
-
*/
|
|
28
|
-
export interface OneLineAddressResponse {
|
|
29
|
-
result?: OneLineAddressResult;
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* Returns the first result from whatever address matches it receives
|
|
33
|
-
* @param address {string}
|
|
34
|
-
* @returns {OneLineAddressMatch}
|
|
35
|
-
* @throws {Error} if response status is not OK
|
|
36
|
-
*/
|
|
37
|
-
export declare function geocodeOneLineAddress(address: string): Promise<OneLineAddressMatch | undefined>;
|
|
38
|
-
/**
|
|
39
|
-
* Returns entire array of {@type OneLineAddressMatch}
|
|
40
|
-
* @param {string} address - The address to submit to the census geocoder
|
|
41
|
-
* @returns {OneLineAddressMatch[]} | undefined
|
|
42
|
-
* @throws {Error} if response status is not OK
|
|
43
|
-
*/
|
|
44
|
-
export declare function geocodeOneLineAddressAll(address: string): Promise<OneLineAddressMatch[] | undefined>;
|
|
45
|
-
//# sourceMappingURL=one-line-address.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"one-line-address.d.ts","sourceRoot":"","sources":["../src/one-line-address.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IAChC,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,iBAAiB,CAAC;IAC/B,cAAc,EAAE,MAAM,CAAC;CACxB;AAED;;;GAGG;AACH,MAAM,WAAW,oBAAoB;IACnC,cAAc,EAAE,mBAAmB,EAAE,CAAC;CACvC;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,MAAM,CAAC,EAAE,oBAAoB,CAAC;CAC/B;AAED;;;;;GAKG;AACH,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,mBAAmB,GAAG,SAAS,CAAC,CAkC1C;AAED;;;;;GAKG;AACH,wBAAsB,wBAAwB,CAC5C,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,mBAAmB,EAAE,GAAG,SAAS,CAAC,CAsB5C"}
|
package/dist/one-line-address.js
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Returns the first result from whatever address matches it receives
|
|
3
|
-
* @param address {string}
|
|
4
|
-
* @returns {OneLineAddressMatch}
|
|
5
|
-
* @throws {Error} if response status is not OK
|
|
6
|
-
*/
|
|
7
|
-
export async function geocodeOneLineAddress(address) {
|
|
8
|
-
//format parameters to use latest census data
|
|
9
|
-
const params = new URLSearchParams({
|
|
10
|
-
address,
|
|
11
|
-
benchmark: "Public_AR_Current",
|
|
12
|
-
format: "json",
|
|
13
|
-
});
|
|
14
|
-
const url = `https://geocoding.geo.census.gov/geocoder/locations/onelineaddress?${params}`;
|
|
15
|
-
const response = await fetch(url);
|
|
16
|
-
if (!response.ok)
|
|
17
|
-
throw new Error(`HTTP error: ${response.status}`);
|
|
18
|
-
// Retreives array of coordinates and string of matched addresses from API res
|
|
19
|
-
const data = (await response.json());
|
|
20
|
-
const matches = data.result?.addressMatches;
|
|
21
|
-
if (!matches?.length) {
|
|
22
|
-
console.log(`No matches found for: ${address}`);
|
|
23
|
-
return;
|
|
24
|
-
}
|
|
25
|
-
// warns if multiple matched addresses exist for a single address
|
|
26
|
-
if (matches?.length > 1) {
|
|
27
|
-
console.warn(`Multiple address matches found for ${address}`);
|
|
28
|
-
for (const match of matches) {
|
|
29
|
-
console.warn(`[WARNING}: multimple matched addresses for: ${match.matchedAddress}
|
|
30
|
-
Coordinates:
|
|
31
|
-
X: ${match.coordinates["x"]}
|
|
32
|
-
Y: ${match.coordinates["y"]}
|
|
33
|
-
Consider geocodeOneLineAddressAll()`);
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
return matches[0];
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* Returns entire array of {@type OneLineAddressMatch}
|
|
40
|
-
* @param {string} address - The address to submit to the census geocoder
|
|
41
|
-
* @returns {OneLineAddressMatch[]} | undefined
|
|
42
|
-
* @throws {Error} if response status is not OK
|
|
43
|
-
*/
|
|
44
|
-
export async function geocodeOneLineAddressAll(address) {
|
|
45
|
-
//format parameters to use latest census data
|
|
46
|
-
const params = new URLSearchParams({
|
|
47
|
-
address,
|
|
48
|
-
benchmark: "Public_AR_Current",
|
|
49
|
-
format: "json",
|
|
50
|
-
});
|
|
51
|
-
const url = `https://geocoding.geo.census.gov/geocoder/locations/onelineaddress?${params}`;
|
|
52
|
-
const response = await fetch(url);
|
|
53
|
-
if (!response.ok)
|
|
54
|
-
throw new Error(`HTTP error: ${response.status}`);
|
|
55
|
-
// Retreives array of coordinates and string of matched addresses from API res
|
|
56
|
-
const data = (await response.json());
|
|
57
|
-
const matches = data.result?.addressMatches;
|
|
58
|
-
if (!matches?.length) {
|
|
59
|
-
console.log(`No matches found for: ${address}`);
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
return matches;
|
|
63
|
-
}
|
|
64
|
-
//# sourceMappingURL=one-line-address.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"one-line-address.js","sourceRoot":"","sources":["../src/one-line-address.ts"],"names":[],"mappings":"AAkCA;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,OAAe;IAEf,6CAA6C;IAC7C,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC;QACjC,OAAO;QACP,SAAS,EAAE,mBAAmB;QAC9B,MAAM,EAAE,MAAM;KACf,CAAC,CAAC;IAEH,MAAM,GAAG,GAAG,sEAAsE,MAAM,EAAE,CAAC;IAC3F,MAAM,QAAQ,GAAa,MAAM,KAAK,CAAC,GAAG,CAAC,CAAC;IAC5C,IAAI,CAAC,QAAQ,CAAC,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,eAAe,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IAEpE,8EAA8E;IAC9E,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAA2B,CAAC;IAC/D,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,EAAE,cAAc,CAAC;IAE5C,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC;QACrB,OAAO,CAAC,GAAG,CAAC,yBAAyB,OAAO,EAAE,CAAC,CAAC;QAChD,OAAO;IACT,CAAC;IAED,iEAAiE;IACjE,IAAI,OAAO,EAAE,MAAM,GAAG,CAAC,EAAE,CAAC;QACxB,OAAO,CAAC,IAAI,CAAC,sCAAsC,OAAO,EAAE,CAAC,CAAC;QAC9D,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,OAAO,CAAC,IAAI,CAAC,+CAA+C,KAAK,CAAC,cAAc;;WAE3E,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC;WACtB,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC;0CACS,CAAC,CAAC;QACxC,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC,CAAC,CAAC,CAAC;AACpB,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC5C,OAAe;IAEf,6CAA6C;IAC7C,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC;QACjC,OAAO;QACP,SAAS,EAAE,mBAAmB;QAC9B,MAAM,EAAE,MAAM;KACf,CAAC,CAAC;IAEH,MAAM,GAAG,GAAG,sEAAsE,MAAM,EAAE,CAAC;IAC3F,MAAM,QAAQ,GAAa,MAAM,KAAK,CAAC,GAAG,CAAC,CAAC;IAC5C,IAAI,CAAC,QAAQ,CAAC,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,eAAe,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IAEpE,8EAA8E;IAC9E,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAA2B,CAAC;IAC/D,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,EAAE,cAAc,CAAC;IAE5C,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC;QACrB,OAAO,CAAC,GAAG,CAAC,yBAAyB,OAAO,EAAE,CAAC,CAAC;QAChD,OAAO;IACT,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"one-line-address.test.d.ts","sourceRoot":"","sources":["../src/one-line-address.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
2
|
-
import { geocodeOneLineAddress, geocodeOneLineAddressAll, } from "./one-line-address.js";
|
|
3
|
-
// create mocking function
|
|
4
|
-
const fetchMock = vi.fn();
|
|
5
|
-
beforeEach(() => {
|
|
6
|
-
// substitute mocking function for node "fetch"
|
|
7
|
-
vi.stubGlobal("fetch", fetchMock);
|
|
8
|
-
});
|
|
9
|
-
afterEach(() => {
|
|
10
|
-
// reset everything after testing
|
|
11
|
-
vi.unstubAllGlobals();
|
|
12
|
-
vi.resetAllMocks();
|
|
13
|
-
});
|
|
14
|
-
describe("geocodeOneLineAddress", () => {
|
|
15
|
-
it("returns lat/lng coordinates when response includes a match", async () => {
|
|
16
|
-
fetchMock.mockResolvedValue({
|
|
17
|
-
ok: true,
|
|
18
|
-
json: async () => ({
|
|
19
|
-
result: {
|
|
20
|
-
addressMatches: [
|
|
21
|
-
{
|
|
22
|
-
coordinates: { x: -77.0365, y: 38.8977 },
|
|
23
|
-
matchedAddress: "1600 Pennsylvania Ave NW, Washington, DC",
|
|
24
|
-
},
|
|
25
|
-
],
|
|
26
|
-
},
|
|
27
|
-
}),
|
|
28
|
-
});
|
|
29
|
-
const result = await geocodeOneLineAddress("1600 Pennsylvania Ave NW, Washington, DC");
|
|
30
|
-
//it should exist
|
|
31
|
-
expect(result).toBeTruthy();
|
|
32
|
-
//it should have correct data
|
|
33
|
-
expect(result?.coordinates).toEqual({
|
|
34
|
-
x: -77.0365,
|
|
35
|
-
y: 38.8977,
|
|
36
|
-
});
|
|
37
|
-
expect(result?.matchedAddress).toEqual("1600 Pennsylvania Ave NW, Washington, DC");
|
|
38
|
-
//it should call fetch once per response
|
|
39
|
-
expect(fetchMock).toHaveBeenCalledOnce();
|
|
40
|
-
});
|
|
41
|
-
it("warns when multiple address matches exist", async () => {
|
|
42
|
-
//spy on warn output stream
|
|
43
|
-
const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => { });
|
|
44
|
-
//set up mocked fetch result with multiple entires
|
|
45
|
-
fetchMock.mockResolvedValue({
|
|
46
|
-
ok: true,
|
|
47
|
-
json: async () => ({
|
|
48
|
-
result: {
|
|
49
|
-
addressMatches: [
|
|
50
|
-
{
|
|
51
|
-
coordinates: { x: -77.0365, y: 38.8977 },
|
|
52
|
-
matchedAddress: "1600 Pennsylvania Ave NW, Washington, DC",
|
|
53
|
-
},
|
|
54
|
-
{
|
|
55
|
-
coordinates: { x: -78.0, y: 40.0 },
|
|
56
|
-
matchedAddress: "1602 Pennsylvania Ave NW, Washington, DC",
|
|
57
|
-
},
|
|
58
|
-
],
|
|
59
|
-
},
|
|
60
|
-
}),
|
|
61
|
-
});
|
|
62
|
-
const result = await geocodeOneLineAddress("1600 Pennsylvania Ave NW, Washington, DC");
|
|
63
|
-
//it should exist
|
|
64
|
-
expect(result).toBeTruthy;
|
|
65
|
-
//it should raise a warning
|
|
66
|
-
expect(warnSpy).toHaveBeenCalled();
|
|
67
|
-
//it should raise the correct warning
|
|
68
|
-
expect(warnSpy).toHaveBeenCalledWith(expect.stringContaining("Consider geocodeOneLineAddressAll()"));
|
|
69
|
-
});
|
|
70
|
-
});
|
|
71
|
-
describe("geocodeOneLineAddressAll", () => {
|
|
72
|
-
it("returns array of all matched addresses", async () => {
|
|
73
|
-
fetchMock.mockResolvedValue({
|
|
74
|
-
ok: true,
|
|
75
|
-
json: async () => ({
|
|
76
|
-
result: {
|
|
77
|
-
addressMatches: [
|
|
78
|
-
{
|
|
79
|
-
coordinates: { x: -77.0365, y: 38.8977 },
|
|
80
|
-
matchedAddress: "1600 Pennsylvania Ave NW, Washington, DC",
|
|
81
|
-
},
|
|
82
|
-
{
|
|
83
|
-
coordinates: { x: -78.0, y: 40.0 },
|
|
84
|
-
matchedAddress: "1602 Pennsylvania Ave NW, Washington, DC",
|
|
85
|
-
},
|
|
86
|
-
],
|
|
87
|
-
},
|
|
88
|
-
}),
|
|
89
|
-
});
|
|
90
|
-
const result = await geocodeOneLineAddressAll("1600 Pennsylvania Ave NW, Washington, DC");
|
|
91
|
-
//it should exist
|
|
92
|
-
expect(result).toBeTruthy;
|
|
93
|
-
if (!result)
|
|
94
|
-
return false;
|
|
95
|
-
//it should be the correct size
|
|
96
|
-
expect(result?.length).toBe(2);
|
|
97
|
-
//it should have correct data
|
|
98
|
-
expect(result[0]?.coordinates).toEqual({
|
|
99
|
-
x: -77.0365,
|
|
100
|
-
y: 38.8977,
|
|
101
|
-
});
|
|
102
|
-
expect(result[0]?.matchedAddress).toEqual("1600 Pennsylvania Ave NW, Washington, DC");
|
|
103
|
-
expect(result[1]?.coordinates).toEqual({
|
|
104
|
-
x: -78.0,
|
|
105
|
-
y: 40.0,
|
|
106
|
-
});
|
|
107
|
-
expect(result[1]?.matchedAddress).toEqual("1602 Pennsylvania Ave NW, Washington, DC");
|
|
108
|
-
//it should call fetch once per response
|
|
109
|
-
expect(fetchMock).toHaveBeenCalledOnce();
|
|
110
|
-
});
|
|
111
|
-
});
|
|
112
|
-
//# sourceMappingURL=one-line-address.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"one-line-address.test.js","sourceRoot":"","sources":["../src/one-line-address.test.ts"],"names":[],"mappings":"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"}
|