@land-catalyst/batch-data-sdk 1.1.12 → 1.1.19

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.
@@ -0,0 +1,479 @@
1
+ "use strict";
2
+ /**
3
+ * Property Field Utilities
4
+ *
5
+ * Utilities for working with property field paths and metadata
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.getPropertyFieldMetadata = getPropertyFieldMetadata;
9
+ exports.getPropertyFieldValue = getPropertyFieldValue;
10
+ exports.getPropertyGroupFields = getPropertyGroupFields;
11
+ exports.getNestedFieldMetadata = getNestedFieldMetadata;
12
+ exports.isValidPropertyField = isValidPropertyField;
13
+ exports.getPropertyGroupFieldPaths = getPropertyGroupFieldPaths;
14
+ exports.getPropertyFieldDescription = getPropertyFieldDescription;
15
+ exports.getPropertyFieldType = getPropertyFieldType;
16
+ exports.mapSearchCriteriaToPropertyPath = mapSearchCriteriaToPropertyPath;
17
+ exports.getSearchCriteriaFieldMetadata = getSearchCriteriaFieldMetadata;
18
+ exports.getSearchCriteriaMetadata = getSearchCriteriaMetadata;
19
+ exports.getSearchCriteriaFieldsForPropertyGroup = getSearchCriteriaFieldsForPropertyGroup;
20
+ exports.getSearchCriteriaFieldsWithMetadata = getSearchCriteriaFieldsWithMetadata;
21
+ exports.getSearchCriteriaMetadataForGroup = getSearchCriteriaMetadataForGroup;
22
+ exports.extractSearchCriteriaFieldPaths = extractSearchCriteriaFieldPaths;
23
+ exports.getSearchCriteriaFieldsMetadata = getSearchCriteriaFieldsMetadata;
24
+ exports.getPropertyFieldsMetadata = getPropertyFieldsMetadata;
25
+ const metadata_1 = require("./metadata");
26
+ /**
27
+ * Get metadata for a property field by its path
28
+ * @param fieldPath The field path (e.g., "address.city", "owner.fullName")
29
+ * @returns The field metadata, or undefined if not found
30
+ * @example
31
+ * ```typescript
32
+ * const cityMeta = getPropertyFieldMetadata("address.city");
33
+ * console.log(cityMeta?.description); // "The city (e.g. Chicago)"
34
+ * ```
35
+ */
36
+ function getPropertyFieldMetadata(fieldPath) {
37
+ return (0, metadata_1.getFieldMetadata)(fieldPath);
38
+ }
39
+ /**
40
+ * Get the value at a field path from a property object
41
+ * @param property The property object
42
+ * @param fieldPath The field path (e.g., "address.city", "owner.fullName")
43
+ * @returns The value at the path, or undefined if not found
44
+ * @example
45
+ * ```typescript
46
+ * const city = getPropertyFieldValue(property, "address.city");
47
+ * ```
48
+ */
49
+ function getPropertyFieldValue(property, fieldPath) {
50
+ const parts = fieldPath.split(".");
51
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
52
+ let value = property;
53
+ for (const part of parts) {
54
+ if (value == null) {
55
+ return undefined;
56
+ }
57
+ // Handle array notation like "[n]"
58
+ if (part === "[n]") {
59
+ // This is an array element - return the array itself
60
+ continue;
61
+ }
62
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
63
+ value = value[part];
64
+ }
65
+ return value;
66
+ }
67
+ /**
68
+ * Get metadata for all fields in a response group
69
+ * @param groupName The response group name (e.g., "address", "owner", "building")
70
+ * @returns Array of field metadata for that group
71
+ * @example
72
+ * ```typescript
73
+ * const addressFields = getPropertyGroupFields("address");
74
+ * // Returns all fields under address.*
75
+ * ```
76
+ */
77
+ function getPropertyGroupFields(groupName) {
78
+ return Object.values(metadata_1.PROPERTY_FIELD_METADATA).filter((field) => field.responseGroupName === groupName);
79
+ }
80
+ /**
81
+ * Get metadata for a nested field path
82
+ * Handles nested paths like "owner.mailingAddress.city"
83
+ * @param fieldPath The full field path
84
+ * @returns The field metadata, or undefined if not found
85
+ */
86
+ function getNestedFieldMetadata(fieldPath) {
87
+ return (0, metadata_1.getFieldMetadata)(fieldPath);
88
+ }
89
+ /**
90
+ * Type guard to check if a field path exists in metadata
91
+ * @param fieldPath The field path to check
92
+ * @returns True if the field exists in metadata
93
+ */
94
+ function isValidPropertyField(fieldPath) {
95
+ return fieldPath in metadata_1.PROPERTY_FIELD_METADATA;
96
+ }
97
+ /**
98
+ * Get all field paths for a specific property group
99
+ * @param groupName The response group name
100
+ * @returns Array of field paths
101
+ */
102
+ function getPropertyGroupFieldPaths(groupName) {
103
+ return Object.values(metadata_1.PROPERTY_FIELD_METADATA)
104
+ .filter((field) => field.responseGroupName === groupName)
105
+ .map((field) => field.fieldPath);
106
+ }
107
+ /**
108
+ * Get field description for a property field
109
+ * @param fieldPath The field path
110
+ * @returns The description, or undefined if not found
111
+ */
112
+ function getPropertyFieldDescription(fieldPath) {
113
+ return (0, metadata_1.getFieldMetadata)(fieldPath)?.description;
114
+ }
115
+ /**
116
+ * Get field data type for a property field
117
+ * @param fieldPath The field path
118
+ * @returns The data type, or undefined if not found
119
+ */
120
+ function getPropertyFieldType(fieldPath) {
121
+ return (0, metadata_1.getFieldMetadata)(fieldPath)?.dataType;
122
+ }
123
+ /**
124
+ * Map a SearchCriteria field path to its corresponding Property field path
125
+ * Most SearchCriteria fields map directly to Property fields (e.g., "address.city" -> "address.city")
126
+ * @param searchCriteriaPath The field path in SearchCriteria (e.g., "address.city", "building.yearBuilt")
127
+ * @returns The corresponding Property field path, or undefined if no mapping exists
128
+ * @example
129
+ * ```typescript
130
+ * const propertyPath = mapSearchCriteriaToPropertyPath("address.city");
131
+ * // Returns "address.city"
132
+ *
133
+ * const propertyPath = mapSearchCriteriaToPropertyPath("building.yearBuilt");
134
+ * // Returns "building.yearBuilt"
135
+ * ```
136
+ */
137
+ function mapSearchCriteriaToPropertyPath(searchCriteriaPath) {
138
+ // Most SearchCriteria paths map directly to Property paths
139
+ // The field names are the same, just used in different contexts
140
+ // Examples:
141
+ // - SearchCriteria.address.city -> Property.address.city
142
+ // - SearchCriteria.building.yearBuilt -> Property.building.yearBuilt
143
+ // - SearchCriteria.assessment.assessmentYear -> Property.assessment.assessmentYear (if exists)
144
+ // Check if the path exists in Property metadata
145
+ if (searchCriteriaPath in metadata_1.PROPERTY_FIELD_METADATA) {
146
+ return searchCriteriaPath;
147
+ }
148
+ // If not found, return undefined to indicate no mapping exists
149
+ // The caller can use this to determine if there's a Property field mapping
150
+ return undefined;
151
+ }
152
+ /**
153
+ * Get Property field metadata for a SearchCriteria field path
154
+ * This helps users understand what Property field they're filtering on
155
+ * @param searchCriteriaPath The field path in SearchCriteria (e.g., "address.city", "building.yearBuilt")
156
+ * @returns The Property field metadata, or undefined if not found
157
+ * @example
158
+ * ```typescript
159
+ * // When building a search criteria, see what Property field you're filtering on
160
+ * const metadata = getSearchCriteriaFieldMetadata("address.city");
161
+ * console.log(metadata?.description); // "The city (e.g. Chicago)"
162
+ * console.log(metadata?.dataType); // "string"
163
+ *
164
+ * const builder = new AddressSearchCriteriaBuilder();
165
+ * builder.city((c) => {
166
+ * // You're filtering on Property.address.city
167
+ * const meta = getSearchCriteriaFieldMetadata("address.city");
168
+ * console.log(`Filtering on: ${meta?.description}`);
169
+ * c.equals("Phoenix");
170
+ * });
171
+ * ```
172
+ */
173
+ function getSearchCriteriaFieldMetadata(searchCriteriaPath) {
174
+ const propertyPath = mapSearchCriteriaToPropertyPath(searchCriteriaPath);
175
+ if (!propertyPath) {
176
+ return undefined;
177
+ }
178
+ return (0, metadata_1.getFieldMetadata)(propertyPath);
179
+ }
180
+ /**
181
+ * Get SearchCriteria field metadata inferred from Property field metadata
182
+ * This creates a SearchCriteria-specific metadata object that references the Property field
183
+ * @param searchCriteriaPath The field path in SearchCriteria (e.g., "address.city", "building.yearBuilt")
184
+ * @returns SearchCriteria field metadata with Property field information
185
+ * @example
186
+ * ```typescript
187
+ * // Get metadata for a SearchCriteria field, even if it doesn't map exactly
188
+ * const scMetadata = getSearchCriteriaMetadata("address.city");
189
+ * console.log(scMetadata.description); // "Filter on: The city (e.g. Chicago)"
190
+ * console.log(scMetadata.propertyPath); // "address.city"
191
+ * console.log(scMetadata.hasPropertyMapping); // true
192
+ *
193
+ * // Works even for fields that might not have exact Property mappings
194
+ * const scMetadata2 = getSearchCriteriaMetadata("assessment.assessmentYear");
195
+ * if (scMetadata2.hasPropertyMapping) {
196
+ * console.log(`Filtering on: ${scMetadata2.propertyMetadata?.description}`);
197
+ * }
198
+ * ```
199
+ */
200
+ function getSearchCriteriaMetadata(searchCriteriaPath) {
201
+ const propertyPath = mapSearchCriteriaToPropertyPath(searchCriteriaPath);
202
+ const propertyMetadata = propertyPath
203
+ ? (0, metadata_1.getFieldMetadata)(propertyPath)
204
+ : undefined;
205
+ // Generate description based on Property metadata
206
+ let description;
207
+ if (propertyMetadata) {
208
+ // If we have Property metadata, create a description that explains
209
+ // this SearchCriteria field filters on that Property field
210
+ description = `Filter on: ${propertyMetadata.description}`;
211
+ }
212
+ else {
213
+ // If no Property metadata, create a generic description
214
+ const parts = searchCriteriaPath.split(".");
215
+ const fieldName = parts[parts.length - 1] || searchCriteriaPath;
216
+ description = `Filter on ${fieldName} field`;
217
+ }
218
+ return {
219
+ searchCriteriaPath,
220
+ propertyPath,
221
+ propertyMetadata: propertyMetadata || undefined,
222
+ hasPropertyMapping: propertyMetadata !== undefined,
223
+ description,
224
+ propertyDataType: propertyMetadata?.dataType,
225
+ dataset: propertyMetadata?.dataset,
226
+ };
227
+ }
228
+ /**
229
+ * Get all SearchCriteria field paths that map to a specific Property response group
230
+ * @param propertyGroupName The Property response group name (e.g., "address", "owner", "building")
231
+ * @returns Array of SearchCriteria field paths that filter on fields in that group
232
+ * @example
233
+ * ```typescript
234
+ * // Get all SearchCriteria fields that filter on address fields
235
+ * const addressSearchFields = getSearchCriteriaFieldsForPropertyGroup("address");
236
+ * // Returns: ["address.street", "address.city", "address.state", ...]
237
+ * ```
238
+ */
239
+ function getSearchCriteriaFieldsForPropertyGroup(propertyGroupName) {
240
+ // Get all Property fields in this group
241
+ const propertyFields = getPropertyGroupFields(propertyGroupName);
242
+ // Map them to SearchCriteria paths (usually 1:1)
243
+ return propertyFields.map((field) => field.fieldPath);
244
+ }
245
+ function getSearchCriteriaFieldsWithMetadata(propertyGroupName) {
246
+ const propertyFields = getPropertyGroupFields(propertyGroupName);
247
+ return propertyFields.map((field) => ({
248
+ searchCriteriaPath: field.fieldPath,
249
+ propertyPath: field.fieldPath,
250
+ metadata: field,
251
+ }));
252
+ }
253
+ /**
254
+ * Get SearchCriteria metadata for all fields in a Property response group
255
+ * @param propertyGroupName The Property response group name (e.g., "address", "owner", "building")
256
+ * @returns Array of SearchCriteria field metadata objects
257
+ * @example
258
+ * ```typescript
259
+ * // Get all address-related SearchCriteria fields with inferred metadata
260
+ * const addressFields = getSearchCriteriaMetadataForGroup("address");
261
+ * // Returns SearchCriteriaFieldMetadata[] with descriptions like
262
+ * // "Filter on: The city (e.g. Chicago)"
263
+ * ```
264
+ */
265
+ function getSearchCriteriaMetadataForGroup(propertyGroupName) {
266
+ const propertyFields = getPropertyGroupFields(propertyGroupName);
267
+ return propertyFields.map((field) => getSearchCriteriaMetadata(field.fieldPath));
268
+ }
269
+ /**
270
+ * Extract all field paths from a SearchCriteria object
271
+ * Recursively walks through the SearchCriteria structure and collects all field paths
272
+ * @param searchCriteria The SearchCriteria object to analyze
273
+ * @param prefix Optional prefix for nested paths (used internally for recursion)
274
+ * @returns Array of field paths found in the SearchCriteria
275
+ * @example
276
+ * ```typescript
277
+ * const criteria = {
278
+ * address: { city: { equals: "Phoenix" }, state: { equals: "AZ" } },
279
+ * building: { yearBuilt: { min: 1990, max: 2020 } }
280
+ * };
281
+ * const paths = extractSearchCriteriaFieldPaths(criteria);
282
+ * // Returns: ["address.city", "address.state", "building.yearBuilt"]
283
+ * ```
284
+ */
285
+ function extractSearchCriteriaFieldPaths(searchCriteria, prefix = "") {
286
+ const paths = [];
287
+ function processValue(value, currentPath) {
288
+ if (value == null) {
289
+ return;
290
+ }
291
+ // Check if this is a filter object (StringFilter, NumericRangeFilter, etc.)
292
+ if (typeof value === "object" && !Array.isArray(value)) {
293
+ const obj = value;
294
+ const filterKeys = [
295
+ "equals",
296
+ "contains",
297
+ "startsWith",
298
+ "endsWith",
299
+ "inList",
300
+ "notInList",
301
+ "matches",
302
+ "min",
303
+ "max",
304
+ "minDate",
305
+ "maxDate",
306
+ ];
307
+ const isFilterObject = filterKeys.some((key) => key in obj);
308
+ if (isFilterObject) {
309
+ // This is a filter object, so the current path is the field path
310
+ if (currentPath) {
311
+ paths.push(currentPath);
312
+ }
313
+ return; // Don't recurse into filter objects
314
+ }
315
+ // It's a nested criteria object, process its properties
316
+ for (const [key, val] of Object.entries(obj)) {
317
+ // Skip special fields
318
+ if (key === "query" ||
319
+ key === "quickList" ||
320
+ key === "quickLists" ||
321
+ key === "orQuickLists" ||
322
+ key === "or") {
323
+ continue;
324
+ }
325
+ const fieldPath = currentPath ? `${currentPath}.${key}` : key;
326
+ processValue(val, fieldPath);
327
+ }
328
+ }
329
+ else if (Array.isArray(value)) {
330
+ // Handle arrays (like orQuickLists, or criteria)
331
+ value.forEach((item, index) => {
332
+ if (typeof item === "object" && item !== null) {
333
+ processValue(item, `${currentPath}[${index}]`);
334
+ }
335
+ });
336
+ }
337
+ }
338
+ // Start processing
339
+ for (const [key, value] of Object.entries(searchCriteria)) {
340
+ // Skip special top-level fields
341
+ if (key === "query" ||
342
+ key === "quickList" ||
343
+ key === "quickLists" ||
344
+ key === "orQuickLists" ||
345
+ key === "or") {
346
+ continue;
347
+ }
348
+ const fieldPath = prefix ? `${prefix}.${key}` : key;
349
+ processValue(value, fieldPath);
350
+ }
351
+ return paths;
352
+ }
353
+ /**
354
+ * Get metadata for all fields present in a SearchCriteria object
355
+ * Extracts all field paths and generates metadata for each one
356
+ * @param searchCriteria The SearchCriteria object to analyze
357
+ * @returns Array of SearchCriteria field metadata for all fields found
358
+ * @example
359
+ * ```typescript
360
+ * const criteria = new SearchCriteriaBuilder("US")
361
+ * .address((a) => {
362
+ * a.city((c) => c.equals("Phoenix"))
363
+ * .state((s) => s.equals("AZ"));
364
+ * })
365
+ * .building((b) => {
366
+ * b.yearBuilt((y) => y.min(1990).max(2020));
367
+ * })
368
+ * .build();
369
+ *
370
+ * const metadata = getSearchCriteriaFieldsMetadata(criteria);
371
+ * // Returns metadata for address.city, address.state, building.yearBuilt
372
+ * ```
373
+ */
374
+ function getSearchCriteriaFieldsMetadata(searchCriteria) {
375
+ const fieldPaths = extractSearchCriteriaFieldPaths(searchCriteria);
376
+ return fieldPaths.map((path) => getSearchCriteriaMetadata(path));
377
+ }
378
+ /**
379
+ * Get metadata for all fields present in a property object
380
+ * Recursively iterates through the property object and collects metadata for each field.
381
+ *
382
+ * Note: This function is designed for Property response objects, not SearchCriteria.
383
+ * The metadata describes Property response fields (their types, descriptions, datasets),
384
+ * which are different from SearchCriteria filter objects.
385
+ *
386
+ * @param property The property object to analyze
387
+ * @param prefix Optional prefix for nested paths (used internally for recursion)
388
+ * @returns Array of field metadata entries
389
+ * @example
390
+ * ```typescript
391
+ * const property = {
392
+ * address: { city: "Phoenix", state: "AZ" },
393
+ * owner: { fullName: "John Doe" }
394
+ * };
395
+ * const metadata = getPropertyFieldsMetadata(property);
396
+ * // Returns metadata for address.city, address.state, owner.fullName
397
+ * ```
398
+ */
399
+ function getPropertyFieldsMetadata(property, prefix = "") {
400
+ const entries = [];
401
+ // Helper function to recursively process objects
402
+ function processValue(value, currentPath, depth = 0) {
403
+ // Limit recursion depth to prevent infinite loops
404
+ if (depth > 10) {
405
+ return;
406
+ }
407
+ if (value == null) {
408
+ return;
409
+ }
410
+ // Handle arrays
411
+ if (Array.isArray(value)) {
412
+ // For arrays, check if there's metadata for the array element pattern
413
+ const arrayPath = currentPath ? `${currentPath}.[n]` : "[n]";
414
+ const arrayMetadata = (0, metadata_1.getFieldMetadata)(arrayPath);
415
+ if (arrayMetadata) {
416
+ entries.push({
417
+ fieldPath: currentPath || arrayPath,
418
+ value: value,
419
+ metadata: arrayMetadata,
420
+ hasMetadata: true,
421
+ });
422
+ }
423
+ // Process each element in the array
424
+ value.forEach((item, index) => {
425
+ if (typeof item === "object" && item !== null) {
426
+ processValue(item, `${currentPath}.[${index}]`, depth + 1);
427
+ }
428
+ });
429
+ return;
430
+ }
431
+ // Handle objects
432
+ if (typeof value === "object" && value !== null) {
433
+ const obj = value;
434
+ // Process each property in the object
435
+ for (const [key, val] of Object.entries(obj)) {
436
+ const fieldPath = currentPath ? `${currentPath}.${key}` : key;
437
+ // Try to get metadata for this field path
438
+ const metadata = (0, metadata_1.getFieldMetadata)(fieldPath);
439
+ // Add entry for this field
440
+ entries.push({
441
+ fieldPath,
442
+ value: val,
443
+ metadata,
444
+ hasMetadata: metadata !== undefined,
445
+ });
446
+ // Recursively process nested objects
447
+ if (val != null && typeof val === "object" && !Array.isArray(val)) {
448
+ processValue(val, fieldPath, depth + 1);
449
+ }
450
+ else if (Array.isArray(val)) {
451
+ // Process array elements
452
+ processValue(val, fieldPath, depth + 1);
453
+ }
454
+ }
455
+ }
456
+ }
457
+ // Start processing from the root
458
+ if (prefix) {
459
+ processValue(property, prefix, 0);
460
+ }
461
+ else {
462
+ // Process top-level properties
463
+ for (const [key, value] of Object.entries(property)) {
464
+ const fieldPath = key;
465
+ const metadata = (0, metadata_1.getFieldMetadata)(fieldPath);
466
+ entries.push({
467
+ fieldPath,
468
+ value,
469
+ metadata,
470
+ hasMetadata: metadata !== undefined,
471
+ });
472
+ // Recursively process nested objects and arrays
473
+ if (value != null) {
474
+ processValue(value, fieldPath, 0);
475
+ }
476
+ }
477
+ }
478
+ return entries;
479
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@land-catalyst/batch-data-sdk",
3
- "version": "1.1.12",
3
+ "version": "1.1.19",
4
4
  "description": "TypeScript SDK for BatchData.io Property API - Types, Builders, and Utilities",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -18,6 +18,9 @@
18
18
  "lint:fix": "eslint src --fix",
19
19
  "format": "prettier --write \"src/**/*.ts\"",
20
20
  "format:check": "prettier --check \"src/**/*.ts\"",
21
+ "generate:metadata": "node scripts/generate-property-field-metadata.js",
22
+ "generate:docs": "npx tsx scripts/generate-property-type-docs.ts",
23
+ "add:jsdoc": "node scripts/add-jsdoc-to-types.js",
21
24
  "v:patch": "npm version patch && git push --follow-tags",
22
25
  "v:minor": "npm version minor && git push --follow-tags",
23
26
  "v:major": "npm version major && git push --follow-tags"
@@ -34,7 +37,7 @@
34
37
  "license": "MIT",
35
38
  "repository": {
36
39
  "type": "git",
37
- "url": "https://github.com/land-catalyst/batch-data-sdk.git"
40
+ "url": "git+https://github.com/land-catalyst/batch-data-sdk.git"
38
41
  },
39
42
  "dependencies": {
40
43
  "axios": "^1.7.9"
File without changes
File without changes
File without changes