feat: Add tool uuid-converter

This commit is contained in:
aSeyfarth 2023-11-09 17:29:16 +01:00
parent 093ff311fd
commit 94eb67b4ab
12 changed files with 15155 additions and 17 deletions

View file

@ -286,6 +286,12 @@
"watchTriggerable": true, "watchTriggerable": true,
"watchWithFilter": true, "watchWithFilter": true,
"whenever": true, "whenever": true,
"toValue": true "toValue": true,
"ExtractDefaultPropTypes": true,
"ExtractPropTypes": true,
"ExtractPublicPropTypes": true,
"WritableComputedRef": true,
"injectLocal": true,
"provideLocal": true
} }
} }

9
auto-imports.d.ts vendored
View file

@ -1,6 +1,7 @@
/* eslint-disable */ /* eslint-disable */
/* prettier-ignore */ /* prettier-ignore */
// @ts-nocheck // @ts-nocheck
// noinspection JSUnusedGlobalSymbols
// Generated by unplugin-auto-import // Generated by unplugin-auto-import
export {} export {}
declare global { declare global {
@ -36,6 +37,7 @@ declare global {
const h: typeof import('vue')['h'] const h: typeof import('vue')['h']
const ignorableWatch: typeof import('@vueuse/core')['ignorableWatch'] const ignorableWatch: typeof import('@vueuse/core')['ignorableWatch']
const inject: typeof import('vue')['inject'] const inject: typeof import('vue')['inject']
const injectLocal: typeof import('@vueuse/core')['injectLocal']
const isDefined: typeof import('@vueuse/core')['isDefined'] const isDefined: typeof import('@vueuse/core')['isDefined']
const isProxy: typeof import('vue')['isProxy'] const isProxy: typeof import('vue')['isProxy']
const isReactive: typeof import('vue')['isReactive'] const isReactive: typeof import('vue')['isReactive']
@ -65,6 +67,7 @@ declare global {
const onUpdated: typeof import('vue')['onUpdated'] const onUpdated: typeof import('vue')['onUpdated']
const pausableWatch: typeof import('@vueuse/core')['pausableWatch'] const pausableWatch: typeof import('@vueuse/core')['pausableWatch']
const provide: typeof import('vue')['provide'] const provide: typeof import('vue')['provide']
const provideLocal: typeof import('@vueuse/core')['provideLocal']
const reactify: typeof import('@vueuse/core')['reactify'] const reactify: typeof import('@vueuse/core')['reactify']
const reactifyObject: typeof import('@vueuse/core')['reactifyObject'] const reactifyObject: typeof import('@vueuse/core')['reactifyObject']
const reactive: typeof import('vue')['reactive'] const reactive: typeof import('vue')['reactive']
@ -288,7 +291,7 @@ declare global {
// for type re-export // for type re-export
declare global { declare global {
// @ts-ignore // @ts-ignore
export type { Component, ComponentPublicInstance, ComputedRef, InjectionKey, PropType, Ref, VNode } from 'vue' export type { Component, ComponentPublicInstance, ComputedRef, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, VNode, WritableComputedRef } from 'vue'
} }
// for vue template auto import // for vue template auto import
import { UnwrapRef } from 'vue' import { UnwrapRef } from 'vue'
@ -326,6 +329,7 @@ declare module 'vue' {
readonly h: UnwrapRef<typeof import('vue')['h']> readonly h: UnwrapRef<typeof import('vue')['h']>
readonly ignorableWatch: UnwrapRef<typeof import('@vueuse/core')['ignorableWatch']> readonly ignorableWatch: UnwrapRef<typeof import('@vueuse/core')['ignorableWatch']>
readonly inject: UnwrapRef<typeof import('vue')['inject']> readonly inject: UnwrapRef<typeof import('vue')['inject']>
readonly injectLocal: UnwrapRef<typeof import('@vueuse/core')['injectLocal']>
readonly isDefined: UnwrapRef<typeof import('@vueuse/core')['isDefined']> readonly isDefined: UnwrapRef<typeof import('@vueuse/core')['isDefined']>
readonly isProxy: UnwrapRef<typeof import('vue')['isProxy']> readonly isProxy: UnwrapRef<typeof import('vue')['isProxy']>
readonly isReactive: UnwrapRef<typeof import('vue')['isReactive']> readonly isReactive: UnwrapRef<typeof import('vue')['isReactive']>
@ -355,6 +359,7 @@ declare module 'vue' {
readonly onUpdated: UnwrapRef<typeof import('vue')['onUpdated']> readonly onUpdated: UnwrapRef<typeof import('vue')['onUpdated']>
readonly pausableWatch: UnwrapRef<typeof import('@vueuse/core')['pausableWatch']> readonly pausableWatch: UnwrapRef<typeof import('@vueuse/core')['pausableWatch']>
readonly provide: UnwrapRef<typeof import('vue')['provide']> readonly provide: UnwrapRef<typeof import('vue')['provide']>
readonly provideLocal: UnwrapRef<typeof import('@vueuse/core')['provideLocal']>
readonly reactify: UnwrapRef<typeof import('@vueuse/core')['reactify']> readonly reactify: UnwrapRef<typeof import('@vueuse/core')['reactify']>
readonly reactifyObject: UnwrapRef<typeof import('@vueuse/core')['reactifyObject']> readonly reactifyObject: UnwrapRef<typeof import('@vueuse/core')['reactifyObject']>
readonly reactive: UnwrapRef<typeof import('vue')['reactive']> readonly reactive: UnwrapRef<typeof import('vue')['reactive']>
@ -610,6 +615,7 @@ declare module '@vue/runtime-core' {
readonly h: UnwrapRef<typeof import('vue')['h']> readonly h: UnwrapRef<typeof import('vue')['h']>
readonly ignorableWatch: UnwrapRef<typeof import('@vueuse/core')['ignorableWatch']> readonly ignorableWatch: UnwrapRef<typeof import('@vueuse/core')['ignorableWatch']>
readonly inject: UnwrapRef<typeof import('vue')['inject']> readonly inject: UnwrapRef<typeof import('vue')['inject']>
readonly injectLocal: UnwrapRef<typeof import('@vueuse/core')['injectLocal']>
readonly isDefined: UnwrapRef<typeof import('@vueuse/core')['isDefined']> readonly isDefined: UnwrapRef<typeof import('@vueuse/core')['isDefined']>
readonly isProxy: UnwrapRef<typeof import('vue')['isProxy']> readonly isProxy: UnwrapRef<typeof import('vue')['isProxy']>
readonly isReactive: UnwrapRef<typeof import('vue')['isReactive']> readonly isReactive: UnwrapRef<typeof import('vue')['isReactive']>
@ -639,6 +645,7 @@ declare module '@vue/runtime-core' {
readonly onUpdated: UnwrapRef<typeof import('vue')['onUpdated']> readonly onUpdated: UnwrapRef<typeof import('vue')['onUpdated']>
readonly pausableWatch: UnwrapRef<typeof import('@vueuse/core')['pausableWatch']> readonly pausableWatch: UnwrapRef<typeof import('@vueuse/core')['pausableWatch']>
readonly provide: UnwrapRef<typeof import('vue')['provide']> readonly provide: UnwrapRef<typeof import('vue')['provide']>
readonly provideLocal: UnwrapRef<typeof import('@vueuse/core')['provideLocal']>
readonly reactify: UnwrapRef<typeof import('@vueuse/core')['reactify']> readonly reactify: UnwrapRef<typeof import('@vueuse/core')['reactify']>
readonly reactifyObject: UnwrapRef<typeof import('@vueuse/core')['reactifyObject']> readonly reactifyObject: UnwrapRef<typeof import('@vueuse/core')['reactifyObject']>
readonly reactive: UnwrapRef<typeof import('vue')['reactive']> readonly reactive: UnwrapRef<typeof import('vue')['reactive']>

17
components.d.ts vendored
View file

@ -3,11 +3,9 @@
// @ts-nocheck // @ts-nocheck
// Generated by unplugin-vue-components // Generated by unplugin-vue-components
// Read more: https://github.com/vuejs/core/pull/3399 // Read more: https://github.com/vuejs/core/pull/3399
import '@vue/runtime-core'
export {} export {}
declare module '@vue/runtime-core' { declare module 'vue' {
export interface GlobalComponents { export interface GlobalComponents {
'404.page': typeof import('./src/pages/404.page.vue')['default'] '404.page': typeof import('./src/pages/404.page.vue')['default']
About: typeof import('./src/pages/About.vue')['default'] About: typeof import('./src/pages/About.vue')['default']
@ -80,27 +78,18 @@ declare module '@vue/runtime-core' {
HttpStatusCodes: typeof import('./src/tools/http-status-codes/http-status-codes.vue')['default'] HttpStatusCodes: typeof import('./src/tools/http-status-codes/http-status-codes.vue')['default']
IbanValidatorAndParser: typeof import('./src/tools/iban-validator-and-parser/iban-validator-and-parser.vue')['default'] IbanValidatorAndParser: typeof import('./src/tools/iban-validator-and-parser/iban-validator-and-parser.vue')['default']
'IconMdi:brushVariant': typeof import('~icons/mdi/brush-variant')['default'] 'IconMdi:brushVariant': typeof import('~icons/mdi/brush-variant')['default']
'IconMdi:contentCopy': typeof import('~icons/mdi/content-copy')['default']
'IconMdi:kettleSteamOutline': typeof import('~icons/mdi/kettle-steam-outline')['default'] 'IconMdi:kettleSteamOutline': typeof import('~icons/mdi/kettle-steam-outline')['default']
IconMdiArrowDown: typeof import('~icons/mdi/arrow-down')['default'] IconMdiArrowDown: typeof import('~icons/mdi/arrow-down')['default']
IconMdiArrowRightBottom: typeof import('~icons/mdi/arrow-right-bottom')['default'] IconMdiArrowRightBottom: typeof import('~icons/mdi/arrow-right-bottom')['default']
IconMdiCamera: typeof import('~icons/mdi/camera')['default']
IconMdiChevronDown: typeof import('~icons/mdi/chevron-down')['default'] IconMdiChevronDown: typeof import('~icons/mdi/chevron-down')['default']
IconMdiChevronRight: typeof import('~icons/mdi/chevron-right')['default'] IconMdiChevronRight: typeof import('~icons/mdi/chevron-right')['default']
IconMdiClose: typeof import('~icons/mdi/close')['default'] IconMdiClose: typeof import('~icons/mdi/close')['default']
IconMdiContentCopy: typeof import('~icons/mdi/content-copy')['default'] IconMdiContentCopy: typeof import('~icons/mdi/content-copy')['default']
IconMdiDeleteOutline: typeof import('~icons/mdi/delete-outline')['default']
IconMdiDownload: typeof import('~icons/mdi/download')['default']
IconMdiEye: typeof import('~icons/mdi/eye')['default'] IconMdiEye: typeof import('~icons/mdi/eye')['default']
IconMdiEyeOff: typeof import('~icons/mdi/eye-off')['default'] IconMdiEyeOff: typeof import('~icons/mdi/eye-off')['default']
IconMdiHeart: typeof import('~icons/mdi/heart')['default'] IconMdiHeart: typeof import('~icons/mdi/heart')['default']
IconMdiPause: typeof import('~icons/mdi/pause')['default']
IconMdiPlay: typeof import('~icons/mdi/play')['default']
IconMdiRecord: typeof import('~icons/mdi/record')['default']
IconMdiRefresh: typeof import('~icons/mdi/refresh')['default']
IconMdiSearch: typeof import('~icons/mdi/search')['default'] IconMdiSearch: typeof import('~icons/mdi/search')['default']
IconMdiTranslate: typeof import('~icons/mdi/translate')['default'] IconMdiTranslate: typeof import('~icons/mdi/translate')['default']
IconMdiVideo: typeof import('~icons/mdi/video')['default']
InputCopyable: typeof import('./src/components/InputCopyable.vue')['default'] InputCopyable: typeof import('./src/components/InputCopyable.vue')['default']
IntegerBaseConverter: typeof import('./src/tools/integer-base-converter/integer-base-converter.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'] Ipv4AddressConverter: typeof import('./src/tools/ipv4-address-converter/ipv4-address-converter.vue')['default']
@ -134,7 +123,6 @@ declare module '@vue/runtime-core' {
NCollapseTransition: typeof import('naive-ui')['NCollapseTransition'] NCollapseTransition: typeof import('naive-ui')['NCollapseTransition']
NColorPicker: typeof import('naive-ui')['NColorPicker'] NColorPicker: typeof import('naive-ui')['NColorPicker']
NConfigProvider: typeof import('naive-ui')['NConfigProvider'] NConfigProvider: typeof import('naive-ui')['NConfigProvider']
NDatePicker: typeof import('naive-ui')['NDatePicker']
NDivider: typeof import('naive-ui')['NDivider'] NDivider: typeof import('naive-ui')['NDivider']
NDynamicInput: typeof import('naive-ui')['NDynamicInput'] NDynamicInput: typeof import('naive-ui')['NDynamicInput']
NEllipsis: typeof import('naive-ui')['NEllipsis'] NEllipsis: typeof import('naive-ui')['NEllipsis']
@ -143,7 +131,6 @@ declare module '@vue/runtime-core' {
NGi: typeof import('naive-ui')['NGi'] NGi: typeof import('naive-ui')['NGi']
NGrid: typeof import('naive-ui')['NGrid'] NGrid: typeof import('naive-ui')['NGrid']
NH1: typeof import('naive-ui')['NH1'] NH1: typeof import('naive-ui')['NH1']
NH2: typeof import('naive-ui')['NH2']
NH3: typeof import('naive-ui')['NH3'] NH3: typeof import('naive-ui')['NH3']
NIcon: typeof import('naive-ui')['NIcon'] NIcon: typeof import('naive-ui')['NIcon']
NImage: typeof import('naive-ui')['NImage'] NImage: typeof import('naive-ui')['NImage']
@ -153,7 +140,6 @@ declare module '@vue/runtime-core' {
NLayout: typeof import('naive-ui')['NLayout'] NLayout: typeof import('naive-ui')['NLayout']
NLayoutSider: typeof import('naive-ui')['NLayoutSider'] NLayoutSider: typeof import('naive-ui')['NLayoutSider']
NMenu: typeof import('naive-ui')['NMenu'] NMenu: typeof import('naive-ui')['NMenu']
NProgress: typeof import('naive-ui')['NProgress']
NScrollbar: typeof import('naive-ui')['NScrollbar'] NScrollbar: typeof import('naive-ui')['NScrollbar']
NSlider: typeof import('naive-ui')['NSlider'] NSlider: typeof import('naive-ui')['NSlider']
NStatistic: typeof import('naive-ui')['NStatistic'] NStatistic: typeof import('naive-ui')['NStatistic']
@ -196,6 +182,7 @@ declare module '@vue/runtime-core' {
UrlParser: typeof import('./src/tools/url-parser/url-parser.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'] 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'] UserAgentResultCards: typeof import('./src/tools/user-agent-parser/user-agent-result-cards.vue')['default']
UuidConverter: typeof import('./src/tools/uuid-converter/uuid-converter.vue')['default']
UuidGenerator: typeof import('./src/tools/uuid-generator/uuid-generator.vue')['default'] UuidGenerator: typeof import('./src/tools/uuid-generator/uuid-generator.vue')['default']
WifiQrCodeGenerator: typeof import('./src/tools/wifi-qr-code-generator/wifi-qr-code-generator.vue')['default'] WifiQrCodeGenerator: typeof import('./src/tools/wifi-qr-code-generator/wifi-qr-code-generator.vue')['default']
XmlFormatter: typeof import('./src/tools/xml-formatter/xml-formatter.vue')['default'] XmlFormatter: typeof import('./src/tools/xml-formatter/xml-formatter.vue')['default']

14956
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,7 @@
import { tool as base64FileConverter } from './base64-file-converter'; import { tool as base64FileConverter } from './base64-file-converter';
import { tool as base64StringConverter } from './base64-string-converter'; import { tool as base64StringConverter } from './base64-string-converter';
import { tool as basicAuthGenerator } from './basic-auth-generator'; import { tool as basicAuthGenerator } from './basic-auth-generator';
import { tool as uuidConverter } from './uuid-converter';
import { tool as numeronymGenerator } from './numeronym-generator'; import { tool as numeronymGenerator } from './numeronym-generator';
import { tool as macAddressGenerator } from './mac-address-generator'; import { tool as macAddressGenerator } from './mac-address-generator';
import { tool as textToBinary } from './text-to-binary'; import { tool as textToBinary } from './text-to-binary';
@ -99,6 +100,7 @@ export const toolsByCategory: ToolCategory[] = [
listConverter, listConverter,
tomlToJson, tomlToJson,
tomlToYaml, tomlToYaml,
uuidConverter,
], ],
}, },
{ {

View file

@ -0,0 +1,13 @@
import { Replace } from '@vicons/tabler';
import { defineTool } from '../tool';
import { translate } from '@/plugins/i18n.plugin';
export const tool = defineTool({
name: translate('tools.uuid-converter.title'),
path: '/uuid-converter',
description: translate('tools.uuid-converter.description'),
keywords: ['uuid', 'converter', 'guid', 'sql'],
component: () => import('./uuid-converter.vue'),
icon: Replace,
createdAt: new Date('2023-11-08'),
});

View file

@ -0,0 +1,12 @@
tools:
uuid-converter:
title: UUID converter
description: Converts a UUID with and without a hyphen to other common SQL notations and back.
uuid: UUID
uuidhexupper: HEX notation (upper)
uuidhexlower: HEX notation (lower)
uuidversion: RFC Version
input:
label: Your Input
placeholder: Your UUID with/without hyphen

View file

@ -0,0 +1,12 @@
tools:
uuid-converter:
title: Convertisseur UUID
description: Convertit un UUID avec et sans trait d'union en d'autres notations SQL courantes et inversement.
uuid: UUID
uuidhexupper: Notation HEX (supérieure)
uuidhexlower: Notation HEX (inférieure)
uuidversion: Version RFC
input:
label: Votre contribution
placeholder: Votre UUID avec/sans trait d'union

View file

@ -0,0 +1,15 @@
import { test, expect } from '@playwright/test';
test.describe('Tool - Uuid converter', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/uuid-converter');
});
test('Has correct title', async ({ page }) => {
await expect(page).toHaveTitle('Uuid converter - IT Tools');
});
test('', async ({ page }) => {
});
});

View file

@ -0,0 +1,41 @@
import { describe, expect, it } from 'vitest';
import { UUID2HEX, getVersion, normalizeUUID } from './uuid-converter.service';
const validUuid = '005056a3-e753-1eee-97a1-e5eb141bb52c';
const validUuidHex = '005056A3E7531EEE97A1E5EB141BB52C';
const inValidUuid = '005056a3-e753-1eee-97a1-e5eb141bb52x';
describe('uuid-converter', () => {
describe('normalizeUUID', () => {
it('A valid UUID should be returned without changes', () => {
expect(normalizeUUID(validUuid)).toBe(validUuid);
});
it('An invalid UUID should return an empty string', () => {
expect(normalizeUUID(inValidUuid)).toBe('');
});
it('A packed UUID in hex format should return its valid UUID', () => {
expect(normalizeUUID(validUuidHex)).toBe(validUuid);
});
});
describe('UUID2HEX', () => {
it('A UUID is converted to upper case hex notation', () => {
expect(UUID2HEX(validUuid)).toBe(validUuidHex.toUpperCase());
});
it('A UUID is converted to lower case hex notation', () => {
expect(UUID2HEX(validUuid, false)).toBe(validUuidHex.toLowerCase());
});
it('An invalid UUID should return an empty string', () => {
expect(UUID2HEX(inValidUuid)).toBe('');
});
});
describe('getVersion', () => {
it('Returns the RFC version of the UUID as string', () => {
expect(getVersion(validUuid)).toBe('1');
});
});
it('An invalid UUID should return an empty string', () => {
expect(getVersion(inValidUuid)).toBe('');
});
});

View file

@ -0,0 +1,38 @@
import { parse as uuidParse, validate as uuidValidate, version as uuidVersion } from 'uuid';
export { normalizeUUID, UUID2HEX, getVersion };
function normalizeUUID(value: string) {
let uuid = ''; // Default return value
const probablyUuid = value.toLowerCase();
const uuidHexRegEx = /^([0-9a-f]{8})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{12})$/;
const isCondensedUuid = uuidHexRegEx.test(probablyUuid);
if (isCondensedUuid) {
uuid = probablyUuid.replace(uuidHexRegEx, '$1-$2-$3-$4-$5');
}
else {
uuid = value;
};
return uuidValidate(uuid) ? uuid : '';
}
function UUID2HEX(value: string, upper = true) {
let result = ''; // Default return value
const uuid = normalizeUUID(value);
if (uuid) {
const hex = value.replace(/-/g, '');
result = upper ? hex.toUpperCase() : hex.toLowerCase();
}
return result;
}
function getVersion(value: string) {
const uuid = normalizeUUID(value);
return uuid ? uuidVersion(uuid).toString() : '';
}

View file

@ -0,0 +1,49 @@
<script setup lang="ts">
import InputCopyable from '../../components/InputCopyable.vue';
import { UUID2HEX, getVersion, normalizeUUID } from './uuid-converter.service';
const { t } = useI18n();
const input = ref('');
const formats = computed(() => [
{
label: t('tools.uuid-converter.uuid'),
value: normalizeUUID(input.value),
},
{
label: t('tools.uuid-converter.uuidhexupper'),
value: UUID2HEX(input.value, true),
},
{
label: t('tools.uuid-converter.uuidhexlower'),
value: UUID2HEX(input.value, false),
},
{
label: t('tools.uuid-converter.uuidversion'),
value: getVersion(input.value).toString(),
},
]);
const inputLabelAlignmentConfig = {
labelPosition: 'left',
labelWidth: '120px',
labelAlign: 'right',
};
</script>
<template>
<c-card>
<c-input-text
v-model:value="input"
autofocus :label="t('tools.uuid-converter.input.label')" :placeholder="t('tools.uuid-converter.input.placeholder')" raw-text
v-bind="inputLabelAlignmentConfig"
/>
<div my-16px divider />
<InputCopyable
v-for="format in formats" :key="format.label" :value="format.value" :label="format.label"
:readonly="true" v-bind="inputLabelAlignmentConfig" mb-1
/>
</c-card>
</template>