parent
							
								
									318fb6efb9
								
							
						
					
					
						commit
						8659024c9b
					
				
							
								
								
									
										7
									
								
								components.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										7
									
								
								components.d.ts
									
									
									
									
										vendored
									
									
								
							| @ -103,6 +103,7 @@ declare module '@vue/runtime-core' { | ||||
|     IconMdiTriangleDown: typeof import('~icons/mdi/triangle-down')['default'] | ||||
|     InputCopyable: typeof import('./src/components/InputCopyable.vue')['default'] | ||||
|     IntegerBaseConverter: typeof import('./src/tools/integer-base-converter/integer-base-converter.vue')['default'] | ||||
|     IntegersToIp: typeof import('./src/tools/integers-to-ip/integers-to-ip.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'] | ||||
| @ -129,11 +130,10 @@ declare module '@vue/runtime-core' { | ||||
|     MetaTagGenerator: typeof import('./src/tools/meta-tag-generator/meta-tag-generator.vue')['default'] | ||||
|     MimeTypes: typeof import('./src/tools/mime-types/mime-types.vue')['default'] | ||||
|     NavbarButtons: typeof import('./src/components/NavbarButtons.vue')['default'] | ||||
|     NCode: typeof import('naive-ui')['NCode'] | ||||
|     NCollapseTransition: typeof import('naive-ui')['NCollapseTransition'] | ||||
|     NConfigProvider: typeof import('naive-ui')['NConfigProvider'] | ||||
|     NDivider: typeof import('naive-ui')['NDivider'] | ||||
|     NEllipsis: typeof import('naive-ui')['NEllipsis'] | ||||
|     NForm: typeof import('naive-ui')['NForm'] | ||||
|     NFormItem: typeof import('naive-ui')['NFormItem'] | ||||
|     NH1: typeof import('naive-ui')['NH1'] | ||||
|     NH3: typeof import('naive-ui')['NH3'] | ||||
| @ -142,9 +142,6 @@ declare module '@vue/runtime-core' { | ||||
|     NLayout: typeof import('naive-ui')['NLayout'] | ||||
|     NLayoutSider: typeof import('naive-ui')['NLayoutSider'] | ||||
|     NMenu: typeof import('naive-ui')['NMenu'] | ||||
|     NScrollbar: typeof import('naive-ui')['NScrollbar'] | ||||
|     NSlider: typeof import('naive-ui')['NSlider'] | ||||
|     NSwitch: typeof import('naive-ui')['NSwitch'] | ||||
|     NumeronymGenerator: typeof import('./src/tools/numeronym-generator/numeronym-generator.vue')['default'] | ||||
|     OtpCodeGeneratorAndValidator: typeof import('./src/tools/otp-code-generator-and-validator/otp-code-generator-and-validator.vue')['default'] | ||||
|     PasswordStrengthAnalyser: typeof import('./src/tools/password-strength-analyser/password-strength-analyser.vue')['default'] | ||||
|  | ||||
| @ -65,6 +65,7 @@ | ||||
|     "highlight.js": "^11.7.0", | ||||
|     "iarna-toml-esm": "^3.0.5", | ||||
|     "ibantools": "^4.3.3", | ||||
|     "ip-bigint": "^8.2.0", | ||||
|     "js-base64": "^3.7.6", | ||||
|     "json5": "^2.2.3", | ||||
|     "jwt-decode": "^3.1.2", | ||||
|  | ||||
							
								
								
									
										22
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										22
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							| @ -95,6 +95,9 @@ dependencies: | ||||
|   ibantools: | ||||
|     specifier: ^4.3.3 | ||||
|     version: 4.3.3 | ||||
|   ip-bigint: | ||||
|     specifier: ^8.2.0 | ||||
|     version: 8.2.0 | ||||
|   js-base64: | ||||
|     specifier: ^3.7.6 | ||||
|     version: 3.7.7 | ||||
| @ -3360,7 +3363,7 @@ packages: | ||||
|     dependencies: | ||||
|       '@unhead/dom': 0.5.1 | ||||
|       '@unhead/schema': 0.5.1 | ||||
|       '@vueuse/shared': 10.11.1(vue@3.3.4) | ||||
|       '@vueuse/shared': 11.0.3(vue@3.3.4) | ||||
|       unhead: 0.5.1 | ||||
|       vue: 3.3.4 | ||||
|     transitivePeerDependencies: | ||||
| @ -3993,19 +3996,19 @@ packages: | ||||
|       - vue | ||||
|     dev: false | ||||
| 
 | ||||
|   /@vueuse/shared@10.11.1(vue@3.3.4): | ||||
|     resolution: {integrity: sha512-LHpC8711VFZlDaYUXEBbFBCQ7GS3dVU9mjOhhMhXP6txTV4EhYQg/KGnQuvt/sPAtoUKq7VVUnL6mVtFoL42sA==} | ||||
|   /@vueuse/shared@10.3.0(vue@3.3.4): | ||||
|     resolution: {integrity: sha512-kGqCTEuFPMK4+fNWy6dUOiYmxGcUbtznMwBZLC1PubidF4VZY05B+Oht7Jh7/6x4VOWGpvu3R37WHi81cKpiqg==} | ||||
|     dependencies: | ||||
|       vue-demi: 0.14.10(vue@3.3.4) | ||||
|       vue-demi: 0.14.5(vue@3.3.4) | ||||
|     transitivePeerDependencies: | ||||
|       - '@vue/composition-api' | ||||
|       - vue | ||||
|     dev: false | ||||
| 
 | ||||
|   /@vueuse/shared@10.3.0(vue@3.3.4): | ||||
|     resolution: {integrity: sha512-kGqCTEuFPMK4+fNWy6dUOiYmxGcUbtznMwBZLC1PubidF4VZY05B+Oht7Jh7/6x4VOWGpvu3R37WHi81cKpiqg==} | ||||
|   /@vueuse/shared@11.0.3(vue@3.3.4): | ||||
|     resolution: {integrity: sha512-0rY2m6HS5t27n/Vp5cTDsKTlNnimCqsbh/fmT2LgE+aaU42EMfXo8+bNX91W9I7DDmxfuACXMmrd7d79JxkqWA==} | ||||
|     dependencies: | ||||
|       vue-demi: 0.14.5(vue@3.3.4) | ||||
|       vue-demi: 0.14.10(vue@3.3.4) | ||||
|     transitivePeerDependencies: | ||||
|       - '@vue/composition-api' | ||||
|       - vue | ||||
| @ -6192,6 +6195,11 @@ packages: | ||||
|       sprintf-js: 1.1.2 | ||||
|     dev: false | ||||
| 
 | ||||
|   /ip-bigint@8.2.0: | ||||
|     resolution: {integrity: sha512-46EAEKzGNxojH5JaGEeCix49tL4h1W8ia5mhogZ68HroVAfyLj1E+SFFid4GuyK0mdIKjwcAITLqwg1wlkx2iQ==} | ||||
|     engines: {node: '>=18'} | ||||
|     dev: false | ||||
| 
 | ||||
|   /ip-cidr@3.1.0: | ||||
|     resolution: {integrity: sha512-HUCn4snshEX1P8cja/IyU3qk8FVDW8T5zZcegDFbu4w7NojmAhk5NcOgj3M8+0fmumo1afJTPDtJlzsxLdOjtg==} | ||||
|     engines: {node: '>=10.0.0'} | ||||
|  | ||||
| @ -2,6 +2,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 emailNormalizer } from './email-normalizer'; | ||||
| import { tool as integersToIp } from './integers-to-ip'; | ||||
| 
 | ||||
| import { tool as asciiTextDrawer } from './ascii-text-drawer'; | ||||
| 
 | ||||
| @ -158,7 +159,15 @@ export const toolsByCategory: ToolCategory[] = [ | ||||
|   }, | ||||
|   { | ||||
|     name: 'Network', | ||||
|     components: [ipv4SubnetCalculator, ipv4AddressConverter, ipv4RangeExpander, macAddressLookup, macAddressGenerator, ipv6UlaGenerator], | ||||
|     components: [ | ||||
|       ipv4SubnetCalculator, | ||||
|       ipv4AddressConverter, | ||||
|       ipv4RangeExpander, | ||||
|       macAddressLookup, | ||||
|       macAddressGenerator, | ||||
|       ipv6UlaGenerator, | ||||
|       integersToIp, | ||||
|     ], | ||||
|   }, | ||||
|   { | ||||
|     name: 'Math', | ||||
|  | ||||
| @ -11,9 +11,21 @@ describe('integer-base-converter', () => { | ||||
|         expect(convertBase({ value: '10100101', fromBase: 2, toBase: 16 })).toEqual('a5'); | ||||
|         expect(convertBase({ value: '192654', fromBase: 10, toBase: 8 })).toEqual('570216'); | ||||
|         expect(convertBase({ value: 'zz', fromBase: 64, toBase: 10 })).toEqual('2275'); | ||||
|         expect(convertBase({ value: '42540766411283223938465490632011909384', fromBase: 10, toBase: 10 })).toEqual('42540766411283223938465490632011909384'); | ||||
|         expect(convertBase({ value: '42540766411283223938465490632011909384', fromBase: 10, toBase: 16 })).toEqual('20010db8000085a300000000ac1f8908'); | ||||
|         expect(convertBase({ value: '20010db8000085a300000000ac1f8908', fromBase: 16, toBase: 10 })).toEqual('42540766411283223938465490632011909384'); | ||||
|         expect(convertBase({ value: 'AA', fromBase: 16, toBase: 10 })).toEqual('170'); | ||||
|         expect(convertBase({ value: 'aa', fromBase: 16, toBase: 10 })).toEqual('170'); | ||||
|         expect(convertBase({ value: '0xAA', fromBase: -1, toBase: 10 })).toEqual('170'); | ||||
|         expect(convertBase({ value: '&HAA', fromBase: -1, toBase: 10 })).toEqual('170'); | ||||
|         expect(convertBase({ value: '0xAAUL', fromBase: -1, toBase: 10 })).toEqual('170'); | ||||
|         expect(convertBase({ value: '0XAAUL', fromBase: -1, toBase: 10 })).toEqual('170'); | ||||
|         expect(convertBase({ value: '10UL', fromBase: 10, toBase: 10 })).toEqual('10'); | ||||
|         expect(convertBase({ value: '10n', fromBase: 10, toBase: 10 })).toEqual('10'); | ||||
|         expect(convertBase({ value: '0o252', fromBase: -1, toBase: 10 })).toEqual('170'); | ||||
|         expect(convertBase({ value: '&O252', fromBase: -1, toBase: 10 })).toEqual('170'); | ||||
|         expect(convertBase({ value: '192 654', fromBase: 10, toBase: 8 })).toEqual('570216'); | ||||
|         expect(convertBase({ value: '192.654', fromBase: 10, toBase: 8 })).toEqual('570216'); | ||||
|         expect(convertBase({ value: '0b10101010', fromBase: -1, toBase: 10 })).toEqual('170'); | ||||
|         expect(convertBase({ value: '0b_1010_1010', fromBase: -1, toBase: 10 })).toEqual('170'); | ||||
|         expect(convertBase({ value: '192,654', fromBase: 10, toBase: 8 })).toEqual('570216'); | ||||
|       }); | ||||
|     }); | ||||
|   }); | ||||
|  | ||||
| @ -1,20 +1,61 @@ | ||||
| export function convertBase({ value, fromBase, toBase }: { value: string; fromBase: number; toBase: number }) { | ||||
| export function hasNumberPrefix(value: string) { | ||||
|   return (value ?? '').trim().match(/^(0[xob].|&[hob].)/i); | ||||
| } | ||||
| 
 | ||||
| export function convertBase( | ||||
|   { | ||||
|     value, fromBase, toBase, | ||||
|     ignorePunctuationsRegexChars = ' \u00A0_\.,-', | ||||
|     handlePrefixSuffix = true, | ||||
|     ignoreCase = true, | ||||
|   }: { | ||||
|     value: string | ||||
|     fromBase: number | ||||
|     toBase: number | ||||
|     ignorePunctuationsRegexChars?: string | ||||
|     handlePrefixSuffix?: boolean | ||||
|     ignoreCase?: boolean | ||||
|   }) { | ||||
|   let cleanedValue = (value ?? '0').trim(); | ||||
|   if (ignorePunctuationsRegexChars) { | ||||
|     cleanedValue = cleanedValue.replace(new RegExp(`[${ignorePunctuationsRegexChars}]`, 'g'), ''); | ||||
|   } | ||||
|   let finalFromBase = fromBase; | ||||
|   if (handlePrefixSuffix) { | ||||
|     for (const regBase of [ | ||||
|       { base: 2, regex: /^(&b|0b)?([01]+)([IULZn]*)$/i }, | ||||
|       { base: 8, regex: /^(&o|0o)?([0-7]+)([IULZn]*)$/i }, | ||||
|       { base: 16, regex: /^(&h|0x)?([a-f0-9]+)([IULZn]*)$/i }, | ||||
|     ]) { | ||||
|       const match = cleanedValue.match(regBase.regex); | ||||
|       if (match) { | ||||
|         if (match[1]) { | ||||
|           finalFromBase = regBase.base; | ||||
|         } | ||||
|         cleanedValue = match[2]; | ||||
|         break; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   if (ignoreCase && finalFromBase <= 36) { | ||||
|     cleanedValue = cleanedValue.toLowerCase(); | ||||
|   } | ||||
|   const range = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+/'.split(''); | ||||
|   const fromRange = range.slice(0, fromBase); | ||||
|   const fromRange = range.slice(0, finalFromBase); | ||||
|   const toRange = range.slice(0, toBase); | ||||
|   let decValue = value | ||||
|   let decValue = cleanedValue | ||||
|     .split('') | ||||
|     .reverse() | ||||
|     .reduce((carry: bigint, digit: string, index: number) => { | ||||
|     .reduce((carry: number, digit: string, index: number) => { | ||||
|       if (!fromRange.includes(digit)) { | ||||
|         throw new Error(`Invalid digit "${digit}" for base ${fromBase}.`); | ||||
|         throw new Error(`Invalid digit "${digit}" for base ${finalFromBase}.`); | ||||
|       } | ||||
|       return (carry += BigInt(fromRange.indexOf(digit)) * BigInt(fromBase) ** BigInt(index)); | ||||
|     }, 0n); | ||||
|       return (carry += fromRange.indexOf(digit) * finalFromBase ** index); | ||||
|     }, 0); | ||||
|   let newValue = ''; | ||||
|   while (decValue > 0) { | ||||
|     newValue = toRange[Number(decValue % BigInt(toBase))] + newValue; | ||||
|     decValue = (decValue - (decValue % BigInt(toBase))) / BigInt(toBase); | ||||
|     newValue = toRange[decValue % toBase] + newValue; | ||||
|     decValue = (decValue - (decValue % toBase)) / toBase; | ||||
|   } | ||||
|   return newValue || '0'; | ||||
| } | ||||
|  | ||||
							
								
								
									
										12
									
								
								src/tools/integers-to-ip/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/tools/integers-to-ip/index.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | ||||
| import { Binary } from '@vicons/tabler'; | ||||
| import { defineTool } from '../tool'; | ||||
| 
 | ||||
| export const tool = defineTool({ | ||||
|   name: 'Integers to IPv4/IPv6', | ||||
|   path: '/integers-to-ip', | ||||
|   description: 'Convert integers to IP', | ||||
|   keywords: ['integers', 'ip', 'ipv4', 'ipv6'], | ||||
|   component: () => import('./integers-to-ip.vue'), | ||||
|   icon: Binary, | ||||
|   createdAt: new Date('2024-07-14'), | ||||
| }); | ||||
							
								
								
									
										65
									
								
								src/tools/integers-to-ip/integers-to-ip.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								src/tools/integers-to-ip/integers-to-ip.vue
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,65 @@ | ||||
| <script setup lang="ts"> | ||||
| import { stringifyIp } from 'ip-bigint'; | ||||
| import InputCopyable from '../../components/InputCopyable.vue'; | ||||
| import { convertBase, hasNumberPrefix } from '../integer-base-converter/integer-base-converter.model'; | ||||
| 
 | ||||
| const input = ref('3232235777'); | ||||
| const inputBase = ref(10); | ||||
| 
 | ||||
| const hasInputNumberPrefix = computed(() => hasNumberPrefix(input.value)); | ||||
| 
 | ||||
| function convertToIP({ value, fromBase, version }: { value: string; fromBase: number; version: 6 | 4 }): string { | ||||
|   try { | ||||
|     return stringifyIp({ | ||||
|       number: BigInt(convertBase({ | ||||
|         value, | ||||
|         fromBase, | ||||
|         toBase: 10, | ||||
|       })), | ||||
|       version, | ||||
|     }) ?? 'Invalid IP'; | ||||
|   } | ||||
|   catch (err) { | ||||
|     return err?.toString() ?? 'Invalid IP'; | ||||
|   } | ||||
| } | ||||
| </script> | ||||
| 
 | ||||
| <template> | ||||
|   <div> | ||||
|     <c-card> | ||||
|       <c-input-text v-model:value="input" label="Input number" placeholder="Put your number here (ex: 3232235777)" label-position="left" label-width="110px" mb-2 label-align="right" /> | ||||
| 
 | ||||
|       <n-form-item v-if="!hasInputNumberPrefix" label="Input base" label-placement="left" label-width="110" :show-feedback="false"> | ||||
|         <c-select | ||||
|           v-model:value="inputBase" | ||||
|           :options="[{ value: 2, label: 'Binary' }, { value: 8, label: 'Octal' }, { value: 10, label: 'Decimal' }, { value: 16, label: 'Hexadecimal' }]" | ||||
|           placeholder="Select a base" | ||||
|           w-100px | ||||
|         /> | ||||
|       </n-form-item> | ||||
| 
 | ||||
|       <n-divider /> | ||||
| 
 | ||||
|       <InputCopyable | ||||
|         label="Formatted IPv4" | ||||
|         label-position="left" label-width="110px" mb-2 label-align="right" | ||||
|         :value="convertToIP({ value: input, fromBase: inputBase, version: 4 })" | ||||
|         placeholder="Formatted IPv4 will be here..." | ||||
|       /> | ||||
| 
 | ||||
|       <InputCopyable | ||||
|         label="Formatted IPv6" | ||||
|         label-position="left" label-width="110px" mb-2 label-align="right" | ||||
|         :value="convertToIP({ value: input, fromBase: inputBase, version: 6 })" | ||||
|         placeholder="Formatted IPv6 will be here..." | ||||
|       /> | ||||
|     </c-card> | ||||
|   </div> | ||||
| </template> | ||||
| 
 | ||||
| <style lang="less" scoped> | ||||
| .n-input-group:not(:first-child) { | ||||
|   margin-top: 5px; | ||||
| } | ||||
| </style> | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user