phil-address
Version:
Lightweight Philippine address data fetcher with smart caching, search, and request deduplication
1,477 lines (1,438 loc) • 49.8 kB
JavaScript
function _arrayLikeToArray(r, a) {
(null == a || a > r.length) && (a = r.length);
for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e];
return n;
}
function _arrayWithHoles(r) {
if (Array.isArray(r)) return r;
}
function _arrayWithoutHoles(r) {
if (Array.isArray(r)) return _arrayLikeToArray(r);
}
function asyncGeneratorStep(n, t, e, r, o, a, c) {
try {
var i = n[a](c),
u = i.value;
} catch (n) {
return void e(n);
}
i.done ? t(u) : Promise.resolve(u).then(r, o);
}
function _asyncToGenerator(n) {
return function () {
var t = this,
e = arguments;
return new Promise(function (r, o) {
var a = n.apply(t, e);
function _next(n) {
asyncGeneratorStep(a, r, o, _next, _throw, "next", n);
}
function _throw(n) {
asyncGeneratorStep(a, r, o, _next, _throw, "throw", n);
}
_next(void 0);
});
};
}
function _createForOfIteratorHelper(r, e) {
var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
if (!t) {
if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) {
t && (r = t);
var n = 0,
F = function () {};
return {
s: F,
n: function () {
return n >= r.length ? {
done: !0
} : {
done: !1,
value: r[n++]
};
},
e: function (r) {
throw r;
},
f: F
};
}
throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
var o,
a = !0,
u = !1;
return {
s: function () {
t = t.call(r);
},
n: function () {
var r = t.next();
return a = r.done, r;
},
e: function (r) {
u = !0, o = r;
},
f: function () {
try {
a || null == t.return || t.return();
} finally {
if (u) throw o;
}
}
};
}
function _defineProperty(e, r, t) {
return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
value: t,
enumerable: !0,
configurable: !0,
writable: !0
}) : e[r] = t, e;
}
function _iterableToArray(r) {
if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r);
}
function _iterableToArrayLimit(r, l) {
var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
if (null != t) {
var e,
n,
i,
u,
a = [],
f = !0,
o = !1;
try {
if (i = (t = t.call(r)).next, 0 === l) {
if (Object(t) !== t) return;
f = !1;
} else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0);
} catch (r) {
o = !0, n = r;
} finally {
try {
if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return;
} finally {
if (o) throw n;
}
}
return a;
}
}
function _nonIterableRest() {
throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
function _nonIterableSpread() {
throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
function ownKeys(e, r) {
var t = Object.keys(e);
if (Object.getOwnPropertySymbols) {
var o = Object.getOwnPropertySymbols(e);
r && (o = o.filter(function (r) {
return Object.getOwnPropertyDescriptor(e, r).enumerable;
})), t.push.apply(t, o);
}
return t;
}
function _objectSpread2(e) {
for (var r = 1; r < arguments.length; r++) {
var t = null != arguments[r] ? arguments[r] : {};
r % 2 ? ownKeys(Object(t), !0).forEach(function (r) {
_defineProperty(e, r, t[r]);
}) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) {
Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r));
});
}
return e;
}
function _regenerator() {
/*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/babel/babel/blob/main/packages/babel-helpers/LICENSE */
var e,
t,
r = "function" == typeof Symbol ? Symbol : {},
n = r.iterator || "@@iterator",
o = r.toStringTag || "@@toStringTag";
function i(r, n, o, i) {
var c = n && n.prototype instanceof Generator ? n : Generator,
u = Object.create(c.prototype);
return _regeneratorDefine(u, "_invoke", function (r, n, o) {
var i,
c,
u,
f = 0,
p = o || [],
y = !1,
G = {
p: 0,
n: 0,
v: e,
a: d,
f: d.bind(e, 4),
d: function (t, r) {
return i = t, c = 0, u = e, G.n = r, a;
}
};
function d(r, n) {
for (c = r, u = n, t = 0; !y && f && !o && t < p.length; t++) {
var o,
i = p[t],
d = G.p,
l = i[2];
r > 3 ? (o = l === n) && (u = i[(c = i[4]) ? 5 : (c = 3, 3)], i[4] = i[5] = e) : i[0] <= d && ((o = r < 2 && d < i[1]) ? (c = 0, G.v = n, G.n = i[1]) : d < l && (o = r < 3 || i[0] > n || n > l) && (i[4] = r, i[5] = n, G.n = l, c = 0));
}
if (o || r > 1) return a;
throw y = !0, n;
}
return function (o, p, l) {
if (f > 1) throw TypeError("Generator is already running");
for (y && 1 === p && d(p, l), c = p, u = l; (t = c < 2 ? e : u) || !y;) {
i || (c ? c < 3 ? (c > 1 && (G.n = -1), d(c, u)) : G.n = u : G.v = u);
try {
if (f = 2, i) {
if (c || (o = "next"), t = i[o]) {
if (!(t = t.call(i, u))) throw TypeError("iterator result is not an object");
if (!t.done) return t;
u = t.value, c < 2 && (c = 0);
} else 1 === c && (t = i.return) && t.call(i), c < 2 && (u = TypeError("The iterator does not provide a '" + o + "' method"), c = 1);
i = e;
} else if ((t = (y = G.n < 0) ? u : r.call(n, G)) !== a) break;
} catch (t) {
i = e, c = 1, u = t;
} finally {
f = 1;
}
}
return {
value: t,
done: y
};
};
}(r, o, i), !0), u;
}
var a = {};
function Generator() {}
function GeneratorFunction() {}
function GeneratorFunctionPrototype() {}
t = Object.getPrototypeOf;
var c = [][n] ? t(t([][n]())) : (_regeneratorDefine(t = {}, n, function () {
return this;
}), t),
u = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(c);
function f(e) {
return Object.setPrototypeOf ? Object.setPrototypeOf(e, GeneratorFunctionPrototype) : (e.__proto__ = GeneratorFunctionPrototype, _regeneratorDefine(e, o, "GeneratorFunction")), e.prototype = Object.create(u), e;
}
return GeneratorFunction.prototype = GeneratorFunctionPrototype, _regeneratorDefine(u, "constructor", GeneratorFunctionPrototype), _regeneratorDefine(GeneratorFunctionPrototype, "constructor", GeneratorFunction), GeneratorFunction.displayName = "GeneratorFunction", _regeneratorDefine(GeneratorFunctionPrototype, o, "GeneratorFunction"), _regeneratorDefine(u), _regeneratorDefine(u, o, "Generator"), _regeneratorDefine(u, n, function () {
return this;
}), _regeneratorDefine(u, "toString", function () {
return "[object Generator]";
}), (_regenerator = function () {
return {
w: i,
m: f
};
})();
}
function _regeneratorDefine(e, r, n, t) {
var i = Object.defineProperty;
try {
i({}, "", {});
} catch (e) {
i = 0;
}
_regeneratorDefine = function (e, r, n, t) {
if (r) i ? i(e, r, {
value: n,
enumerable: !t,
configurable: !t,
writable: !t
}) : e[r] = n;else {
function o(r, n) {
_regeneratorDefine(e, r, function (e) {
return this._invoke(r, n, e);
});
}
o("next", 0), o("throw", 1), o("return", 2);
}
}, _regeneratorDefine(e, r, n, t);
}
function _regeneratorValues(e) {
if (null != e) {
var t = e["function" == typeof Symbol && Symbol.iterator || "@@iterator"],
r = 0;
if (t) return t.call(e);
if ("function" == typeof e.next) return e;
if (!isNaN(e.length)) return {
next: function () {
return e && r >= e.length && (e = void 0), {
value: e && e[r++],
done: !e
};
}
};
}
throw new TypeError(typeof e + " is not iterable");
}
function _slicedToArray(r, e) {
return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest();
}
function _toConsumableArray(r) {
return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread();
}
function _toPrimitive(t, r) {
if ("object" != typeof t || !t) return t;
var e = t[Symbol.toPrimitive];
if (void 0 !== e) {
var i = e.call(t, r || "default");
if ("object" != typeof i) return i;
throw new TypeError("@@toPrimitive must return a primitive value.");
}
return ("string" === r ? String : Number)(t);
}
function _toPropertyKey(t) {
var i = _toPrimitive(t, "string");
return "symbol" == typeof i ? i : i + "";
}
function _unsupportedIterableToArray(r, a) {
if (r) {
if ("string" == typeof r) return _arrayLikeToArray(r, a);
var t = {}.toString.call(r).slice(8, -1);
return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0;
}
}
// ---------------------------------------------------------------------
// API Base URL and Cache Configuration
// ---------------------------------------------------------------------
/**
* The base URL for the Philippine address API.
* All subsequent API calls will prepend this URL.
*
* @constant {string}
*/
var API = 'https://phil-address-api.portal-api.workers.dev';
/**
* Cache Time-To-Live in milliseconds.
* The default value (1 hour) determines how long cached data remains valid.
*
* @constant {number}
*/
var CACHE_TTL = 3600000;
// ---------------------------------------------------------------------
// Caching Variables with TTL Support
// ---------------------------------------------------------------------
/**
* Cache for regions data.
* @type {{data: Array|null, timestamp: number}}
*/
var regionsCache = {
data: null,
timestamp: 0
};
/**
* Cache for provinces data, keyed by region code.
* @type {Object.<string, {data: Array, timestamp: number}>}
*/
var provincesCache = {};
/**
* Cache for cities data, keyed by province code.
* @type {Object.<string, {data: Array, timestamp: number}>}
*/
var citiesCache = {};
/**
* Cache for barangays data, keyed by city code.
* @type {Object.<string, {data: Array, timestamp: number}>}
*/
var barangaysCache = {};
// ---------------------------------------------------------------------
// Request Deduplication
// Prevents multiple simultaneous requests for the same resource
// ---------------------------------------------------------------------
/**
* Pending requests map to prevent duplicate API calls
* @type {Map<string, Promise>}
*/
var pendingRequests = new Map();
// ---------------------------------------------------------------------
// Configuration Options
// ---------------------------------------------------------------------
/**
* Global configuration options
* @type {{cacheTTL: number, timeout: number, retries: number}}
*/
var config = {
cacheTTL: CACHE_TTL,
timeout: 10000,
// 10 seconds
retries: 3
};
/**
* Configure the package settings
* @param {Object} options - Configuration options
* @param {number} [options.cacheTTL] - Cache TTL in milliseconds
* @param {number} [options.timeout] - Request timeout in milliseconds
* @param {number} [options.retries] - Number of retry attempts
*/
function configure(options) {
config = _objectSpread2(_objectSpread2({}, config), options);
}
// ---------------------------------------------------------------------
// Utility Functions
// ---------------------------------------------------------------------
/**
* Performs a fetch request with timeout and retry logic
* @param {string} url - The URL to fetch
* @param {number} [retries] - Number of retry attempts remaining
* @returns {Promise<Response>}
*/
function fetchWithTimeout(_x) {
return _fetchWithTimeout.apply(this, arguments);
}
/**
* Performance monitoring configuration
*/
function _fetchWithTimeout() {
_fetchWithTimeout = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee(url) {
var retries,
controller,
timeout,
response,
_args = arguments,
_t;
return _regenerator().w(function (_context) {
while (1) switch (_context.n) {
case 0:
retries = _args.length > 1 && _args[1] !== undefined ? _args[1] : config.retries;
controller = new AbortController();
timeout = setTimeout(function () {
return controller.abort();
}, config.timeout);
_context.p = 1;
_context.n = 2;
return fetch(url, {
signal: controller.signal
});
case 2:
response = _context.v;
clearTimeout(timeout);
if (!(!response.ok && retries > 0)) {
_context.n = 4;
break;
}
_context.n = 3;
return new Promise(function (resolve) {
return setTimeout(resolve, (config.retries - retries + 1) * 1000);
});
case 3:
return _context.a(2, fetchWithTimeout(url, retries - 1));
case 4:
return _context.a(2, response);
case 5:
_context.p = 5;
_t = _context.v;
clearTimeout(timeout);
if (!(_t.name === 'AbortError')) {
_context.n = 6;
break;
}
throw new Error('Request timeout');
case 6:
if (!(retries > 0)) {
_context.n = 8;
break;
}
_context.n = 7;
return new Promise(function (resolve) {
return setTimeout(resolve, (config.retries - retries + 1) * 1000);
});
case 7:
return _context.a(2, fetchWithTimeout(url, retries - 1));
case 8:
throw _t;
case 9:
return _context.a(2);
}
}, _callee, null, [[1, 5]]);
}));
return _fetchWithTimeout.apply(this, arguments);
}
var performanceConfig = {
enabled: false,
logSlowRequests: true,
slowRequestThreshold: 1000 // ms
};
/**
* Performance metrics storage
*/
var performanceMetrics = {
apiCalls: 0,
cacheHits: 0,
cacheMisses: 0,
totalResponseTime: 0,
slowRequests: []
};
/**
* Enable/disable performance monitoring
* @param {boolean} enabled - Whether to enable monitoring
* @param {Object} options - Monitoring options
*/
function configurePerformanceMonitoring(enabled) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
performanceConfig = _objectSpread2(_objectSpread2({}, performanceConfig), {}, {
enabled: enabled
}, options);
}
function getPerformanceMetrics() {
var avgResponseTime = performanceMetrics.apiCalls > 0 ? Math.round(performanceMetrics.totalResponseTime / performanceMetrics.apiCalls) : 0;
var cacheHitRate = performanceMetrics.cacheHits + performanceMetrics.cacheMisses > 0 ? Math.round(performanceMetrics.cacheHits / (performanceMetrics.cacheHits + performanceMetrics.cacheMisses) * 100) : 0;
return _objectSpread2(_objectSpread2({}, performanceMetrics), {}, {
avgResponseTime: avgResponseTime,
cacheHitRate: "".concat(cacheHitRate, "%"),
summary: {
totalCalls: performanceMetrics.apiCalls,
avgResponseTime: "".concat(avgResponseTime, "ms"),
cacheEfficiency: "".concat(cacheHitRate, "%"),
slowRequestCount: performanceMetrics.slowRequests.length
}
});
}
/**
* Reset performance metrics
*/
function resetPerformanceMetrics() {
performanceMetrics.apiCalls = 0;
performanceMetrics.cacheHits = 0;
performanceMetrics.cacheMisses = 0;
performanceMetrics.totalResponseTime = 0;
performanceMetrics.slowRequests = [];
}
/**
* Generic function to load data with caching and deduplication
* @param {string} endpoint - API endpoint
* @param {Object} cache - Cache object to use
* @param {string} cacheKey - Key for caching
* @returns {Promise<Array>}
*/
function loadData(_x4, _x5, _x6) {
return _loadData.apply(this, arguments);
} // ---------------------------------------------------------------------
// API Functions
// ---------------------------------------------------------------------
/**
* Fetches region data from the API
* @async
* @returns {Promise<Array>} Array of region objects
*/
function _loadData() {
_loadData = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee4(endpoint, cache, cacheKey) {
var cacheEntry, pendingKey, requestPromise;
return _regenerator().w(function (_context4) {
while (1) switch (_context4.n) {
case 0:
cacheEntry = cache[cacheKey];
if (!(cacheEntry && Date.now() - cacheEntry.timestamp < config.cacheTTL)) {
_context4.n = 1;
break;
}
if (performanceConfig.enabled) performanceMetrics.cacheHits++;
return _context4.a(2, cacheEntry.data);
case 1:
if (performanceConfig.enabled) performanceMetrics.cacheMisses++;
// Check if there's already a pending request
pendingKey = "".concat(endpoint, "-").concat(cacheKey);
if (!pendingRequests.has(pendingKey)) {
_context4.n = 2;
break;
}
return _context4.a(2, pendingRequests.get(pendingKey));
case 2:
// Create new request
requestPromise = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee3() {
var res, data, _t3;
return _regenerator().w(function (_context3) {
while (1) switch (_context3.n) {
case 0:
_context3.p = 0;
_context3.n = 1;
return fetchWithTimeout("".concat(API).concat(endpoint));
case 1:
res = _context3.v;
if (res.ok) {
_context3.n = 2;
break;
}
throw new Error("Network error while fetching ".concat(endpoint));
case 2:
_context3.n = 3;
return res.json();
case 3:
data = _context3.v;
// Update cache
cache[cacheKey] = {
data: data,
timestamp: Date.now()
};
return _context3.a(2, data);
case 4:
_context3.p = 4;
_t3 = _context3.v;
console.error("Error loading ".concat(endpoint, ":"), _t3);
// Return cached data if available, even if expired
if (!(cacheEntry !== null && cacheEntry !== void 0 && cacheEntry.data)) {
_context3.n = 5;
break;
}
return _context3.a(2, cacheEntry.data);
case 5:
return _context3.a(2, []);
case 6:
_context3.p = 6;
// Clean up pending request
pendingRequests.delete(pendingKey);
return _context3.f(6);
case 7:
return _context3.a(2);
}
}, _callee3, null, [[0, 4, 6, 7]]);
}))(); // Store pending request
pendingRequests.set(pendingKey, requestPromise);
return _context4.a(2, requestPromise);
}
}, _callee4);
}));
return _loadData.apply(this, arguments);
}
function loadRegions() {
return _loadRegions.apply(this, arguments);
}
/**
* Fetches province data for a given region code
* @async
* @param {string} regionCode - The region code
* @returns {Promise<Array>} Array of province objects
*/
function _loadRegions() {
_loadRegions = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee6() {
var pendingKey, requestPromise;
return _regenerator().w(function (_context6) {
while (1) switch (_context6.n) {
case 0:
if (!(regionsCache.data && Date.now() - regionsCache.timestamp < config.cacheTTL)) {
_context6.n = 1;
break;
}
return _context6.a(2, regionsCache.data);
case 1:
pendingKey = 'regions';
if (!pendingRequests.has(pendingKey)) {
_context6.n = 2;
break;
}
return _context6.a(2, pendingRequests.get(pendingKey));
case 2:
requestPromise = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee5() {
var res, data, _t4;
return _regenerator().w(function (_context5) {
while (1) switch (_context5.n) {
case 0:
_context5.p = 0;
_context5.n = 1;
return fetchWithTimeout("".concat(API, "/regions"));
case 1:
res = _context5.v;
if (res.ok) {
_context5.n = 2;
break;
}
throw new Error("Network error while fetching regions");
case 2:
_context5.n = 3;
return res.json();
case 3:
data = _context5.v;
regionsCache = {
data: data,
timestamp: Date.now()
};
return _context5.a(2, data);
case 4:
_context5.p = 4;
_t4 = _context5.v;
console.error("Error in loadRegions:", _t4);
if (!regionsCache.data) {
_context5.n = 5;
break;
}
return _context5.a(2, regionsCache.data);
case 5:
return _context5.a(2, []);
case 6:
_context5.p = 6;
pendingRequests.delete(pendingKey);
return _context5.f(6);
case 7:
return _context5.a(2);
}
}, _callee5, null, [[0, 4, 6, 7]]);
}))();
pendingRequests.set(pendingKey, requestPromise);
return _context6.a(2, requestPromise);
}
}, _callee6);
}));
return _loadRegions.apply(this, arguments);
}
function loadProvinces(_x7) {
return _loadProvinces.apply(this, arguments);
}
/**
* Fetches cities data for a given province code
* @async
* @param {string} provCode - The province code
* @returns {Promise<Array>} Array of city objects
*/
function _loadProvinces() {
_loadProvinces = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee7(regionCode) {
var cacheKey;
return _regenerator().w(function (_context7) {
while (1) switch (_context7.n) {
case 0:
if (!(typeof regionCode !== 'string' || !regionCode)) {
_context7.n = 1;
break;
}
console.error("Invalid region code");
return _context7.a(2, []);
case 1:
cacheKey = "provinces-".concat(regionCode);
return _context7.a(2, loadData("/provinces/".concat(regionCode), provincesCache, cacheKey));
}
}, _callee7);
}));
return _loadProvinces.apply(this, arguments);
}
function loadCities(_x8) {
return _loadCities.apply(this, arguments);
}
/**
* Fetches barangay data for a given city code
* @async
* @param {string} cityCode - The city code
* @returns {Promise<Array>} Array of barangay objects
*/
function _loadCities() {
_loadCities = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee8(provCode) {
var cacheKey;
return _regenerator().w(function (_context8) {
while (1) switch (_context8.n) {
case 0:
if (!(typeof provCode !== 'string' || !provCode)) {
_context8.n = 1;
break;
}
console.error("Invalid province code");
return _context8.a(2, []);
case 1:
cacheKey = "cities-".concat(provCode);
return _context8.a(2, loadData("/cities/".concat(provCode), citiesCache, cacheKey));
}
}, _callee8);
}));
return _loadCities.apply(this, arguments);
}
function loadBarangays(_x9) {
return _loadBarangays.apply(this, arguments);
} // ---------------------------------------------------------------------
// Helper Functions
// ---------------------------------------------------------------------
/**
* Constructs a full address string from address parts
* @param {Object} address - Address components
* @param {string} [address.region] - Region name
* @param {string} [address.province] - Province name
* @param {string} [address.city] - City name
* @param {string} [address.barangay] - Barangay name
* @param {string} [address.street] - Street address
* @param {string} [address.zipCode] - ZIP code
* @returns {string} Full address string
*/
function _loadBarangays() {
_loadBarangays = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee9(cityCode) {
var cacheKey;
return _regenerator().w(function (_context9) {
while (1) switch (_context9.n) {
case 0:
if (!(typeof cityCode !== 'string' || !cityCode)) {
_context9.n = 1;
break;
}
console.error("Invalid city code");
return _context9.a(2, []);
case 1:
cacheKey = "barangays-".concat(cityCode);
return _context9.a(2, loadData("/barangays/".concat(cityCode), barangaysCache, cacheKey));
}
}, _callee9);
}));
return _loadBarangays.apply(this, arguments);
}
function constructAddress(address) {
var parts = [address.street, address.barangay, address.city, address.province, address.region, address.zipCode].filter(Boolean);
return parts.join(', ');
}
/**
* Searches for a location by name across all levels
* @param {string} query - Search query
* @param {Object} [options] - Search options
* @param {boolean} [options.includeRegions=true] - Include regions in search
* @param {boolean} [options.includeProvinces=true] - Include provinces in search
* @param {boolean} [options.includeCities=true] - Include cities in search
* @param {boolean} [options.includeBarangays=false] - Include barangays in search
* @param {number} [options.limit=10] - Maximum results to return
* @returns {Promise<Array>} Search results
*/
function search(_x0) {
return _search.apply(this, arguments);
}
/**
* Clears all cached data
*/
function _search() {
_search = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee0(query) {
var options,
_options$includeRegio,
includeRegions,
_options$includeProvi,
includeProvinces,
_options$includeCitie,
includeCities,
_options$limit,
limit,
normalizedQuery,
results,
regionsData,
regionMatches,
_regionsData,
_iterator,
_step,
_loop,
_args10 = arguments,
_t6,
_t7;
return _regenerator().w(function (_context10) {
while (1) switch (_context10.n) {
case 0:
options = _args10.length > 1 && _args10[1] !== undefined ? _args10[1] : {};
_options$includeRegio = options.includeRegions, includeRegions = _options$includeRegio === void 0 ? true : _options$includeRegio, _options$includeProvi = options.includeProvinces, includeProvinces = _options$includeProvi === void 0 ? true : _options$includeProvi, _options$includeCitie = options.includeCities, includeCities = _options$includeCitie === void 0 ? true : _options$includeCitie, options.includeBarangays, _options$limit = options.limit, limit = _options$limit === void 0 ? 10 : _options$limit;
if (!(!query || typeof query !== 'string')) {
_context10.n = 1;
break;
}
return _context10.a(2, []);
case 1:
normalizedQuery = query.toLowerCase().trim();
results = [];
_context10.p = 2;
if (!includeRegions) {
_context10.n = 4;
break;
}
_context10.n = 3;
return loadRegions();
case 3:
regionsData = _context10.v;
regionMatches = regionsData.filter(function (r) {
return r.name.toLowerCase().includes(normalizedQuery);
}).map(function (r) {
return _objectSpread2(_objectSpread2({}, r), {}, {
type: 'region'
});
});
results.push.apply(results, _toConsumableArray(regionMatches));
case 4:
if (!(includeProvinces || includeCities)) {
_context10.n = 13;
break;
}
_context10.n = 5;
return loadRegions();
case 5:
_regionsData = _context10.v;
_iterator = _createForOfIteratorHelper(_regionsData);
_context10.p = 6;
_loop = /*#__PURE__*/_regenerator().m(function _loop() {
var region, provincesData, provinceMatches, _provincesData, _iterator2, _step2, _loop2, _t5;
return _regenerator().w(function (_context1) {
while (1) switch (_context1.n) {
case 0:
region = _step.value;
if (!(results.length >= limit)) {
_context1.n = 1;
break;
}
return _context1.a(2, 1);
case 1:
if (!includeProvinces) {
_context1.n = 3;
break;
}
_context1.n = 2;
return loadProvinces(region.psgcCode);
case 2:
provincesData = _context1.v;
provinceMatches = provincesData.filter(function (p) {
return p.name.toLowerCase().includes(normalizedQuery);
}).map(function (p) {
return _objectSpread2(_objectSpread2({}, p), {}, {
type: 'province',
regionName: region.name
});
});
results.push.apply(results, _toConsumableArray(provinceMatches));
case 3:
if (!(includeCities && results.length < limit)) {
_context1.n = 12;
break;
}
_context1.n = 4;
return loadProvinces(region.psgcCode);
case 4:
_provincesData = _context1.v;
_iterator2 = _createForOfIteratorHelper(_provincesData);
_context1.p = 5;
_loop2 = /*#__PURE__*/_regenerator().m(function _loop2() {
var province, citiesData, cityMatches;
return _regenerator().w(function (_context0) {
while (1) switch (_context0.n) {
case 0:
province = _step2.value;
if (!(results.length >= limit)) {
_context0.n = 1;
break;
}
return _context0.a(2, 1);
case 1:
_context0.n = 2;
return loadCities(province.id);
case 2:
citiesData = _context0.v;
cityMatches = citiesData.filter(function (c) {
return c.name.toLowerCase().includes(normalizedQuery);
}).map(function (c) {
return _objectSpread2(_objectSpread2({}, c), {}, {
type: 'city',
provinceName: province.name,
regionName: region.name
});
});
results.push.apply(results, _toConsumableArray(cityMatches));
case 3:
return _context0.a(2);
}
}, _loop2);
});
_iterator2.s();
case 6:
if ((_step2 = _iterator2.n()).done) {
_context1.n = 9;
break;
}
return _context1.d(_regeneratorValues(_loop2()), 7);
case 7:
if (!_context1.v) {
_context1.n = 8;
break;
}
return _context1.a(3, 9);
case 8:
_context1.n = 6;
break;
case 9:
_context1.n = 11;
break;
case 10:
_context1.p = 10;
_t5 = _context1.v;
_iterator2.e(_t5);
case 11:
_context1.p = 11;
_iterator2.f();
return _context1.f(11);
case 12:
return _context1.a(2);
}
}, _loop, null, [[5, 10, 11, 12]]);
});
_iterator.s();
case 7:
if ((_step = _iterator.n()).done) {
_context10.n = 10;
break;
}
return _context10.d(_regeneratorValues(_loop()), 8);
case 8:
if (!_context10.v) {
_context10.n = 9;
break;
}
return _context10.a(3, 10);
case 9:
_context10.n = 7;
break;
case 10:
_context10.n = 12;
break;
case 11:
_context10.p = 11;
_t6 = _context10.v;
_iterator.e(_t6);
case 12:
_context10.p = 12;
_iterator.f();
return _context10.f(12);
case 13:
return _context10.a(2, results.slice(0, limit));
case 14:
_context10.p = 14;
_t7 = _context10.v;
console.error('Error in search:', _t7);
return _context10.a(2, []);
}
}, _callee0, null, [[6, 11, 12, 13], [2, 14]]);
}));
return _search.apply(this, arguments);
}
function clearCache() {
regionsCache = {
data: null,
timestamp: 0
};
Object.keys(provincesCache).forEach(function (key) {
return delete provincesCache[key];
});
Object.keys(citiesCache).forEach(function (key) {
return delete citiesCache[key];
});
Object.keys(barangaysCache).forEach(function (key) {
return delete barangaysCache[key];
});
pendingRequests.clear();
}
/**
* Gets cache statistics
* @returns {Object} Cache statistics
*/
function getCacheStats() {
var countCache = function countCache(cache) {
return Object.keys(cache).length;
};
return {
regions: regionsCache.data ? 1 : 0,
provinces: countCache(provincesCache),
cities: countCache(citiesCache),
barangays: countCache(barangaysCache),
pendingRequests: pendingRequests.size,
totalCached: (regionsCache.data ? 1 : 0) + countCache(provincesCache) + countCache(citiesCache) + countCache(barangaysCache)
};
}
// ---------------------------------------------------------------------
// Public API Exports
// ---------------------------------------------------------------------
/**
* Fetches all regions
* @returns {Promise<Array>} Array of regions
*/
function regions() {
return _regions.apply(this, arguments);
}
/**
* Fetches provinces for a given region
* @param {string} regionCode - Region code
* @returns {Promise<Array>} Array of provinces
*/
function _regions() {
_regions = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee1() {
return _regenerator().w(function (_context11) {
while (1) switch (_context11.n) {
case 0:
return _context11.a(2, loadRegions());
}
}, _callee1);
}));
return _regions.apply(this, arguments);
}
function provinces(_x1) {
return _provinces.apply(this, arguments);
}
/**
* Fetches cities for a given province
* @param {string} provCode - Province code
* @returns {Promise<Array>} Array of cities
*/
function _provinces() {
_provinces = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee10(regionCode) {
return _regenerator().w(function (_context12) {
while (1) switch (_context12.n) {
case 0:
return _context12.a(2, loadProvinces(regionCode));
}
}, _callee10);
}));
return _provinces.apply(this, arguments);
}
function cities(_x10) {
return _cities.apply(this, arguments);
}
/**
* Fetches barangays for a given city
* @param {string} cityCode - City code
* @returns {Promise<Array>} Array of barangays
*/
function _cities() {
_cities = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee11(provCode) {
return _regenerator().w(function (_context13) {
while (1) switch (_context13.n) {
case 0:
return _context13.a(2, loadCities(provCode));
}
}, _callee11);
}));
return _cities.apply(this, arguments);
}
function barangays(_x11) {
return _barangays.apply(this, arguments);
}
/**
* Get region by code
* @param {string} regionCode - Region code
* @returns {Promise<Object|null>} Region object or null
*/
function _barangays() {
_barangays = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee12(cityCode) {
return _regenerator().w(function (_context14) {
while (1) switch (_context14.n) {
case 0:
return _context14.a(2, loadBarangays(cityCode));
}
}, _callee12);
}));
return _barangays.apply(this, arguments);
}
function getRegionByCode(_x12) {
return _getRegionByCode.apply(this, arguments);
}
/**
* Get province by code
* @param {string} provinceCode - Province code
* @returns {Promise<Object|null>} Province object with region info or null
*/
function _getRegionByCode() {
_getRegionByCode = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee13(regionCode) {
var regionsData;
return _regenerator().w(function (_context15) {
while (1) switch (_context15.n) {
case 0:
_context15.n = 1;
return regions();
case 1:
regionsData = _context15.v;
return _context15.a(2, regionsData.find(function (r) {
return r.psgcCode === regionCode;
}) || null);
}
}, _callee13);
}));
return _getRegionByCode.apply(this, arguments);
}
function getProvinceByCode(_x13) {
return _getProvinceByCode.apply(this, arguments);
}
/**
* Get full address hierarchy by barangay code
* @param {string} barangayCode - Barangay code
* @returns {Promise<Object|null>} Complete address hierarchy
*/
function _getProvinceByCode() {
_getProvinceByCode = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee14(provinceCode) {
var regionsData, _iterator3, _step3, region, provincesData, province, _t8;
return _regenerator().w(function (_context16) {
while (1) switch (_context16.n) {
case 0:
_context16.n = 1;
return regions();
case 1:
regionsData = _context16.v;
_iterator3 = _createForOfIteratorHelper(regionsData);
_context16.p = 2;
_iterator3.s();
case 3:
if ((_step3 = _iterator3.n()).done) {
_context16.n = 6;
break;
}
region = _step3.value;
_context16.n = 4;
return provinces(region.psgcCode);
case 4:
provincesData = _context16.v;
province = provincesData.find(function (p) {
return p.psgcCode === provinceCode;
});
if (!province) {
_context16.n = 5;
break;
}
return _context16.a(2, _objectSpread2(_objectSpread2({}, province), {}, {
region: region
}));
case 5:
_context16.n = 3;
break;
case 6:
_context16.n = 8;
break;
case 7:
_context16.p = 7;
_t8 = _context16.v;
_iterator3.e(_t8);
case 8:
_context16.p = 8;
_iterator3.f();
return _context16.f(8);
case 9:
return _context16.a(2, null);
}
}, _callee14, null, [[2, 7, 8, 9]]);
}));
return _getProvinceByCode.apply(this, arguments);
}
function getAddressHierarchy(_x14) {
return _getAddressHierarchy.apply(this, arguments);
}
/**
* Validate Philippine ZIP code
* @param {string} zipCode - ZIP code to validate
* @returns {boolean} Whether the ZIP code is valid
*/
function _getAddressHierarchy() {
_getAddressHierarchy = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee15(barangayCode) {
var regionCode, provinceCode, cityCode, _yield$Promise$all, _yield$Promise$all2, regionsData, provincesData, citiesData, barangaysData, region, province, city, barangay, _t9;
return _regenerator().w(function (_context17) {
while (1) switch (_context17.n) {
case 0:
if (!(!barangayCode || barangayCode.length < 9)) {
_context17.n = 1;
break;
}
return _context17.a(2, null);
case 1:
regionCode = barangayCode.substring(0, 2);
provinceCode = barangayCode.substring(0, 4);
cityCode = barangayCode.substring(0, 6);
_context17.p = 2;
_context17.n = 3;
return Promise.all([regions(), provinces(regionCode), cities(provinceCode), barangays(cityCode)]);
case 3:
_yield$Promise$all = _context17.v;
_yield$Promise$all2 = _slicedToArray(_yield$Promise$all, 4);
regionsData = _yield$Promise$all2[0];
provincesData = _yield$Promise$all2[1];
citiesData = _yield$Promise$all2[2];
barangaysData = _yield$Promise$all2[3];
region = regionsData.find(function (r) {
return r.psgcCode === regionCode;
});
province = provincesData.find(function (p) {
return p.id === provinceCode;
});
city = citiesData.find(function (c) {
return c.id === cityCode;
});
barangay = barangaysData.find(function (b) {
return b.id === barangayCode;
});
if (!(!region || !province || !city || !barangay)) {
_context17.n = 4;
break;
}
return _context17.a(2, null);
case 4:
return _context17.a(2, {
region: region,
province: province,
city: city,
barangay: barangay,
fullAddress: constructAddress({
barangay: barangay.name,
city: city.name,
province: province.name,
region: region.name
})
});
case 5:
_context17.p = 5;
_t9 = _context17.v;
console.error('Error getting address hierarchy:', _t9);
return _context17.a(2, null);
}
}, _callee15, null, [[2, 5]]);
}));
return _getAddressHierarchy.apply(this, arguments);
}
function isValidZipCode(zipCode) {
// Philippine ZIP codes are 4 digits
return /^\d{4}$/.test(zipCode);
}
/**
* Get all provinces grouped by region
* @returns {Promise<Object>} Provinces grouped by region
*/
function getProvincesGroupedByRegion() {
return _getProvincesGroupedByRegion.apply(this, arguments);
}
/**
* Fuzzy search with scoring
* @param {string} query - Search query
* @param {Object} options - Search options
* @returns {Promise<Array>} Search results with scores
*/
function _getProvincesGroupedByRegion() {
_getProvincesGroupedByRegion = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee17() {
var regionsData, grouped;
return _regenerator().w(function (_context19) {
while (1) switch (_context19.n) {
case 0:
_context19.n = 1;
return regions();
case 1:
regionsData = _context19.v;
grouped = {};
_context19.n = 2;
return Promise.all(regionsData.map(/*#__PURE__*/function () {
var _ref3 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee16(region) {
var provincesData;
return _regenerator().w(function (_context18) {
while (1) switch (_context18.n) {
case 0:
_context18.n = 1;
return provinces(region.psgcCode);
case 1:
provincesData = _context18.v;
grouped[region.name] = {
code: region.psgcCode,
provinces: provincesData
};
case 2:
return _context18.a(2);
}
}, _callee16);
}));
return function (_x16) {
return _ref3.apply(this, arguments);
};
}()));
case 2:
return _context19.a(2, grouped);
}
}, _callee17);
}));
return _getProvincesGroupedByRegion.apply(this, arguments);
}
function fuzzySearch(_x15) {
return _fuzzySearch.apply(this, arguments);
}
/**
* Calculate string similarity (Levenshtein distance based)
* @private
*/
function _fuzzySearch() {
_fuzzySearch = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee18(query) {
var options,
results,
_args20 = arguments;
return _regenerator().w(function (_context20) {
while (1) switch (_context20.n) {
case 0:
options = _args20.length > 1 && _args20[1] !== undefined ? _args20[1] : {};
_context20.n = 1;
return search(query, options);
case 1:
results = _context20.v;
return _context20.a(2, results.map(function (result) {
var name = result.name.toLowerCase();
var searchQuery = query.toLowerCase();
var score = 0;
if (name === searchQuery) {
score = 100; // Exact match
} else if (name.startsWith(searchQuery)) {
score = 90; // Starts with query
} else if (name.includes(searchQuery)) {
score = 70; // Contains query
} else {
// Calculate similarity score
score = calculateSimilarity(name, searchQuery);
}
return _objectSpread2(_objectSpread2({}, result), {}, {
score: score
});
}).sort(function (a, b) {
return b.score - a.score;
}));
}
}, _callee18);
}));
return _fuzzySearch.apply(this, arguments);
}
function calculateSimilarity(str1, str2) {
var longer = str1.length > str2.length ? str1 : str2;
var shorter = str1.length > str2.length ? str2 : str1;
if (longer.length === 0) return 100;
var editDistance = levenshteinDistance(longer, shorter);
return Math.round((longer.length - editDistance) / longer.length * 100);
}
/**
* Levenshtein distance algorithm
* @private
*/
function levenshteinDistance(str1, str2) {
var matrix = [];
for (var i = 0; i <= str2.length; i++) {
matrix[i] = [i];
}
for (var j = 0; j <= str1.length; j++) {
matrix[0][j] = j;
}
for (var _i = 1; _i <= str2.length; _i++) {
for (var _j = 1; _j <= str1.length; _j++) {
if (str2.charAt(_i - 1) === str1.charAt(_j - 1)) {
matrix[_i][_j] = matrix[_i - 1][_j - 1];
} else {
matrix[_i][_j] = Math.min(matrix[_i - 1][_j - 1] + 1, matrix[_i][_j - 1] + 1, matrix[_i - 1][_j] + 1);
}
}
}
return matrix[str2.length][str1.length];
}
// Default export for convenience
var index = {
regions: regions,
provinces: provinces,
cities: cities,
barangays: barangays,
constructAddress: constructAddress,
search: search,
configure: configure,
clearCache: clearCache,
getCacheStats: getCacheStats,
getRegionByCode: getRegionByCode,
getProvinceByCode: getProvinceByCode,
getAddressHierarchy: getAddressHierarchy,
isValidZipCode: isValidZipCode,
getProvincesGroupedByRegion: getProvincesGroupedByRegion,
fuzzySearch: fuzzySearch,
configurePerformanceMonitoring: configurePerformanceMonitoring,
getPerformanceMetrics: getPerformanceMetrics,
resetPerformanceMetrics: resetPerformanceMetrics
};
export { barangays, cities, clearCache, configure, configurePerformanceMonitoring, constructAddress, index as default, fuzzySearch, getAddressHierarchy, getCacheStats, getPerformanceMetrics, getProvinceByCode, getProvincesGroupedByRegion, getRegionByCode, isValidZipCode, provinces, regions, resetPerformanceMetrics, search };
//# sourceMappingURL=index.esm.js.map