mirror of
https://github.com/CorentinTh/it-tools.git
synced 2025-08-07 06:25:18 +02:00
Merge e66702ec9f
into 07eea0f484
This commit is contained in:
commit
0cd29f0d54
16 changed files with 372 additions and 0 deletions
1
components.d.ts
vendored
1
components.d.ts
vendored
|
@ -42,6 +42,7 @@ declare module '@vue/runtime-core' {
|
||||||
CKeyValueList: typeof import('./src/ui/c-key-value-list/c-key-value-list.vue')['default']
|
CKeyValueList: typeof import('./src/ui/c-key-value-list/c-key-value-list.vue')['default']
|
||||||
CKeyValueListItem: typeof import('./src/ui/c-key-value-list/c-key-value-list-item.vue')['default']
|
CKeyValueListItem: typeof import('./src/ui/c-key-value-list/c-key-value-list-item.vue')['default']
|
||||||
CLabel: typeof import('./src/ui/c-label/c-label.vue')['default']
|
CLabel: typeof import('./src/ui/c-label/c-label.vue')['default']
|
||||||
|
CliCommandEditor: typeof import('./src/tools/cli-command-editor/cli-command-editor.vue')['default']
|
||||||
CLink: typeof import('./src/ui/c-link/c-link.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']
|
'CLink.demo': typeof import('./src/ui/c-link/c-link.demo.vue')['default']
|
||||||
CMarkdown: typeof import('./src/ui/c-markdown/c-markdown.vue')['default']
|
CMarkdown: typeof import('./src/ui/c-markdown/c-markdown.vue')['default']
|
||||||
|
|
|
@ -454,3 +454,10 @@ tools:
|
||||||
text-to-binary:
|
text-to-binary:
|
||||||
title: Text zu ASCII-Binär
|
title: Text zu ASCII-Binär
|
||||||
description: Konvertiere Text in seine ASCII-Binärrepräsentation und umgekehrt.
|
description: Konvertiere Text in seine ASCII-Binärrepräsentation und umgekehrt.
|
||||||
|
|
||||||
|
cli-command-editor:
|
||||||
|
title: CLI-Befehlseditor
|
||||||
|
description: Wandeln Sie CLI-Befehle mit Optionen in eine leicht bearbeitbare Form um und generieren Sie den Befehl mit Eingabewerten.
|
||||||
|
command: Befehl
|
||||||
|
placeholder: Befehl hier einfügen
|
||||||
|
|
||||||
|
|
|
@ -392,3 +392,9 @@ tools:
|
||||||
text-to-binary:
|
text-to-binary:
|
||||||
title: Text to ASCII binary
|
title: Text to ASCII binary
|
||||||
description: Convert text to its ASCII binary representation and vice-versa.
|
description: Convert text to its ASCII binary representation and vice-versa.
|
||||||
|
|
||||||
|
cli-command-editor:
|
||||||
|
title: CLI command editor
|
||||||
|
description: Convert CLI commands with options into an easily editable form and generate the resulting command with input values.
|
||||||
|
command: Command
|
||||||
|
placeholder: Paste command here
|
||||||
|
|
|
@ -70,3 +70,8 @@ tools:
|
||||||
measurement: Measurement
|
measurement: Measurement
|
||||||
text: Text
|
text: Text
|
||||||
data: Data
|
data: Data
|
||||||
|
cli-command-editor:
|
||||||
|
title: editor de comandos CLI
|
||||||
|
description: Convierta comandos CLI con opciones en un formato fácilmente editable y genere el comando resultante con valores de entrada.
|
||||||
|
command: Dominio
|
||||||
|
placeholder: Pegar comando aquí
|
||||||
|
|
|
@ -80,3 +80,8 @@ tools:
|
||||||
copied: Le token a été copié
|
copied: Le token a été copié
|
||||||
length: Longueur
|
length: Longueur
|
||||||
tokenPlaceholder: Le token...
|
tokenPlaceholder: Le token...
|
||||||
|
cli-command-editor:
|
||||||
|
title: Éditeur de commandes CLI
|
||||||
|
description: Convertissez les commandes CLI avec des options dans un format facilement modifiable et générez la commande résultante avec des valeurs d'entrée.
|
||||||
|
command: Commande
|
||||||
|
placeholder: Coller la commande ici
|
||||||
|
|
|
@ -392,3 +392,9 @@ tools:
|
||||||
text-to-binary:
|
text-to-binary:
|
||||||
title: Tekst til ASCII binært
|
title: Tekst til ASCII binært
|
||||||
description: Konverter tekst til sin ASCII binære representasjon og visa-versa.
|
description: Konverter tekst til sin ASCII binære representasjon og visa-versa.
|
||||||
|
|
||||||
|
cli-command-editor:
|
||||||
|
title: CLI kommando editor
|
||||||
|
description: Konverter CLI-kommandoer med alternativer til et enkelt redigerbart format og generer den resulterende kommandoen med inndataverdier.
|
||||||
|
command: Kommando
|
||||||
|
placeholder: Lim inn kommando her
|
||||||
|
|
|
@ -70,3 +70,8 @@ tools:
|
||||||
measurement: 'Medidas'
|
measurement: 'Medidas'
|
||||||
text: 'Texto'
|
text: 'Texto'
|
||||||
data: 'Dados'
|
data: 'Dados'
|
||||||
|
cli-command-editor:
|
||||||
|
title: Editor de comando CLI
|
||||||
|
description: Converta comandos CLI com opções em um formato facilmente editável e gere o comando resultante com valores de entrada.
|
||||||
|
command: Comando
|
||||||
|
placeholder: Cole o comando aqui
|
||||||
|
|
|
@ -70,3 +70,8 @@ tools:
|
||||||
measurement: Вимірювання
|
measurement: Вимірювання
|
||||||
text: Текст
|
text: Текст
|
||||||
data: Дані
|
data: Дані
|
||||||
|
cli-command-editor:
|
||||||
|
title: Редактор команд CLI
|
||||||
|
description: Перетворіть команди CLI з опціями у форму, яку легко редагувати, та згенеруйте результуючу команду з вхідними значеннями.
|
||||||
|
command: Команда
|
||||||
|
placeholder: Вставте команду сюди
|
||||||
|
|
|
@ -381,3 +381,9 @@ tools:
|
||||||
text-to-binary:
|
text-to-binary:
|
||||||
title: Chuyển đổi văn bản thành nhị phân ASCII
|
title: Chuyển đổi văn bản thành nhị phân ASCII
|
||||||
description: Chuyển đổi văn bản thành biểu diễn nhị phân ASCII của nó và ngược lại.
|
description: Chuyển đổi văn bản thành biểu diễn nhị phân ASCII của nó và ngược lại.
|
||||||
|
|
||||||
|
cli-command-editor:
|
||||||
|
title: Trình soạn thảo lệnh CLI
|
||||||
|
description: Chuyển đổi các lệnh CLI có tùy chọn thành dạng dễ chỉnh sửa và tạo lệnh kết quả với các giá trị đầu vào.
|
||||||
|
command: Yêu cầu
|
||||||
|
placeholder: Dán lệnh vào đây
|
||||||
|
|
|
@ -388,3 +388,9 @@ tools:
|
||||||
text-to-binary:
|
text-to-binary:
|
||||||
title: 文本到 ASCII 二进制
|
title: 文本到 ASCII 二进制
|
||||||
description: 将文本转换为其 ASCII 二进制表示形式,反之亦然。
|
description: 将文本转换为其 ASCII 二进制表示形式,反之亦然。
|
||||||
|
|
||||||
|
cli-command-editor:
|
||||||
|
title: CLI 命令编辑器
|
||||||
|
description: 将带有选项的 CLI 命令转换为易于编辑的形式,并生成带有输入值的结果命令。
|
||||||
|
command: 命令
|
||||||
|
placeholder: 将命令粘贴到此处
|
||||||
|
|
11
src/tools/cli-command-editor/cli-command-editor.e2e.spec.ts
Normal file
11
src/tools/cli-command-editor/cli-command-editor.e2e.spec.ts
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
import { expect, test } from '@playwright/test';
|
||||||
|
|
||||||
|
test.describe('Tool - Cli command editor', () => {
|
||||||
|
test.beforeEach(async ({ page }) => {
|
||||||
|
await page.goto('/cli-command-editor');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Has correct title', async ({ page }) => {
|
||||||
|
await expect(page).toHaveTitle('Cli command editor - IT Tools');
|
||||||
|
});
|
||||||
|
});
|
140
src/tools/cli-command-editor/cli-command-editor.service.test.ts
Normal file
140
src/tools/cli-command-editor/cli-command-editor.service.test.ts
Normal file
|
@ -0,0 +1,140 @@
|
||||||
|
import { describe, expect, it } from 'vitest';
|
||||||
|
import { buildEditedCommand, buildOptionsObject, extractOptions, isOption, sanitizeOption } from './cli-command-editor.service';
|
||||||
|
|
||||||
|
describe('cli-command-editor', () => {
|
||||||
|
describe('extractOptions', () => {
|
||||||
|
it ('extracts all the options from a command', () => {
|
||||||
|
expect(
|
||||||
|
extractOptions('aws elb describe-load-balancers --load-balancer-name my-load-balancer')[0],
|
||||||
|
).toContain('--load-balancer-name');
|
||||||
|
|
||||||
|
expect(
|
||||||
|
extractOptions('aws elb describe-load-balancers --load-balancer-name my-load-balancer --debug --query my-queryyy')[0],
|
||||||
|
).toContain('--load-balancer-name');
|
||||||
|
|
||||||
|
expect(
|
||||||
|
extractOptions('aws elb describe-load-balancers --load-balancer-name my-load-balancer --debug --query my-queryyy')[1],
|
||||||
|
).toContain('--debug');
|
||||||
|
|
||||||
|
expect(
|
||||||
|
extractOptions('aws elb describe-load-balancers --load-balancer-name my-load-balancer --debug --query my-queryyy')[2],
|
||||||
|
).toContain('--query');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('extracts all the option from a command with a mix of hyphen and double hyphens', () => {
|
||||||
|
expect(
|
||||||
|
extractOptions('npm i lodash -g --legacy-peer-deps')[0],
|
||||||
|
).toContain('-g');
|
||||||
|
|
||||||
|
expect(
|
||||||
|
extractOptions('npm i lodash -g --legacy-peer-deps')[1],
|
||||||
|
).toContain('--legacy-peer-deps');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('shouldn\'t extract any options from a command without options', () => {
|
||||||
|
expect(
|
||||||
|
extractOptions('npm i lodash'),
|
||||||
|
).toEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('shouldn\'t return any options if command is not passed', () => {
|
||||||
|
expect(extractOptions()).toEqual([]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('buildOptionsObject', () => {
|
||||||
|
it('returns a valid options object with the given options', () => {
|
||||||
|
expect(
|
||||||
|
buildOptionsObject(['--debug', '--load-balancer-names']),
|
||||||
|
).toEqual({
|
||||||
|
'--debug': '',
|
||||||
|
'--load-balancer-names': '',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns an empty obnject with blank options array', () => {
|
||||||
|
expect(
|
||||||
|
buildOptionsObject([]),
|
||||||
|
).toEqual({});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('sanitizeOption', () => {
|
||||||
|
it('returns the sanitized option without `id` suffix', () => {
|
||||||
|
expect(sanitizeOption('--debug-id-1dfsj'))
|
||||||
|
.toEqual('--debug');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns the blank string', () => {
|
||||||
|
expect(sanitizeOption('')).toEqual('');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('isOption', () => {
|
||||||
|
it('returns true for a valid double hyphen option token', () => {
|
||||||
|
expect(isOption('--debug')).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns true for a valid single hyphen option token', () => {
|
||||||
|
expect(isOption('-i')).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns false for an non-option token', () => {
|
||||||
|
expect(isOption('hello-world')).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('buildEditedCommand', () => {
|
||||||
|
it('returns the edited command', () => {
|
||||||
|
expect(
|
||||||
|
buildEditedCommand({
|
||||||
|
'--debug-id-1dfsj': 'stdin',
|
||||||
|
'-p': '',
|
||||||
|
'-m': 'nahhhh',
|
||||||
|
}, {
|
||||||
|
'--debug-id-1dfsj': 'stdin',
|
||||||
|
'-p': '',
|
||||||
|
'-m': 'nahhhh',
|
||||||
|
}, 'aws node --debug stdio -p -m okayyy'),
|
||||||
|
).toEqual('aws node --debug stdin -p -m nahhhh');
|
||||||
|
|
||||||
|
expect(
|
||||||
|
buildEditedCommand({
|
||||||
|
'-d-id-1dfsj': '',
|
||||||
|
'-p-id-fdsd': '4444:3333',
|
||||||
|
'-p-id-fddd': '3333:4444',
|
||||||
|
'--name-id-nnnn': 'clickhouse-server',
|
||||||
|
'--ulimit-id-uuuu': 'nofile=3333:4444',
|
||||||
|
}, {
|
||||||
|
'-d-id-1dfsj': '',
|
||||||
|
'-p-id-fdsd': '4444:3333',
|
||||||
|
'-p-id-fddd': '3333:4444',
|
||||||
|
'--name-id-nnnn': 'clickhouse-server',
|
||||||
|
'--ulimit-id-uuuu': 'nofile=3333:4444',
|
||||||
|
}, 'docker run -d -p 18123:8123 -p 19000:9000 --name some-clickhouse-server --ulimit nofile=262144:262144 clickhouse/clickhouse-server'),
|
||||||
|
).toEqual('docker run -d -p 4444:3333 -p 3333:4444 --name clickhouse-server --ulimit nofile=3333:4444 clickhouse/clickhouse-server');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns the edited command when options object and CLI options order doesn\'t match', () => {
|
||||||
|
expect(
|
||||||
|
buildEditedCommand({
|
||||||
|
'-d-id-t1dd3': 'true',
|
||||||
|
'--install-id-only123': 'nodemon',
|
||||||
|
}, {
|
||||||
|
'--install-id-only123': 'nodem',
|
||||||
|
'-d-id-t1dd3': 'false',
|
||||||
|
}, 'npm --install nodem -d false'),
|
||||||
|
).toBe('npm --install nodemon -d true');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns the original command', () => {
|
||||||
|
expect(
|
||||||
|
buildEditedCommand({}, {}, 'npm install nodemon'),
|
||||||
|
).toBe('npm install nodemon');
|
||||||
|
|
||||||
|
expect(
|
||||||
|
buildEditedCommand({}, {}, 'aws load-balancer describe-load-balancers all'),
|
||||||
|
).toBe('aws load-balancer describe-load-balancers all');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
104
src/tools/cli-command-editor/cli-command-editor.service.ts
Normal file
104
src/tools/cli-command-editor/cli-command-editor.service.ts
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
import { generateRandomId } from '@/utils/random';
|
||||||
|
|
||||||
|
export function isOption(token: string): boolean {
|
||||||
|
return token?.startsWith('--') || token?.startsWith('-');
|
||||||
|
}
|
||||||
|
|
||||||
|
export function extractOptions(command: string = ''): string[] {
|
||||||
|
/*
|
||||||
|
in a CLI, the options are either written with a hyphen or double hyphens, however,
|
||||||
|
script names or package/library sometimes include a hyphen, too, for example 'describe-load-balancers'
|
||||||
|
*/
|
||||||
|
|
||||||
|
// split into tokens first
|
||||||
|
const tokens = command.split(' ');
|
||||||
|
|
||||||
|
// map each token of the command to an option
|
||||||
|
const options = tokens.map((token: string) => {
|
||||||
|
// every option in a starts with either a hyphen or double hyphens
|
||||||
|
if (isOption(token)) {
|
||||||
|
const randomId = generateRandomId();
|
||||||
|
return `${token}-${randomId}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
|
}).filter((option: string): boolean => !!option);
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildOptionsObject(options: string[]): Record<string, string> {
|
||||||
|
const optionsObject: Record<string, string> = {};
|
||||||
|
|
||||||
|
for (const option of options) {
|
||||||
|
optionsObject[option] = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return optionsObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function sanitizeOption(option: string): string {
|
||||||
|
return option.split('-id')?.[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildEditedCommand(options: Record<string, string>, originalOptions: Record<string, string>, command: string): string {
|
||||||
|
if (!Object.keys(options).length) {
|
||||||
|
return command;
|
||||||
|
}
|
||||||
|
|
||||||
|
const tokens = command.split(' ');
|
||||||
|
const editedTokens = [];
|
||||||
|
|
||||||
|
// user may input the option value in any order, from the form
|
||||||
|
// preserve the original object with options in the correct
|
||||||
|
// order as they appear in the original command, this is done
|
||||||
|
// to handle the interpolation of edited option values into the
|
||||||
|
// command
|
||||||
|
originalOptions = Object.entries(options)
|
||||||
|
.reduce((previousValue: Record<string, string>, currentValue: string[]) => {
|
||||||
|
previousValue[currentValue[0]] = currentValue[1];
|
||||||
|
|
||||||
|
return previousValue;
|
||||||
|
}, originalOptions);
|
||||||
|
|
||||||
|
const defaultValues: Record<string, string> = {};
|
||||||
|
// replacing the options and their values (if any) with formatter ($i) to
|
||||||
|
// help in interpolation of the command
|
||||||
|
for (let i = 0, j = 0, n = tokens.length; i < n; ++i) {
|
||||||
|
const token = tokens[i];
|
||||||
|
const nextToken = tokens[i + 1];
|
||||||
|
|
||||||
|
if (isOption(token)) {
|
||||||
|
editedTokens.push(`$${j}`);
|
||||||
|
|
||||||
|
if (!isOption(nextToken)) {
|
||||||
|
++i;
|
||||||
|
defaultValues[`$${j}`] = nextToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
++j;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
editedTokens.push(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
let editedCommand = editedTokens.join(' ');
|
||||||
|
|
||||||
|
const originalOptionKeys = Object.keys(originalOptions);
|
||||||
|
|
||||||
|
for (let i = 0, n = originalOptionKeys.length; i < n; ++i) {
|
||||||
|
const key = originalOptionKeys[i];
|
||||||
|
const keyWithoutIdSuffix = key.split('-id-')[0] || key;
|
||||||
|
|
||||||
|
if (originalOptions[key]) {
|
||||||
|
editedCommand = editedCommand.replace(`$${i}`, `${keyWithoutIdSuffix} ${originalOptions[key]}`);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const value = defaultValues[`$${i}`];
|
||||||
|
const replaceValue = value ? `${keyWithoutIdSuffix} ${value}` : keyWithoutIdSuffix;
|
||||||
|
editedCommand = editedCommand.replace(`$${i}`, replaceValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return editedCommand;
|
||||||
|
}
|
51
src/tools/cli-command-editor/cli-command-editor.vue
Normal file
51
src/tools/cli-command-editor/cli-command-editor.vue
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import * as service from './cli-command-editor.service';
|
||||||
|
|
||||||
|
const inputCommand = ref('');
|
||||||
|
const options = computed(() => service.extractOptions(inputCommand.value));
|
||||||
|
const optionsObject = computed(() => service.buildOptionsObject(options.value));
|
||||||
|
const optionsInput = ref<{ [k: string]: string }>(optionsObject.value);
|
||||||
|
const command = ref('');
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<c-card>
|
||||||
|
<n-grid x-gap="12" y-gap="12" cols="1 600:3">
|
||||||
|
<n-gi span="2">
|
||||||
|
<c-input-text
|
||||||
|
v-model:value="inputCommand"
|
||||||
|
label-position="left"
|
||||||
|
label-width="130px"
|
||||||
|
:label="$t('tools.cli-command-editor.command')"
|
||||||
|
:aria-label="$t('tools.cli-command-editor.command')"
|
||||||
|
:placeholder="$t('tools.cli-command-editor.placeholder')"
|
||||||
|
:aria-placeholder="$t('tools.cli-command-editor.placeholder')"
|
||||||
|
raw-text
|
||||||
|
@update:value="() => { command = inputCommand }"
|
||||||
|
/>
|
||||||
|
<div v-for="option in options" :key="option" flex justify-center>
|
||||||
|
<c-input-text
|
||||||
|
v-model:value="optionsInput[option]"
|
||||||
|
label-position="left"
|
||||||
|
label-width="130px"
|
||||||
|
label-align="left"
|
||||||
|
:label="service.sanitizeOption(option)"
|
||||||
|
:aria-label="service.sanitizeOption(option)"
|
||||||
|
:placeholder="service.sanitizeOption(option)"
|
||||||
|
:aria-placeholder="service.sanitizeOption(option)"
|
||||||
|
mt-6
|
||||||
|
@update:value="() => { command = service.buildEditedCommand(optionsInput, optionsObject, inputCommand) }"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<c-text-copyable
|
||||||
|
v-if="command"
|
||||||
|
:value="command"
|
||||||
|
font-mono
|
||||||
|
:show-icon="false"
|
||||||
|
mt-6
|
||||||
|
/>
|
||||||
|
</n-gi>
|
||||||
|
</n-grid>
|
||||||
|
</c-card>
|
||||||
|
</template>
|
12
src/tools/cli-command-editor/index.ts
Normal file
12
src/tools/cli-command-editor/index.ts
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
import { Terminal2 } from '@vicons/tabler';
|
||||||
|
import { defineTool } from '../tool';
|
||||||
|
|
||||||
|
export const tool = defineTool({
|
||||||
|
name: 'CLI command editor',
|
||||||
|
path: '/cli-command-editor',
|
||||||
|
description: '',
|
||||||
|
keywords: ['cli', 'command', 'editor'],
|
||||||
|
component: () => import('./cli-command-editor.vue'),
|
||||||
|
icon: Terminal2,
|
||||||
|
createdAt: new Date('2025-06-21'),
|
||||||
|
});
|
|
@ -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 cliCommandEditor } from './cli-command-editor';
|
||||||
import { tool as emailNormalizer } from './email-normalizer';
|
import { tool as emailNormalizer } from './email-normalizer';
|
||||||
|
|
||||||
import { tool as asciiTextDrawer } from './ascii-text-drawer';
|
import { tool as asciiTextDrawer } from './ascii-text-drawer';
|
||||||
|
@ -160,6 +161,7 @@ export const toolsByCategory: ToolCategory[] = [
|
||||||
emailNormalizer,
|
emailNormalizer,
|
||||||
regexTester,
|
regexTester,
|
||||||
regexMemo,
|
regexMemo,
|
||||||
|
cliCommandEditor,
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue