├── .gitignore ├── package.json ├── index.d.ts ├── index.js ├── test └── tests.js ├── README.md └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .idea/ 3 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "city-timezones", 3 | "version": "1.3.2", 4 | "description": "A light and fast method of looking up timezones given the name of a city.", 5 | "main": "index.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "git+https://github.com/kevinroberts/city-timezones.git" 9 | }, 10 | "scripts": { 11 | "test": "mocha" 12 | }, 13 | "types": "./index.d.ts", 14 | "keywords": [ 15 | "timezone", 16 | "cities", 17 | "global", 18 | "lookups", 19 | "geo" 20 | ], 21 | "homepage": "https://github.com/kevinroberts/city-timezones#readme", 22 | "author": "Kevin Roberts", 23 | "license": "MIT", 24 | "dependencies": { 25 | "lodash": "^4.17.21" 26 | }, 27 | "devDependencies": { 28 | "mocha": "^10.7.0" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /index.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'city-timezones' { 2 | interface CityData { 3 | readonly lat: number; 4 | readonly lng: number; 5 | readonly pop: number; 6 | readonly city: string; 7 | readonly iso2: string; 8 | readonly iso3: string; 9 | readonly country: string; 10 | readonly timezone: string; 11 | readonly province: string; 12 | readonly exactCity: string; 13 | readonly city_ascii: string; 14 | readonly state_ansi: string; 15 | readonly exactProvince: string; 16 | } 17 | 18 | /** 19 | * Search for city info by searching by city name. 20 | * 21 | * @param input City name. 22 | * @returns All the matching cities from search criteria. 23 | */ 24 | export function lookupViaCity(input: string): CityData[]; 25 | 26 | /** 27 | * Search for city info by searching a state or province name I.E. Springfield MO 28 | * 29 | * @param input State or province name. 30 | * @returns All the matching cities from search criteria. 31 | */ 32 | export function findFromCityStateProvince(input: string): CityData[]; 33 | 34 | /** 35 | * Find city data via its ISO2 or ISO3 code 36 | * @param input Iso2 or iso3 code 37 | * @returns All the matching cities from search criteria. 38 | */ 39 | export function findFromIsoCode(input: string): CityData[]; 40 | 41 | /** 42 | * Array of all city objects 43 | * 44 | * @returns All the cities. 45 | */ 46 | export const cityMapping: CityData[]; 47 | } 48 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | const _ = require('lodash') 3 | const cityMapping = require('./data/cityMap.json') 4 | 5 | /** 6 | * Look up timezone data via City name 7 | * @param {string} city - The city name to find 8 | * @returns {CityData[]} - array of city data matches 9 | */ 10 | function lookupViaCity(city) { 11 | const cityLookup = _.filter(cityMapping, function (o) { return o.city.toLowerCase() === city.toLowerCase() }) 12 | if (cityLookup && cityLookup.length) { 13 | return cityLookup 14 | } else { 15 | return [] 16 | } 17 | } 18 | 19 | /** 20 | * Find a partial match on the provided String array for a given search string 21 | * @param itemsToSearch {string[]} 22 | * @param searchString {string} 23 | * @returns {boolean} match found 24 | */ 25 | function findPartialMatch(itemsToSearch, searchString) { 26 | const searchItems = searchString.split(" "); 27 | const isPartialMatch = searchItems.every(function(i) { 28 | return itemsToSearch.join().toLowerCase().indexOf(i.toLowerCase()) >= 0; 29 | }) 30 | return isPartialMatch 31 | } 32 | 33 | /** 34 | * Find city data via a city name, province, state or country combination 35 | * @param {string} searchString search containing a city / state / province 36 | * @returns {CityData[]} - array of city data matches 37 | */ 38 | function findFromCityStateProvince(searchString) { 39 | if (searchString) { 40 | const cityLookup = _.filter(cityMapping, function (o) { return findPartialMatch([o.city,o.state_ansi,o.province,o.country], searchString) }) 41 | if (cityLookup && cityLookup.length) { 42 | return cityLookup 43 | } else { 44 | return [] 45 | } 46 | } else { 47 | return [] 48 | } 49 | } 50 | 51 | /** 52 | * Find city data via its ISO2 or ISO3 code 53 | * @param {string} isoCodeValue Iso2 or iso3 code 54 | * @returns {CityData[]} - array of city data matches 55 | */ 56 | function findFromIsoCode(isoCodeValue){ 57 | if (isoCodeValue) { 58 | const cityLookup = _.filter(cityMapping, function (o) { 59 | return o.iso2.toString().toLowerCase() === isoCodeValue.toLowerCase() || o.iso3.toString().toLowerCase() === isoCodeValue.toLowerCase() }) 60 | if (cityLookup && cityLookup.length) { 61 | return cityLookup 62 | } else { 63 | return [] 64 | } 65 | } else { 66 | return [] 67 | } 68 | } 69 | 70 | module.exports = { 71 | lookupViaCity, 72 | findFromCityStateProvince, 73 | findFromIsoCode, 74 | cityMapping 75 | }; 76 | -------------------------------------------------------------------------------- /test/tests.js: -------------------------------------------------------------------------------- 1 | const assert = require('assert'); 2 | const cityTimezones = require('../index.js'); 3 | 4 | describe('City lookup tests', function() { 5 | it('finding Chicago', function() { 6 | let city = cityTimezones.lookupViaCity('Chicago') 7 | console.log('found Chicago by name: ', city) 8 | assert.equal(41.82999066, city[0].lat); 9 | }); 10 | it('finding Chicago lower cased', function() { 11 | let city = cityTimezones.lookupViaCity('chicago') 12 | console.log('found Chicago by name lower case: ', city) 13 | assert.equal(41.82999066, city[0].lat); 14 | }); 15 | it('return empty for non matching city', function() { 16 | let city = cityTimezones.lookupViaCity('Foobar') 17 | assert.deepEqual([], city); 18 | }) 19 | it('return multiple matches', function() { 20 | let city = cityTimezones.lookupViaCity('Springfield') 21 | console.log(city.length + ' matches found for Springfield') 22 | assert(city.length > 1, city); 23 | }); 24 | }); 25 | 26 | describe('Partial lookup tests', function() { 27 | it('finding Springfield MO', function() { 28 | let city = cityTimezones.findFromCityStateProvince('springfield mo') 29 | console.log('found Springfield by match: ', city) 30 | assert.equal(37.18001609, city[0].lat) 31 | }); 32 | it('finding cities matching London', function() { 33 | let city = cityTimezones.findFromCityStateProvince('London') 34 | console.log('found 6 London\'s by match: ', city) 35 | assert.equal(6, city.length); 36 | }); 37 | it('return nothing from nothing', function() { 38 | let city = cityTimezones.findFromCityStateProvince('') 39 | console.log('found no matches ', city) 40 | assert.deepEqual([], city) 41 | }); 42 | }); 43 | 44 | describe('Returns full list of cities from source JSON', function() { 45 | it('finding all cities', function() { 46 | const cityMapping = cityTimezones.cityMapping 47 | console.log('found number of cities: ', cityMapping.length) 48 | assert(cityMapping.length >= 7323, 'finding all cities'); 49 | }); 50 | }); 51 | 52 | describe('Iso code lookup tests', function() { 53 | it('finding iso2 de', function() { 54 | let iso_code_result = cityTimezones.findFromIsoCode('de') 55 | console.log('found de by iso2: ', iso_code_result) 56 | assert.equal(49.98247246, iso_code_result[0].lat); 57 | }); 58 | 59 | it('finding iso3 deu', function() { 60 | let iso_code_result = cityTimezones.findFromIsoCode('deu') 61 | console.log('found deu by iso3: ', iso_code_result) 62 | assert.equal(49.98247246, iso_code_result[0].lat); 63 | }); 64 | 65 | it('finding DE lower cased', function() { 66 | let iso_code_result = cityTimezones.findFromIsoCode('DE') 67 | console.log('found DE by iso lower case: ', iso_code_result) 68 | assert.equal(49.98247246, iso_code_result[0].lat); 69 | }); 70 | 71 | it('return empty for non matching city', function() { 72 | let iso_code_result = cityTimezones.findFromIsoCode('Foobar') 73 | assert.deepEqual([], iso_code_result); 74 | }) 75 | 76 | it('return multiple matches', function() { 77 | let iso_code_result = cityTimezones.findFromIsoCode('de') 78 | console.log(iso_code_result.length + ' matches found for de') 79 | assert(iso_code_result.length > 1, iso_code_result); 80 | }); 81 | }); 82 | 83 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # city-timezones 2 | 3 | A light and fast method of looking up timezones given the name of a city. 4 | 5 | ```bash 6 | npm install city-timezones 7 | ``` 8 | 9 | ```javascript 10 | var cityTimezones = require('city-timezones'); 11 | ``` 12 | 13 | ### cityTimezones.lookupViaCity(city: string) 14 | 15 | If a city is found, returns an **array** of possible matches with city, state, lat, lng, timezone. Returns an empty `[]` if nothing matches. Multiple cities can be found if they have the same name, i.e. Springfield. 16 | A U.S. based city will contain a `state_ansi` property which is the abbreviated form of a US State [ANSI State Table](https://www.census.gov/geo/reference/ansi_statetables.html) 17 | 18 | finding based on city name of Chicago (case insensitive): 19 | ```javascript 20 | const cityLookup = cityTimezones.lookupViaCity('Chicago') 21 | console.log(cityLookup) 22 | ``` 23 | Will return: 24 | ```javascript 25 | [ { city: 'Chicago', 26 | city_ascii: 'Chicago', 27 | lat: 41.82999066, 28 | lng: -87.75005497, 29 | pop: 5915976, 30 | country: 'United States of America', 31 | iso2: 'US', 32 | iso3: 'USA', 33 | province: 'Illinois', 34 | exactCity: 'Chicago', 35 | exactProvince: 'IL', 36 | state_ansi: 'IL', 37 | timezone: 'America/Chicago' } ] 38 | ``` 39 | 40 | ### cityTimezones.findFromCityStateProvince(searchString: string) 41 | 42 | This method will return any partial match for the search term based on city, province, or country, or a combination thereof. A U.S. based city will also return matches for the `state_ansi` property. 43 | 44 | finding based on search term of Springfield MO 45 | ```javascript 46 | const cityLookup = cityTimezones.findFromCityStateProvince('springfield mo') 47 | console.log(cityLookup) 48 | ``` 49 | Will return: 50 | ```javascript 51 | [ { city: 'Springfield', 52 | city_ascii: 'Springfield', 53 | lat: 37.18001609, 54 | lng: -93.31999923, 55 | pop: 180691, 56 | country: 'United States of America', 57 | iso2: 'US', 58 | iso3: 'USA', 59 | province: 'Missouri', 60 | state_ansi: 'MO', 61 | timezone: 'America/Chicago' } ] 62 | ``` 63 | 64 | ### cityTimezones.findFromIsoCode(iso_code: string) 65 | 66 | If a iso code is found, returns an **array** of possible matches with city, state, lat, lng, timezone. Returns an empty `[]` if nothing matches. Multiple cities are returned if there are more than one city for the given iso code. 67 | 68 | finding based on iso code of Germany (case insensitive): 69 | ```javascript 70 | const findFromIsoCode = cityTimezones.findFromIsoCode('DE') 71 | console.log(findFromIsoCode) 72 | ``` 73 | Will return: 74 | ```javascript 75 | [ 76 | { 77 | city: "Mainz", 78 | city_ascii: "Mainz", 79 | country: "Germany", 80 | iso2: "DE", 81 | iso3: "DEU", 82 | lat: 49.98247246, 83 | lng: 8.273219156, 84 | pop: 184997, 85 | province: "Rheinland-Pfalz", 86 | timezone: "Europe/Berlin" 87 | }, 88 | ... 89 | ] 90 | ``` 91 | 92 | ### cityTimezones.cityMapping 93 | 94 | This array will contain the full list of all available cities. 95 | 96 | ```javascript 97 | const cityMapping = cityTimezones.cityMapping 98 | console.log(cityMapping) 99 | ``` 100 | Will return: 101 | ```javascript 102 | [ 103 | { 104 | "city": "Qal eh-ye Now", 105 | "city_ascii": "Qal eh-ye", 106 | "lat": 34.98300013, 107 | "lng": 63.13329964, 108 | "pop": 2997, 109 | "country": "Afghanistan", 110 | "iso2": "AF", 111 | "iso3": "AFG", 112 | "province": "Badghis", 113 | "timezone": "Asia/Kabul" 114 | }, 115 | { 116 | "city": "Chaghcharan", 117 | "city_ascii": "Chaghcharan", 118 | "lat": 34.5167011, 119 | "lng": 65.25000063, 120 | "pop": 15000, 121 | "country": "Afghanistan", 122 | "iso2": "AF", 123 | "iso3": "AFG", 124 | "province": "Ghor", 125 | "timezone": "Asia/Kabul" 126 | }, 127 | ... 128 | ] 129 | ``` 130 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | ansi-colors@^4.1.3: 6 | version "4.1.3" 7 | resolved "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz" 8 | integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw== 9 | 10 | ansi-regex@^5.0.1: 11 | version "5.0.1" 12 | resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz" 13 | integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== 14 | 15 | ansi-styles@^4.0.0, ansi-styles@^4.1.0: 16 | version "4.3.0" 17 | resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" 18 | integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== 19 | dependencies: 20 | color-convert "^2.0.1" 21 | 22 | anymatch@~3.1.2: 23 | version "3.1.3" 24 | resolved "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz" 25 | integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== 26 | dependencies: 27 | normalize-path "^3.0.0" 28 | picomatch "^2.0.4" 29 | 30 | argparse@^2.0.1: 31 | version "2.0.1" 32 | resolved "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz" 33 | integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== 34 | 35 | balanced-match@^1.0.0: 36 | version "1.0.2" 37 | resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" 38 | integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== 39 | 40 | binary-extensions@^2.0.0: 41 | version "2.3.0" 42 | resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz" 43 | integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== 44 | 45 | brace-expansion@^2.0.1: 46 | version "2.0.1" 47 | resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz" 48 | integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== 49 | dependencies: 50 | balanced-match "^1.0.0" 51 | 52 | braces@~3.0.2: 53 | version "3.0.3" 54 | resolved "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz" 55 | integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== 56 | dependencies: 57 | fill-range "^7.1.1" 58 | 59 | browser-stdout@^1.3.1: 60 | version "1.3.1" 61 | resolved "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz" 62 | integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== 63 | 64 | camelcase@^6.0.0: 65 | version "6.3.0" 66 | resolved "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz" 67 | integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== 68 | 69 | chalk@^4.1.0: 70 | version "4.1.2" 71 | resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz" 72 | integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== 73 | dependencies: 74 | ansi-styles "^4.1.0" 75 | supports-color "^7.1.0" 76 | 77 | chokidar@^3.5.3: 78 | version "3.6.0" 79 | resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz" 80 | integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== 81 | dependencies: 82 | anymatch "~3.1.2" 83 | braces "~3.0.2" 84 | glob-parent "~5.1.2" 85 | is-binary-path "~2.1.0" 86 | is-glob "~4.0.1" 87 | normalize-path "~3.0.0" 88 | readdirp "~3.6.0" 89 | optionalDependencies: 90 | fsevents "~2.3.2" 91 | 92 | cliui@^7.0.2: 93 | version "7.0.4" 94 | resolved "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz" 95 | integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== 96 | dependencies: 97 | string-width "^4.2.0" 98 | strip-ansi "^6.0.0" 99 | wrap-ansi "^7.0.0" 100 | 101 | color-convert@^2.0.1: 102 | version "2.0.1" 103 | resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz" 104 | integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== 105 | dependencies: 106 | color-name "~1.1.4" 107 | 108 | color-name@~1.1.4: 109 | version "1.1.4" 110 | resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" 111 | integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== 112 | 113 | debug@^4.3.5: 114 | version "4.3.5" 115 | resolved "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz" 116 | integrity sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg== 117 | dependencies: 118 | ms "2.1.2" 119 | 120 | decamelize@^4.0.0: 121 | version "4.0.0" 122 | resolved "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz" 123 | integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== 124 | 125 | diff@^5.2.0: 126 | version "5.2.0" 127 | resolved "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz" 128 | integrity sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A== 129 | 130 | emoji-regex@^8.0.0: 131 | version "8.0.0" 132 | resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz" 133 | integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== 134 | 135 | escalade@^3.1.1: 136 | version "3.1.2" 137 | resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz" 138 | integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA== 139 | 140 | escape-string-regexp@^4.0.0: 141 | version "4.0.0" 142 | resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz" 143 | integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== 144 | 145 | fill-range@^7.1.1: 146 | version "7.1.1" 147 | resolved "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz" 148 | integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== 149 | dependencies: 150 | to-regex-range "^5.0.1" 151 | 152 | find-up@^5.0.0: 153 | version "5.0.0" 154 | resolved "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz" 155 | integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== 156 | dependencies: 157 | locate-path "^6.0.0" 158 | path-exists "^4.0.0" 159 | 160 | flat@^5.0.2: 161 | version "5.0.2" 162 | resolved "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz" 163 | integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== 164 | 165 | fs.realpath@^1.0.0: 166 | version "1.0.0" 167 | resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" 168 | integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== 169 | 170 | fsevents@~2.3.2: 171 | version "2.3.3" 172 | resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz" 173 | integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== 174 | 175 | get-caller-file@^2.0.5: 176 | version "2.0.5" 177 | resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz" 178 | integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== 179 | 180 | glob-parent@~5.1.2: 181 | version "5.1.2" 182 | resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz" 183 | integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== 184 | dependencies: 185 | is-glob "^4.0.1" 186 | 187 | glob@^8.1.0: 188 | version "8.1.0" 189 | resolved "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz" 190 | integrity sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ== 191 | dependencies: 192 | fs.realpath "^1.0.0" 193 | inflight "^1.0.4" 194 | inherits "2" 195 | minimatch "^5.0.1" 196 | once "^1.3.0" 197 | 198 | has-flag@^4.0.0: 199 | version "4.0.0" 200 | resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz" 201 | integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== 202 | 203 | he@^1.2.0: 204 | version "1.2.0" 205 | resolved "https://registry.npmjs.org/he/-/he-1.2.0.tgz" 206 | integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== 207 | 208 | inflight@^1.0.4: 209 | version "1.0.6" 210 | resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz" 211 | integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== 212 | dependencies: 213 | once "^1.3.0" 214 | wrappy "1" 215 | 216 | inherits@2: 217 | version "2.0.4" 218 | resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" 219 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== 220 | 221 | is-binary-path@~2.1.0: 222 | version "2.1.0" 223 | resolved "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz" 224 | integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== 225 | dependencies: 226 | binary-extensions "^2.0.0" 227 | 228 | is-extglob@^2.1.1: 229 | version "2.1.1" 230 | resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz" 231 | integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== 232 | 233 | is-fullwidth-code-point@^3.0.0: 234 | version "3.0.0" 235 | resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz" 236 | integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== 237 | 238 | is-glob@^4.0.1, is-glob@~4.0.1: 239 | version "4.0.3" 240 | resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz" 241 | integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== 242 | dependencies: 243 | is-extglob "^2.1.1" 244 | 245 | is-number@^7.0.0: 246 | version "7.0.0" 247 | resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz" 248 | integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== 249 | 250 | is-plain-obj@^2.1.0: 251 | version "2.1.0" 252 | resolved "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz" 253 | integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== 254 | 255 | is-unicode-supported@^0.1.0: 256 | version "0.1.0" 257 | resolved "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz" 258 | integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== 259 | 260 | js-yaml@^4.1.0: 261 | version "4.1.0" 262 | resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz" 263 | integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== 264 | dependencies: 265 | argparse "^2.0.1" 266 | 267 | locate-path@^6.0.0: 268 | version "6.0.0" 269 | resolved "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz" 270 | integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== 271 | dependencies: 272 | p-locate "^5.0.0" 273 | 274 | lodash@^4.17.21: 275 | version "4.17.21" 276 | resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" 277 | integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== 278 | 279 | log-symbols@^4.1.0: 280 | version "4.1.0" 281 | resolved "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz" 282 | integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== 283 | dependencies: 284 | chalk "^4.1.0" 285 | is-unicode-supported "^0.1.0" 286 | 287 | minimatch@^5.0.1, minimatch@^5.1.6: 288 | version "5.1.6" 289 | resolved "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz" 290 | integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== 291 | dependencies: 292 | brace-expansion "^2.0.1" 293 | 294 | mocha@^10.7.0: 295 | version "10.7.0" 296 | resolved "https://registry.npmjs.org/mocha/-/mocha-10.7.0.tgz" 297 | integrity sha512-v8/rBWr2VO5YkspYINnvu81inSz2y3ODJrhO175/Exzor1RcEZZkizgE2A+w/CAXXoESS8Kys5E62dOHGHzULA== 298 | dependencies: 299 | ansi-colors "^4.1.3" 300 | browser-stdout "^1.3.1" 301 | chokidar "^3.5.3" 302 | debug "^4.3.5" 303 | diff "^5.2.0" 304 | escape-string-regexp "^4.0.0" 305 | find-up "^5.0.0" 306 | glob "^8.1.0" 307 | he "^1.2.0" 308 | js-yaml "^4.1.0" 309 | log-symbols "^4.1.0" 310 | minimatch "^5.1.6" 311 | ms "^2.1.3" 312 | serialize-javascript "^6.0.2" 313 | strip-json-comments "^3.1.1" 314 | supports-color "^8.1.1" 315 | workerpool "^6.5.1" 316 | yargs "^16.2.0" 317 | yargs-parser "^20.2.9" 318 | yargs-unparser "^2.0.0" 319 | 320 | ms@^2.1.3: 321 | version "2.1.3" 322 | resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" 323 | integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== 324 | 325 | ms@2.1.2: 326 | version "2.1.2" 327 | resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" 328 | integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== 329 | 330 | normalize-path@^3.0.0, normalize-path@~3.0.0: 331 | version "3.0.0" 332 | resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz" 333 | integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== 334 | 335 | once@^1.3.0: 336 | version "1.4.0" 337 | resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz" 338 | integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== 339 | dependencies: 340 | wrappy "1" 341 | 342 | p-limit@^3.0.2: 343 | version "3.1.0" 344 | resolved "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz" 345 | integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== 346 | dependencies: 347 | yocto-queue "^0.1.0" 348 | 349 | p-locate@^5.0.0: 350 | version "5.0.0" 351 | resolved "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz" 352 | integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== 353 | dependencies: 354 | p-limit "^3.0.2" 355 | 356 | path-exists@^4.0.0: 357 | version "4.0.0" 358 | resolved "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz" 359 | integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== 360 | 361 | picomatch@^2.0.4, picomatch@^2.2.1: 362 | version "2.3.1" 363 | resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz" 364 | integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== 365 | 366 | randombytes@^2.1.0: 367 | version "2.1.0" 368 | resolved "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz" 369 | integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== 370 | dependencies: 371 | safe-buffer "^5.1.0" 372 | 373 | readdirp@~3.6.0: 374 | version "3.6.0" 375 | resolved "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz" 376 | integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== 377 | dependencies: 378 | picomatch "^2.2.1" 379 | 380 | require-directory@^2.1.1: 381 | version "2.1.1" 382 | resolved "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz" 383 | integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== 384 | 385 | safe-buffer@^5.1.0: 386 | version "5.2.1" 387 | resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" 388 | integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== 389 | 390 | serialize-javascript@^6.0.2: 391 | version "6.0.2" 392 | resolved "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz" 393 | integrity sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g== 394 | dependencies: 395 | randombytes "^2.1.0" 396 | 397 | string-width@^4.1.0, string-width@^4.2.0: 398 | version "4.2.3" 399 | resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" 400 | integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== 401 | dependencies: 402 | emoji-regex "^8.0.0" 403 | is-fullwidth-code-point "^3.0.0" 404 | strip-ansi "^6.0.1" 405 | 406 | strip-ansi@^6.0.0, strip-ansi@^6.0.1: 407 | version "6.0.1" 408 | resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" 409 | integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== 410 | dependencies: 411 | ansi-regex "^5.0.1" 412 | 413 | strip-json-comments@^3.1.1: 414 | version "3.1.1" 415 | resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz" 416 | integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== 417 | 418 | supports-color@^7.1.0: 419 | version "7.2.0" 420 | resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz" 421 | integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== 422 | dependencies: 423 | has-flag "^4.0.0" 424 | 425 | supports-color@^8.1.1: 426 | version "8.1.1" 427 | resolved "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz" 428 | integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== 429 | dependencies: 430 | has-flag "^4.0.0" 431 | 432 | to-regex-range@^5.0.1: 433 | version "5.0.1" 434 | resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz" 435 | integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== 436 | dependencies: 437 | is-number "^7.0.0" 438 | 439 | workerpool@^6.5.1: 440 | version "6.5.1" 441 | resolved "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz" 442 | integrity sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA== 443 | 444 | wrap-ansi@^7.0.0: 445 | version "7.0.0" 446 | resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" 447 | integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== 448 | dependencies: 449 | ansi-styles "^4.0.0" 450 | string-width "^4.1.0" 451 | strip-ansi "^6.0.0" 452 | 453 | wrappy@1: 454 | version "1.0.2" 455 | resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" 456 | integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== 457 | 458 | y18n@^5.0.5: 459 | version "5.0.8" 460 | resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz" 461 | integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== 462 | 463 | yargs-parser@^20.2.2, yargs-parser@^20.2.9: 464 | version "20.2.9" 465 | resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz" 466 | integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== 467 | 468 | yargs-unparser@^2.0.0: 469 | version "2.0.0" 470 | resolved "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz" 471 | integrity sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA== 472 | dependencies: 473 | camelcase "^6.0.0" 474 | decamelize "^4.0.0" 475 | flat "^5.0.2" 476 | is-plain-obj "^2.1.0" 477 | 478 | yargs@^16.2.0: 479 | version "16.2.0" 480 | resolved "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz" 481 | integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== 482 | dependencies: 483 | cliui "^7.0.2" 484 | escalade "^3.1.1" 485 | get-caller-file "^2.0.5" 486 | require-directory "^2.1.1" 487 | string-width "^4.2.0" 488 | y18n "^5.0.5" 489 | yargs-parser "^20.2.2" 490 | 491 | yocto-queue@^0.1.0: 492 | version "0.1.0" 493 | resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz" 494 | integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== 495 | --------------------------------------------------------------------------------