aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Corentin Thomasset <corentin.thomasset74@gmail.com> 2023-05-01 16:43:45 +0200
committerGravatar Corentin THOMASSET <corentin.thomasset74@gmail.com> 2023-05-02 13:57:39 +0200
commitce3150c65d14273539362f24afd43ee689cdb287 (patch)
treed232976b96f13cce26de3f10f47dd73ba9d3d74d
parent3f6c8f0eddc51798d62c9011e5179f6cc497e88e (diff)
downloadit-tools-ce3150c65d14273539362f24afd43ee689cdb287.tar.gz
it-tools-ce3150c65d14273539362f24afd43ee689cdb287.tar.zst
it-tools-ce3150c65d14273539362f24afd43ee689cdb287.zip
feat(new tool): phone parser and normalizer
-rw-r--r--components.d.ts277
-rw-r--r--package.json2
-rw-r--r--pnpm-lock.yaml14
-rw-r--r--src/tools/index.ts5
-rw-r--r--src/tools/phone-parser-and-formatter/index.ts25
-rw-r--r--src/tools/phone-parser-and-formatter/phone-parser-and-formatter.e2e.spec.ts11
-rw-r--r--src/tools/phone-parser-and-formatter/phone-parser-and-formatter.models.ts41
-rw-r--r--src/tools/phone-parser-and-formatter/phone-parser-and-formatter.vue107
-rw-r--r--src/utils/boolean.test.ts9
-rw-r--r--src/utils/boolean.ts6
10 files changed, 357 insertions, 140 deletions
diff --git a/components.d.ts b/components.d.ts
index 2750ce6..84e879c 100644
--- a/components.d.ts
+++ b/components.d.ts
@@ -5,146 +5,147 @@
// Read more: https://github.com/vuejs/core/pull/3399
import '@vue/runtime-core'
-export {}
+export {};
declare module '@vue/runtime-core' {
export interface GlobalComponents {
- '404.page': typeof import('./src/pages/404.page.vue')['default']
- About: typeof import('./src/pages/About.vue')['default']
- App: typeof import('./src/App.vue')['default']
- 'Base.layout': typeof import('./src/layouts/base.layout.vue')['default']
- Base64FileConverter: typeof import('./src/tools/base64-file-converter/base64-file-converter.vue')['default']
- Base64StringConverter: typeof import('./src/tools/base64-string-converter/base64-string-converter.vue')['default']
- BasicAuthGenerator: typeof import('./src/tools/basic-auth-generator/basic-auth-generator.vue')['default']
- Bcrypt: typeof import('./src/tools/bcrypt/bcrypt.vue')['default']
- BenchmarkBuilder: typeof import('./src/tools/benchmark-builder/benchmark-builder.vue')['default']
- Bip39Generator: typeof import('./src/tools/bip39-generator/bip39-generator.vue')['default']
- CaseConverter: typeof import('./src/tools/case-converter/case-converter.vue')['default']
- CButton: typeof import('./src/ui/c-button/c-button.vue')['default']
- 'CButton.demo': typeof import('./src/ui/c-button/c-button.demo.vue')['default']
- CCard: typeof import('./src/ui/c-card/c-card.vue')['default']
- 'CCard.demo': typeof import('./src/ui/c-card/c-card.demo.vue')['default']
- ChmodCalculator: typeof import('./src/tools/chmod-calculator/chmod-calculator.vue')['default']
- Chronometer: typeof import('./src/tools/chronometer/chronometer.vue')['default']
- CLink: typeof import('./src/ui/c-link/c-link.vue')['default']
- 'CLink.demo': typeof import('./src/ui/c-link/c-link.demo.vue')['default']
- CollapsibleToolMenu: typeof import('./src/components/CollapsibleToolMenu.vue')['default']
- ColorConverter: typeof import('./src/tools/color-converter/color-converter.vue')['default']
- ColoredCard: typeof import('./src/components/ColoredCard.vue')['default']
- CopyableIpLike: typeof import('./src/tools/ipv4-subnet-calculator/copyable-ip-like.vue')['default']
- CrontabGenerator: typeof import('./src/tools/crontab-generator/crontab-generator.vue')['default']
- DateTimeConverter: typeof import('./src/tools/date-time-converter/date-time-converter.vue')['default']
- 'Demo.routes': typeof import('./src/ui/demo/demo.routes.vue')['default']
- DemoWrapper: typeof import('./src/ui/demo/demo-wrapper.vue')['default']
- DeviceInformation: typeof import('./src/tools/device-information/device-information.vue')['default']
- DiffViewer: typeof import('./src/tools/json-diff/diff-viewer/diff-viewer.vue')['default']
- DockerRunToDockerComposeConverter: typeof import('./src/tools/docker-run-to-docker-compose-converter/docker-run-to-docker-compose-converter.vue')['default']
- DynamicValues: typeof import('./src/tools/benchmark-builder/dynamic-values.vue')['default']
- Editor: typeof import('./src/tools/html-wysiwyg-editor/editor/editor.vue')['default']
- Encryption: typeof import('./src/tools/encryption/encryption.vue')['default']
- EtaCalculator: typeof import('./src/tools/eta-calculator/eta-calculator.vue')['default']
- FavoriteButton: typeof import('./src/components/FavoriteButton.vue')['default']
- FormatTransformer: typeof import('./src/components/FormatTransformer.vue')['default']
- GitMemo: typeof import('./src/tools/git-memo/git-memo.md')['default']
- HashText: typeof import('./src/tools/hash-text/hash-text.vue')['default']
- HmacGenerator: typeof import('./src/tools/hmac-generator/hmac-generator.vue')['default']
- 'Home.page': typeof import('./src/pages/Home.page.vue')['default']
- HtmlEntities: typeof import('./src/tools/html-entities/html-entities.vue')['default']
- HtmlWysiwygEditor: typeof import('./src/tools/html-wysiwyg-editor/html-wysiwyg-editor.vue')['default']
- HttpStatusCodes: typeof import('./src/tools/http-status-codes/http-status-codes.vue')['default']
- InputCopyable: typeof import('./src/components/InputCopyable.vue')['default']
- IntegerBaseConverter: typeof import('./src/tools/integer-base-converter/integer-base-converter.vue')['default']
- Ipv4AddressConverter: typeof import('./src/tools/ipv4-address-converter/ipv4-address-converter.vue')['default']
- Ipv4RangeExpander: typeof import('./src/tools/ipv4-range-expander/ipv4-range-expander.vue')['default']
- Ipv4SubnetCalculator: typeof import('./src/tools/ipv4-subnet-calculator/ipv4-subnet-calculator.vue')['default']
- Ipv6UlaGenerator: typeof import('./src/tools/ipv6-ula-generator/ipv6-ula-generator.vue')['default']
- JsonDiff: typeof import('./src/tools/json-diff/json-diff.vue')['default']
- JsonMinify: typeof import('./src/tools/json-minify/json-minify.vue')['default']
- JsonToYaml: typeof import('./src/tools/json-to-yaml-converter/json-to-yaml.vue')['default']
- JsonViewer: typeof import('./src/tools/json-viewer/json-viewer.vue')['default']
- JwtParser: typeof import('./src/tools/jwt-parser/jwt-parser.vue')['default']
- KeycodeInfo: typeof import('./src/tools/keycode-info/keycode-info.vue')['default']
- LoremIpsumGenerator: typeof import('./src/tools/lorem-ipsum-generator/lorem-ipsum-generator.vue')['default']
- MacAddressLookup: typeof import('./src/tools/mac-address-lookup/mac-address-lookup.vue')['default']
- MathEvaluator: typeof import('./src/tools/math-evaluator/math-evaluator.vue')['default']
- MenuBar: typeof import('./src/tools/html-wysiwyg-editor/editor/menu-bar.vue')['default']
- MenuBarItem: typeof import('./src/tools/html-wysiwyg-editor/editor/menu-bar-item.vue')['default']
- MenuIconItem: typeof import('./src/components/MenuIconItem.vue')['default']
- MenuLayout: typeof import('./src/components/MenuLayout.vue')['default']
- MetaTagGenerator: typeof import('./src/tools/meta-tag-generator/meta-tag-generator.vue')['default']
- MimeTypes: typeof import('./src/tools/mime-types/mime-types.vue')['default']
- NAlert: typeof import('naive-ui')['NAlert']
- NAutoComplete: typeof import('naive-ui')['NAutoComplete']
- NavbarButtons: typeof import('./src/components/NavbarButtons.vue')['default']
- NButton: typeof import('naive-ui')['NButton']
- NCard: typeof import('naive-ui')['NCard']
- NCheckbox: typeof import('naive-ui')['NCheckbox']
- NCode: typeof import('naive-ui')['NCode']
- NCollapseTransition: typeof import('naive-ui')['NCollapseTransition']
- NColorPicker: typeof import('naive-ui')['NColorPicker']
- NConfigProvider: typeof import('naive-ui')['NConfigProvider']
- NDatePicker: typeof import('naive-ui')['NDatePicker']
- NDivider: typeof import('naive-ui')['NDivider']
- NDynamicInput: typeof import('naive-ui')['NDynamicInput']
- NEllipsis: typeof import('naive-ui')['NEllipsis']
- NForm: typeof import('naive-ui')['NForm']
- NFormItem: typeof import('naive-ui')['NFormItem']
- NGi: typeof import('naive-ui')['NGi']
- NGrid: typeof import('naive-ui')['NGrid']
- NH1: typeof import('naive-ui')['NH1']
- NH2: typeof import('naive-ui')['NH2']
- NH3: typeof import('naive-ui')['NH3']
- NIcon: typeof import('naive-ui')['NIcon']
- NImage: typeof import('naive-ui')['NImage']
- NInput: typeof import('naive-ui')['NInput']
- NInputGroup: typeof import('naive-ui')['NInputGroup']
- NInputGroupLabel: typeof import('naive-ui')['NInputGroupLabel']
- NInputNumber: typeof import('naive-ui')['NInputNumber']
- NLayout: typeof import('naive-ui')['NLayout']
- NLayoutSider: typeof import('naive-ui')['NLayoutSider']
- NMenu: typeof import('naive-ui')['NMenu']
- NP: typeof import('naive-ui')['NP']
- NPageHeader: typeof import('naive-ui')['NPageHeader']
- NProgress: typeof import('naive-ui')['NProgress']
- NScrollbar: typeof import('naive-ui')['NScrollbar']
- NSelect: typeof import('naive-ui')['NSelect']
- NSlider: typeof import('naive-ui')['NSlider']
- NSpace: typeof import('naive-ui')['NSpace']
- NStatistic: typeof import('naive-ui')['NStatistic']
- NSwitch: typeof import('naive-ui')['NSwitch']
- NTable: typeof import('naive-ui')['NTable']
- NTag: typeof import('naive-ui')['NTag']
- NText: typeof import('naive-ui')['NText']
- NTooltip: typeof import('naive-ui')['NTooltip']
- NUpload: typeof import('naive-ui')['NUpload']
- NUploadDragger: typeof import('naive-ui')['NUploadDragger']
- OtpCodeGeneratorAndValidator: typeof import('./src/tools/otp-code-generator-and-validator/otp-code-generator-and-validator.vue')['default']
- QrCodeGenerator: typeof import('./src/tools/qr-code-generator/qr-code-generator.vue')['default']
- RandomPortGenerator: typeof import('./src/tools/random-port-generator/random-port-generator.vue')['default']
- ResultRow: typeof import('./src/tools/ipv4-range-expander/result-row.vue')['default']
- RomanNumeralConverter: typeof import('./src/tools/roman-numeral-converter/roman-numeral-converter.vue')['default']
- RouterLink: typeof import('vue-router')['RouterLink']
- RouterView: typeof import('vue-router')['RouterView']
- RsaKeyPairGenerator: typeof import('./src/tools/rsa-key-pair-generator/rsa-key-pair-generator.vue')['default']
- SearchBar: typeof import('./src/components/SearchBar.vue')['default']
- SearchBarItem: typeof import('./src/components/SearchBarItem.vue')['default']
- SlugifyString: typeof import('./src/tools/slugify-string/slugify-string.vue')['default']
- SpanCopyable: typeof import('./src/components/SpanCopyable.vue')['default']
- SqlPrettify: typeof import('./src/tools/sql-prettify/sql-prettify.vue')['default']
- SvgPlaceholderGenerator: typeof import('./src/tools/svg-placeholder-generator/svg-placeholder-generator.vue')['default']
- TemperatureConverter: typeof import('./src/tools/temperature-converter/temperature-converter.vue')['default']
- TextareaCopyable: typeof import('./src/components/TextareaCopyable.vue')['default']
- TextStatistics: typeof import('./src/tools/text-statistics/text-statistics.vue')['default']
- TextToNatoAlphabet: typeof import('./src/tools/text-to-nato-alphabet/text-to-nato-alphabet.vue')['default']
- TokenDisplay: typeof import('./src/tools/otp-code-generator-and-validator/token-display.vue')['default']
- 'TokenGenerator.tool': typeof import('./src/tools/token-generator/token-generator.tool.vue')['default']
- 'Tool.layout': typeof import('./src/layouts/tool.layout.vue')['default']
- ToolCard: typeof import('./src/components/ToolCard.vue')['default']
- UrlEncoder: typeof import('./src/tools/url-encoder/url-encoder.vue')['default']
- UrlParser: typeof import('./src/tools/url-parser/url-parser.vue')['default']
- UserAgentParser: typeof import('./src/tools/user-agent-parser/user-agent-parser.vue')['default']
- UserAgentResultCards: typeof import('./src/tools/user-agent-parser/user-agent-result-cards.vue')['default']
- UuidGenerator: typeof import('./src/tools/uuid-generator/uuid-generator.vue')['default']
- YamlToJson: typeof import('./src/tools/yaml-to-json-converter/yaml-to-json.vue')['default']
+ '404.page': typeof import('./src/pages/404.page.vue')['default'];
+ About: typeof import('./src/pages/About.vue')['default'];
+ App: typeof import('./src/App.vue')['default'];
+ 'Base.layout': typeof import('./src/layouts/base.layout.vue')['default'];
+ Base64FileConverter: typeof import('./src/tools/base64-file-converter/base64-file-converter.vue')['default'];
+ Base64StringConverter: typeof import('./src/tools/base64-string-converter/base64-string-converter.vue')['default'];
+ BasicAuthGenerator: typeof import('./src/tools/basic-auth-generator/basic-auth-generator.vue')['default'];
+ Bcrypt: typeof import('./src/tools/bcrypt/bcrypt.vue')['default'];
+ BenchmarkBuilder: typeof import('./src/tools/benchmark-builder/benchmark-builder.vue')['default'];
+ Bip39Generator: typeof import('./src/tools/bip39-generator/bip39-generator.vue')['default'];
+ CaseConverter: typeof import('./src/tools/case-converter/case-converter.vue')['default'];
+ CButton: typeof import('./src/ui/c-button/c-button.vue')['default'];
+ 'CButton.demo': typeof import('./src/ui/c-button/c-button.demo.vue')['default'];
+ CCard: typeof import('./src/ui/c-card/c-card.vue')['default'];
+ 'CCard.demo': typeof import('./src/ui/c-card/c-card.demo.vue')['default'];
+ ChmodCalculator: typeof import('./src/tools/chmod-calculator/chmod-calculator.vue')['default'];
+ Chronometer: typeof import('./src/tools/chronometer/chronometer.vue')['default'];
+ CLink: typeof import('./src/ui/c-link/c-link.vue')['default'];
+ 'CLink.demo': typeof import('./src/ui/c-link/c-link.demo.vue')['default'];
+ CollapsibleToolMenu: typeof import('./src/components/CollapsibleToolMenu.vue')['default'];
+ ColorConverter: typeof import('./src/tools/color-converter/color-converter.vue')['default'];
+ ColoredCard: typeof import('./src/components/ColoredCard.vue')['default'];
+ CopyableIpLike: typeof import('./src/tools/ipv4-subnet-calculator/copyable-ip-like.vue')['default'];
+ CrontabGenerator: typeof import('./src/tools/crontab-generator/crontab-generator.vue')['default'];
+ DateTimeConverter: typeof import('./src/tools/date-time-converter/date-time-converter.vue')['default'];
+ 'Demo.routes': typeof import('./src/ui/demo/demo.routes.vue')['default'];
+ DemoWrapper: typeof import('./src/ui/demo/demo-wrapper.vue')['default'];
+ DeviceInformation: typeof import('./src/tools/device-information/device-information.vue')['default'];
+ DiffViewer: typeof import('./src/tools/json-diff/diff-viewer/diff-viewer.vue')['default'];
+ DockerRunToDockerComposeConverter: typeof import('./src/tools/docker-run-to-docker-compose-converter/docker-run-to-docker-compose-converter.vue')['default'];
+ DynamicValues: typeof import('./src/tools/benchmark-builder/dynamic-values.vue')['default'];
+ Editor: typeof import('./src/tools/html-wysiwyg-editor/editor/editor.vue')['default'];
+ Encryption: typeof import('./src/tools/encryption/encryption.vue')['default'];
+ EtaCalculator: typeof import('./src/tools/eta-calculator/eta-calculator.vue')['default'];
+ FavoriteButton: typeof import('./src/components/FavoriteButton.vue')['default'];
+ FormatTransformer: typeof import('./src/components/FormatTransformer.vue')['default'];
+ GitMemo: typeof import('./src/tools/git-memo/git-memo.md')['default'];
+ HashText: typeof import('./src/tools/hash-text/hash-text.vue')['default'];
+ HmacGenerator: typeof import('./src/tools/hmac-generator/hmac-generator.vue')['default'];
+ 'Home.page': typeof import('./src/pages/Home.page.vue')['default'];
+ HtmlEntities: typeof import('./src/tools/html-entities/html-entities.vue')['default'];
+ HtmlWysiwygEditor: typeof import('./src/tools/html-wysiwyg-editor/html-wysiwyg-editor.vue')['default'];
+ HttpStatusCodes: typeof import('./src/tools/http-status-codes/http-status-codes.vue')['default'];
+ InputCopyable: typeof import('./src/components/InputCopyable.vue')['default'];
+ IntegerBaseConverter: typeof import('./src/tools/integer-base-converter/integer-base-converter.vue')['default'];
+ Ipv4AddressConverter: typeof import('./src/tools/ipv4-address-converter/ipv4-address-converter.vue')['default'];
+ Ipv4RangeExpander: typeof import('./src/tools/ipv4-range-expander/ipv4-range-expander.vue')['default'];
+ Ipv4SubnetCalculator: typeof import('./src/tools/ipv4-subnet-calculator/ipv4-subnet-calculator.vue')['default'];
+ Ipv6UlaGenerator: typeof import('./src/tools/ipv6-ula-generator/ipv6-ula-generator.vue')['default'];
+ JsonDiff: typeof import('./src/tools/json-diff/json-diff.vue')['default'];
+ JsonMinify: typeof import('./src/tools/json-minify/json-minify.vue')['default'];
+ JsonToYaml: typeof import('./src/tools/json-to-yaml-converter/json-to-yaml.vue')['default'];
+ JsonViewer: typeof import('./src/tools/json-viewer/json-viewer.vue')['default'];
+ JwtParser: typeof import('./src/tools/jwt-parser/jwt-parser.vue')['default'];
+ KeycodeInfo: typeof import('./src/tools/keycode-info/keycode-info.vue')['default'];
+ LoremIpsumGenerator: typeof import('./src/tools/lorem-ipsum-generator/lorem-ipsum-generator.vue')['default'];
+ MacAddressLookup: typeof import('./src/tools/mac-address-lookup/mac-address-lookup.vue')['default'];
+ MathEvaluator: typeof import('./src/tools/math-evaluator/math-evaluator.vue')['default'];
+ MenuBar: typeof import('./src/tools/html-wysiwyg-editor/editor/menu-bar.vue')['default'];
+ MenuBarItem: typeof import('./src/tools/html-wysiwyg-editor/editor/menu-bar-item.vue')['default'];
+ MenuIconItem: typeof import('./src/components/MenuIconItem.vue')['default'];
+ MenuLayout: typeof import('./src/components/MenuLayout.vue')['default'];
+ MetaTagGenerator: typeof import('./src/tools/meta-tag-generator/meta-tag-generator.vue')['default'];
+ MimeTypes: typeof import('./src/tools/mime-types/mime-types.vue')['default'];
+ NAlert: typeof import('naive-ui')['NAlert'];
+ NAutoComplete: typeof import('naive-ui')['NAutoComplete'];
+ NavbarButtons: typeof import('./src/components/NavbarButtons.vue')['default'];
+ NButton: typeof import('naive-ui')['NButton'];
+ NCard: typeof import('naive-ui')['NCard'];
+ NCheckbox: typeof import('naive-ui')['NCheckbox'];
+ NCode: typeof import('naive-ui')['NCode'];
+ NCollapseTransition: typeof import('naive-ui')['NCollapseTransition'];
+ NColorPicker: typeof import('naive-ui')['NColorPicker'];
+ NConfigProvider: typeof import('naive-ui')['NConfigProvider'];
+ NDatePicker: typeof import('naive-ui')['NDatePicker'];
+ NDivider: typeof import('naive-ui')['NDivider'];
+ NDynamicInput: typeof import('naive-ui')['NDynamicInput'];
+ NEllipsis: typeof import('naive-ui')['NEllipsis'];
+ NForm: typeof import('naive-ui')['NForm'];
+ NFormItem: typeof import('naive-ui')['NFormItem'];
+ NGi: typeof import('naive-ui')['NGi'];
+ NGrid: typeof import('naive-ui')['NGrid'];
+ NH1: typeof import('naive-ui')['NH1'];
+ NH2: typeof import('naive-ui')['NH2'];
+ NH3: typeof import('naive-ui')['NH3'];
+ NIcon: typeof import('naive-ui')['NIcon'];
+ NImage: typeof import('naive-ui')['NImage'];
+ NInput: typeof import('naive-ui')['NInput'];
+ NInputGroup: typeof import('naive-ui')['NInputGroup'];
+ NInputGroupLabel: typeof import('naive-ui')['NInputGroupLabel'];
+ NInputNumber: typeof import('naive-ui')['NInputNumber'];
+ NLayout: typeof import('naive-ui')['NLayout'];
+ NLayoutSider: typeof import('naive-ui')['NLayoutSider'];
+ NMenu: typeof import('naive-ui')['NMenu'];
+ NP: typeof import('naive-ui')['NP'];
+ NPageHeader: typeof import('naive-ui')['NPageHeader'];
+ NProgress: typeof import('naive-ui')['NProgress'];
+ NScrollbar: typeof import('naive-ui')['NScrollbar'];
+ NSelect: typeof import('naive-ui')['NSelect'];
+ NSlider: typeof import('naive-ui')['NSlider'];
+ NSpace: typeof import('naive-ui')['NSpace'];
+ NStatistic: typeof import('naive-ui')['NStatistic'];
+ NSwitch: typeof import('naive-ui')['NSwitch'];
+ NTable: typeof import('naive-ui')['NTable'];
+ NTag: typeof import('naive-ui')['NTag'];
+ NText: typeof import('naive-ui')['NText'];
+ NTooltip: typeof import('naive-ui')['NTooltip'];
+ NUpload: typeof import('naive-ui')['NUpload'];
+ NUploadDragger: typeof import('naive-ui')['NUploadDragger'];
+ OtpCodeGeneratorAndValidator: typeof import('./src/tools/otp-code-generator-and-validator/otp-code-generator-and-validator.vue')['default'];
+ PhoneParserAndFormatter: typeof import('./src/tools/phone-parser-and-formatter/phone-parser-and-formatter.vue')['default'];
+ QrCodeGenerator: typeof import('./src/tools/qr-code-generator/qr-code-generator.vue')['default'];
+ RandomPortGenerator: typeof import('./src/tools/random-port-generator/random-port-generator.vue')['default'];
+ ResultRow: typeof import('./src/tools/ipv4-range-expander/result-row.vue')['default'];
+ RomanNumeralConverter: typeof import('./src/tools/roman-numeral-converter/roman-numeral-converter.vue')['default'];
+ RouterLink: typeof import('vue-router')['RouterLink'];
+ RouterView: typeof import('vue-router')['RouterView'];
+ RsaKeyPairGenerator: typeof import('./src/tools/rsa-key-pair-generator/rsa-key-pair-generator.vue')['default'];
+ SearchBar: typeof import('./src/components/SearchBar.vue')['default'];
+ SearchBarItem: typeof import('./src/components/SearchBarItem.vue')['default'];
+ SlugifyString: typeof import('./src/tools/slugify-string/slugify-string.vue')['default'];
+ SpanCopyable: typeof import('./src/components/SpanCopyable.vue')['default'];
+ SqlPrettify: typeof import('./src/tools/sql-prettify/sql-prettify.vue')['default'];
+ SvgPlaceholderGenerator: typeof import('./src/tools/svg-placeholder-generator/svg-placeholder-generator.vue')['default'];
+ TemperatureConverter: typeof import('./src/tools/temperature-converter/temperature-converter.vue')['default'];
+ TextareaCopyable: typeof import('./src/components/TextareaCopyable.vue')['default'];
+ TextStatistics: typeof import('./src/tools/text-statistics/text-statistics.vue')['default'];
+ TextToNatoAlphabet: typeof import('./src/tools/text-to-nato-alphabet/text-to-nato-alphabet.vue')['default'];
+ TokenDisplay: typeof import('./src/tools/otp-code-generator-and-validator/token-display.vue')['default'];
+ 'TokenGenerator.tool': typeof import('./src/tools/token-generator/token-generator.tool.vue')['default'];
+ 'Tool.layout': typeof import('./src/layouts/tool.layout.vue')['default'];
+ ToolCard: typeof import('./src/components/ToolCard.vue')['default'];
+ UrlEncoder: typeof import('./src/tools/url-encoder/url-encoder.vue')['default'];
+ UrlParser: typeof import('./src/tools/url-parser/url-parser.vue')['default'];
+ UserAgentParser: typeof import('./src/tools/user-agent-parser/user-agent-parser.vue')['default'];
+ UserAgentResultCards: typeof import('./src/tools/user-agent-parser/user-agent-result-cards.vue')['default'];
+ UuidGenerator: typeof import('./src/tools/uuid-generator/uuid-generator.vue')['default'];
+ YamlToJson: typeof import('./src/tools/yaml-to-json-converter/yaml-to-json.vue')['default'];
}
}
diff --git a/package.json b/package.json
index bed82dc..6f5856b 100644
--- a/package.json
+++ b/package.json
@@ -48,6 +48,7 @@
"change-case": "^4.1.2",
"colord": "^2.9.3",
"composerize-ts": "^0.6.2",
+ "country-code-lookup": "^0.0.23",
"cron-validator": "^1.3.1",
"cronstrue": "^2.26.0",
"crypto-js": "^4.1.1",
@@ -57,6 +58,7 @@
"highlight.js": "^11.7.0",
"json5": "^2.2.3",
"jwt-decode": "^3.1.2",
+ "libphonenumber-js": "^1.10.28",
"lodash": "^4.17.21",
"mathjs": "^10.6.4",
"mime-types": "^2.1.35",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 1e1b871..e5813b7 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -46,6 +46,9 @@ dependencies:
composerize-ts:
specifier: ^0.6.2
version: 0.6.2
+ country-code-lookup:
+ specifier: ^0.0.23
+ version: 0.0.23
cron-validator:
specifier: ^1.3.1
version: 1.3.1
@@ -73,6 +76,9 @@ dependencies:
jwt-decode:
specifier: ^3.1.2
version: 3.1.2
+ libphonenumber-js:
+ specifier: ^1.10.28
+ version: 1.10.28
lodash:
specifier: ^4.17.21
version: 4.17.21
@@ -3604,6 +3610,10 @@ packages:
browserslist: 4.21.5
dev: true
+ /country-code-lookup@0.0.23:
+ resolution: {integrity: sha512-kxhIGcau9/X+tgPg9yO2q1OLu8jiYYsdwXuiXzHdsgNChd36xrJMlOba7ka9O1xShCVTiVQPQpq/tcuy4WiW+Q==}
+ dev: false
+
/country-data@0.0.31:
resolution: {integrity: sha512-YqlY/i6ikZwoBFfdjK+hJTGaBdTgDpXLI15MCj2UsXZ2cPBb+Kx86AXmDH7PRGt0LUleck0cCgNdWeIhfbcxkQ==}
dependencies:
@@ -5665,6 +5675,10 @@ packages:
type-check: 0.4.0
dev: true
+ /libphonenumber-js@1.10.28:
+ resolution: {integrity: sha512-1eAgjLrZA0+2Wgw4hs+4Q/kEBycxQo8ZLYnmOvZ3AlM8ImAVAJgDPlZtISLEzD1vunc2q8s2Pn7XwB7I8U3Kzw==}
+ dev: false
+
/linkify-it@3.0.3:
resolution: {integrity: sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==}
dependencies:
diff --git a/src/tools/index.ts b/src/tools/index.ts
index 73f0834..bc54b4d 100644
--- a/src/tools/index.ts
+++ b/src/tools/index.ts
@@ -1,6 +1,7 @@
import { tool as base64FileConverter } from './base64-file-converter';
import { tool as base64StringConverter } from './base64-string-converter';
import { tool as basicAuthGenerator } from './basic-auth-generator';
+import { tool as phoneParserAndFormatter } from './phone-parser-and-formatter';
import { tool as jsonDiff } from './json-diff';
import { tool as ipv4RangeExpander } from './ipv4-range-expander';
import { tool as httpStatusCodes } from './http-status-codes';
@@ -128,6 +129,10 @@ export const toolsByCategory: ToolCategory[] = [
name: 'Text',
components: [loremIpsumGenerator, textStatistics],
},
+ {
+ name: 'Data',
+ components: [phoneParserAndFormatter],
+ },
];
export const tools = toolsByCategory.flatMap(({ components }) => components);
diff --git a/src/tools/phone-parser-and-formatter/index.ts b/src/tools/phone-parser-and-formatter/index.ts
new file mode 100644
index 0000000..5b19ae6
--- /dev/null
+++ b/src/tools/phone-parser-and-formatter/index.ts
@@ -0,0 +1,25 @@
+import { Phone } from '@vicons/tabler';
+import { defineTool } from '../tool';
+
+export const tool = defineTool({
+ name: 'Phone parser and formatter',
+ path: '/phone-parser-and-formatter',
+ description:
+ 'Parse, validate and format phone numbers. Get information about the phone number, like the country code, type, etc.',
+ keywords: [
+ 'phone',
+ 'parser',
+ 'formatter',
+ 'validate',
+ 'format',
+ 'number',
+ 'telephone',
+ 'mobile',
+ 'cell',
+ 'international',
+ 'national',
+ ],
+ component: () => import('./phone-parser-and-formatter.vue'),
+ icon: Phone,
+ createdAt: new Date('2023-05-01'),
+});
diff --git a/src/tools/phone-parser-and-formatter/phone-parser-and-formatter.e2e.spec.ts b/src/tools/phone-parser-and-formatter/phone-parser-and-formatter.e2e.spec.ts
new file mode 100644
index 0000000..ddf5510
--- /dev/null
+++ b/src/tools/phone-parser-and-formatter/phone-parser-and-formatter.e2e.spec.ts
@@ -0,0 +1,11 @@
+import { test, expect } from '@playwright/test';
+
+test.describe('Tool - Phone parser and formatter', () => {
+ test.beforeEach(async ({ page }) => {
+ await page.goto('/phone-parser-and-formatter');
+ });
+
+ test('Has correct title', async ({ page }) => {
+ await expect(page).toHaveTitle('Phone parser and formatter - IT Tools');
+ });
+});
diff --git a/src/tools/phone-parser-and-formatter/phone-parser-and-formatter.models.ts b/src/tools/phone-parser-and-formatter/phone-parser-and-formatter.models.ts
new file mode 100644
index 0000000..1e2a483
--- /dev/null
+++ b/src/tools/phone-parser-and-formatter/phone-parser-and-formatter.models.ts
@@ -0,0 +1,41 @@
+import type { NumberType } from 'libphonenumber-js/types';
+import lookup from 'country-code-lookup';
+
+export { formatTypeToHumanReadable, getFullCountryName, getDefaultCountryCode };
+
+const typeToLabel: Record<NonNullable<NumberType>, string> = {
+ MOBILE: 'Mobile',
+ FIXED_LINE: 'Fixed line',
+ FIXED_LINE_OR_MOBILE: 'Fixed line or mobile',
+ PERSONAL_NUMBER: 'Personal number',
+ PREMIUM_RATE: 'Premium rate',
+ SHARED_COST: 'Shared cost',
+ TOLL_FREE: 'Toll free',
+ UAN: 'Universal access number',
+ VOICEMAIL: 'Voicemail',
+ VOIP: 'VoIP',
+ PAGER: 'Pager',
+};
+
+function formatTypeToHumanReadable(type: NumberType): string | undefined {
+ if (!type) return undefined;
+
+ return typeToLabel[type];
+}
+
+function getFullCountryName(countryCode: string | undefined) {
+ if (!countryCode) return undefined;
+
+ return lookup.byIso(countryCode)?.country;
+}
+
+function getDefaultCountryCode({
+ locale = window.navigator.language,
+ defaultCode = 'FR',
+}: { locale?: string; defaultCode?: string } = {}): string {
+ const countryCode = locale.split('-')[1]?.toUpperCase();
+
+ if (!countryCode) return defaultCode;
+
+ return lookup.byIso(countryCode)?.iso2 ?? defaultCode;
+}
diff --git a/src/tools/phone-parser-and-formatter/phone-parser-and-formatter.vue b/src/tools/phone-parser-and-formatter/phone-parser-and-formatter.vue
new file mode 100644
index 0000000..d17356a
--- /dev/null
+++ b/src/tools/phone-parser-and-formatter/phone-parser-and-formatter.vue
@@ -0,0 +1,107 @@
+<template>
+ <div>
+ <n-form-item label="Default country code:">
+ <n-select v-model:value="defaultCountryCode" :options="countriesOptions" />
+ </n-form-item>
+ <n-form-item label="Phone number:" v-bind="validation.attrs">
+ <n-input v-model:value="rawPhone" placeholder="Enter a phone number" />
+ </n-form-item>
+
+ <n-table v-if="parsedDetails">
+ <tbody>
+ <tr v-for="{ label, value } in parsedDetails" :key="label">
+ <td>
+ <n-text strong>{{ label }}</n-text>
+ </td>
+ <td>
+ <span-copyable v-if="value" :value="value"></span-copyable>
+ <n-text v-else depth="3" italic>Unknown</n-text>
+ </td>
+ </tr>
+ </tbody>
+ </n-table>
+ </div>
+</template>
+
+<script setup lang="ts">
+import { withDefaultOnError } from '@/utils/defaults';
+import { parsePhoneNumber, getCountries, getCountryCallingCode } from 'libphonenumber-js/max';
+import { booleanToHumanReadable } from '@/utils/boolean';
+import { useValidation } from '@/composable/validation';
+import lookup from 'country-code-lookup';
+import {
+ formatTypeToHumanReadable,
+ getFullCountryName,
+ getDefaultCountryCode,
+} from './phone-parser-and-formatter.models';
+
+const rawPhone = ref('');
+const defaultCountryCode = ref(getDefaultCountryCode());
+const validation = useValidation({
+ source: rawPhone,
+ rules: [
+ {
+ validator: (value) => value === '' || /^[0-9 +\-()]+$/.test(value),
+ message: 'Invalid phone number',
+ },
+ ],
+});
+
+const parsedDetails = computed(() => {
+ if (!validation.isValid) return undefined;
+
+ const parsed = withDefaultOnError(() => parsePhoneNumber(rawPhone.value, 'FR'), undefined);
+
+ if (!parsed) return undefined;
+
+ return [
+ {
+ label: 'Country',
+ value: parsed.country,
+ },
+ {
+ label: 'Country',
+ value: getFullCountryName(parsed.country),
+ },
+ {
+ label: 'Country calling code',
+ value: parsed.countryCallingCode,
+ },
+ {
+ label: 'Is valid?',
+ value: booleanToHumanReadable(parsed.isValid()),
+ },
+ {
+ label: 'Is possible?',
+ value: booleanToHumanReadable(parsed.isPossible()),
+ },
+ {
+ label: 'Type',
+ value: formatTypeToHumanReadable(parsed.getType()),
+ },
+ {
+ label: 'International format',
+ value: parsed.formatInternational(),
+ },
+ {
+ label: 'National format',
+ value: parsed.formatNational(),
+ },
+ {
+ label: 'E.164 format',
+ value: parsed.format('E.164'),
+ },
+ {
+ label: 'RFC3966 format',
+ value: parsed.format('RFC3966'),
+ },
+ ];
+});
+
+const countriesOptions = getCountries().map((code) => ({
+ label: `${lookup.byIso(code)?.country || code} (+${getCountryCallingCode(code)})`,
+ value: code,
+}));
+</script>
+
+<style lang="less" scoped></style>
diff --git a/src/utils/boolean.test.ts b/src/utils/boolean.test.ts
index 57ca10a..52bda9e 100644
--- a/src/utils/boolean.test.ts
+++ b/src/utils/boolean.test.ts
@@ -1,6 +1,6 @@
import _ from 'lodash';
import { describe, expect, it } from 'vitest';
-import { isNotThrowing } from './boolean';
+import { booleanToHumanReadable, isNotThrowing } from './boolean';
describe('boolean utils', () => {
describe('isNotThrowing', () => {
@@ -13,4 +13,11 @@ describe('boolean utils', () => {
).to.eql(false);
});
});
+
+ describe('booleanToHumanReadable', () => {
+ it('should return "Yes" if the value is true and "No" otherwise', () => {
+ expect(booleanToHumanReadable(true)).to.eql('Yes');
+ expect(booleanToHumanReadable(false)).to.eql('No');
+ });
+ });
});
diff --git a/src/utils/boolean.ts b/src/utils/boolean.ts
index 9e842ea..cf10b37 100644
--- a/src/utils/boolean.ts
+++ b/src/utils/boolean.ts
@@ -1,4 +1,4 @@
-export { isNotThrowing };
+export { isNotThrowing, booleanToHumanReadable };
function isNotThrowing(cb: () => unknown): boolean {
try {
@@ -8,3 +8,7 @@ function isNotThrowing(cb: () => unknown): boolean {
return false;
}
}
+
+function booleanToHumanReadable(value: boolean): string {
+ return value ? 'Yes' : 'No';
+}