From ce3150c65d14273539362f24afd43ee689cdb287 Mon Sep 17 00:00:00 2001 From: Corentin Thomasset Date: Mon, 1 May 2023 16:43:45 +0200 Subject: [PATCH] feat(new tool): phone parser and normalizer --- components.d.ts | 277 +++++++++--------- package.json | 2 + pnpm-lock.yaml | 14 + src/tools/index.ts | 5 + src/tools/phone-parser-and-formatter/index.ts | 25 ++ .../phone-parser-and-formatter.e2e.spec.ts | 11 + .../phone-parser-and-formatter.models.ts | 41 +++ .../phone-parser-and-formatter.vue | 107 +++++++ src/utils/boolean.test.ts | 9 +- src/utils/boolean.ts | 6 +- 10 files changed, 357 insertions(+), 140 deletions(-) create mode 100644 src/tools/phone-parser-and-formatter/index.ts create mode 100644 src/tools/phone-parser-and-formatter/phone-parser-and-formatter.e2e.spec.ts create mode 100644 src/tools/phone-parser-and-formatter/phone-parser-and-formatter.models.ts create mode 100644 src/tools/phone-parser-and-formatter/phone-parser-and-formatter.vue diff --git a/components.d.ts b/components.d.ts index 2750ce66..84e879c9 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 bed82dcf..6f5856b0 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 1e1b8715..e5813b71 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 73f08348..bc54b4d2 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 00000000..5b19ae61 --- /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 00000000..ddf55102 --- /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 00000000..1e2a483d --- /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, 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 00000000..d17356a9 --- /dev/null +++ b/src/tools/phone-parser-and-formatter/phone-parser-and-formatter.vue @@ -0,0 +1,107 @@ + + + + + diff --git a/src/utils/boolean.test.ts b/src/utils/boolean.test.ts index 57ca10a4..52bda9e2 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 9e842ea8..cf10b377 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'; +}