1
0
Fork 0
mirror of https://github.com/CorentinTh/it-tools.git synced 2025-08-07 06:25:18 +02:00

fix(lint): lint fixes

This commit is contained in:
Dhwanik Panchal 2025-06-28 14:51:38 +05:30
parent 2e91373d6b
commit e66702ec9f
5 changed files with 114 additions and 122 deletions

View file

@ -1,4 +1,4 @@
import { test, expect } from '@playwright/test'; import { expect, test } from '@playwright/test';
test.describe('Tool - Cli command editor', () => { test.describe('Tool - Cli command editor', () => {
test.beforeEach(async ({ page }) => { test.beforeEach(async ({ page }) => {
@ -8,8 +8,4 @@ test.describe('Tool - Cli command editor', () => {
test('Has correct title', async ({ page }) => { test('Has correct title', async ({ page }) => {
await expect(page).toHaveTitle('Cli command editor - IT Tools'); await expect(page).toHaveTitle('Cli command editor - IT Tools');
}); });
});
test('', async ({ page }) => {
});
});

View file

@ -1,140 +1,140 @@
import { expect, describe, it } from 'vitest'; import { describe, expect, it } from 'vitest';
import { extractOptions, buildOptionsObject, sanitizeOption, buildEditedCommand, isOption } from './cli-command-editor.service'; import { buildEditedCommand, buildOptionsObject, extractOptions, isOption, sanitizeOption } from './cli-command-editor.service';
describe('cli-command-editor', () => { describe('cli-command-editor', () => {
describe("extractOptions", () => { describe('extractOptions', () => {
it ("extracts all the options from a command", () => { it ('extracts all the options from a command', () => {
expect( expect(
extractOptions("aws elb describe-load-balancers --load-balancer-name my-load-balancer")[0] extractOptions('aws elb describe-load-balancers --load-balancer-name my-load-balancer')[0],
).toContain("--load-balancer-name"); ).toContain('--load-balancer-name');
expect( expect(
extractOptions("aws elb describe-load-balancers --load-balancer-name my-load-balancer --debug --query my-queryyy")[0] extractOptions('aws elb describe-load-balancers --load-balancer-name my-load-balancer --debug --query my-queryyy')[0],
).toContain("--load-balancer-name"); ).toContain('--load-balancer-name');
expect( expect(
extractOptions("aws elb describe-load-balancers --load-balancer-name my-load-balancer --debug --query my-queryyy")[1] extractOptions('aws elb describe-load-balancers --load-balancer-name my-load-balancer --debug --query my-queryyy')[1],
).toContain("--debug"); ).toContain('--debug');
expect( expect(
extractOptions("aws elb describe-load-balancers --load-balancer-name my-load-balancer --debug --query my-queryyy")[2] extractOptions('aws elb describe-load-balancers --load-balancer-name my-load-balancer --debug --query my-queryyy')[2],
).toContain("--query"); ).toContain('--query');
}); });
it("extracts all the option from a command with a mix of hyphen and double hyphens", () => { it('extracts all the option from a command with a mix of hyphen and double hyphens', () => {
expect( expect(
extractOptions("npm i lodash -g --legacy-peer-deps")[0] extractOptions('npm i lodash -g --legacy-peer-deps')[0],
).toContain("-g"); ).toContain('-g');
expect( expect(
extractOptions("npm i lodash -g --legacy-peer-deps")[1] extractOptions('npm i lodash -g --legacy-peer-deps')[1],
).toContain("--legacy-peer-deps"); ).toContain('--legacy-peer-deps');
}); });
it("shouldn't extract any options from a command without options", () => { it('shouldn\'t extract any options from a command without options', () => {
expect( expect(
extractOptions("npm i lodash") extractOptions('npm i lodash'),
).toEqual([]); ).toEqual([]);
}); });
it("shouldn't return any options if command is not passed", () => { it('shouldn\'t return any options if command is not passed', () => {
expect(extractOptions()).toEqual([]); expect(extractOptions()).toEqual([]);
}); });
}); });
describe("buildOptionsObject", () => { describe('buildOptionsObject', () => {
it("returns a valid options object with the given options", () => { it('returns a valid options object with the given options', () => {
expect( expect(
buildOptionsObject(["--debug", "--load-balancer-names"]) buildOptionsObject(['--debug', '--load-balancer-names']),
).toEqual({ ).toEqual({
"--debug": "", '--debug': '',
"--load-balancer-names": "", '--load-balancer-names': '',
}); });
}); });
it("returns an empty obnject with blank options array", () => { it('returns an empty obnject with blank options array', () => {
expect( expect(
buildOptionsObject([]) buildOptionsObject([]),
).toEqual({}); ).toEqual({});
}); });
}); });
describe("sanitizeOption", () => { describe('sanitizeOption', () => {
it("returns the sanitized option without 'id' suffix", () => { it('returns the sanitized option without `id` suffix', () => {
expect(sanitizeOption("--debug-id-1dfsj")) expect(sanitizeOption('--debug-id-1dfsj'))
.toEqual("--debug"); .toEqual('--debug');
}); });
it("returns the blank string", () => { it('returns the blank string', () => {
expect(sanitizeOption("")).toEqual(""); expect(sanitizeOption('')).toEqual('');
}); });
}); });
describe("isOption", () => { describe('isOption', () => {
it("returns true for a valid double hyphen option token", () => { it('returns true for a valid double hyphen option token', () => {
expect(isOption("--debug")).toBe(true); expect(isOption('--debug')).toBe(true);
}); });
it("returns true for a valid single hyphen option token", () => { it('returns true for a valid single hyphen option token', () => {
expect(isOption("-i")).toBe(true); expect(isOption('-i')).toBe(true);
}); });
it("returns false for an non-option token", () => { it('returns false for an non-option token', () => {
expect(isOption("hello-world")).toBe(false); expect(isOption('hello-world')).toBe(false);
}); });
}); });
describe("buildEditedCommand", () => { describe('buildEditedCommand', () => {
it("returns the edited command", () => { it('returns the edited command', () => {
expect( expect(
buildEditedCommand({ buildEditedCommand({
"--debug-id-1dfsj": "stdin", '--debug-id-1dfsj': 'stdin',
"-p": "", '-p': '',
"-m": "nahhhh", '-m': 'nahhhh',
}, { }, {
"--debug-id-1dfsj": "stdin", '--debug-id-1dfsj': 'stdin',
"-p": "", '-p': '',
"-m": "nahhhh", '-m': 'nahhhh',
}, "aws node --debug stdio -p -m okayyy") }, 'aws node --debug stdio -p -m okayyy'),
).toEqual("aws node --debug stdin -p -m nahhhh"); ).toEqual('aws node --debug stdin -p -m nahhhh');
expect( expect(
buildEditedCommand({ buildEditedCommand({
"-d-id-1dfsj": "", '-d-id-1dfsj': '',
"-p-id-fdsd": "4444:3333", '-p-id-fdsd': '4444:3333',
"-p-id-fddd": "3333:4444", '-p-id-fddd': '3333:4444',
"--name-id-nnnn": "clickhouse-server", '--name-id-nnnn': 'clickhouse-server',
"--ulimit-id-uuuu": "nofile=3333:4444", '--ulimit-id-uuuu': 'nofile=3333:4444',
}, { }, {
"-d-id-1dfsj": "", '-d-id-1dfsj': '',
"-p-id-fdsd": "4444:3333", '-p-id-fdsd': '4444:3333',
"-p-id-fddd": "3333:4444", '-p-id-fddd': '3333:4444',
"--name-id-nnnn": "clickhouse-server", '--name-id-nnnn': 'clickhouse-server',
"--ulimit-id-uuuu": "nofile=3333:4444", '--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") }, '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"); ).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", () => { it('returns the edited command when options object and CLI options order doesn\'t match', () => {
expect( expect(
buildEditedCommand({ buildEditedCommand({
"-d-id-t1dd3": "true", '-d-id-t1dd3': 'true',
"--install-id-only123": "nodemon", '--install-id-only123': 'nodemon',
}, { }, {
"--install-id-only123": "nodem", '--install-id-only123': 'nodem',
"-d-id-t1dd3": "false", '-d-id-t1dd3': 'false',
}, "npm --install nodem -d false") }, 'npm --install nodem -d false'),
).toBe("npm --install nodemon -d true"); ).toBe('npm --install nodemon -d true');
}); });
it("returns the original command", () => { it('returns the original command', () => {
expect( expect(
buildEditedCommand({}, {}, "npm install nodemon") buildEditedCommand({}, {}, 'npm install nodemon'),
).toBe("npm install nodemon"); ).toBe('npm install nodemon');
expect( expect(
buildEditedCommand({}, {}, "aws load-balancer describe-load-balancers all") buildEditedCommand({}, {}, 'aws load-balancer describe-load-balancers all'),
).toBe("aws load-balancer describe-load-balancers all"); ).toBe('aws load-balancer describe-load-balancers all');
}); });
}); });
}); });

View file

@ -1,20 +1,17 @@
import { generateRandomId } from "@/utils/random"; import { generateRandomId } from '@/utils/random';
export function isOption(token: string): boolean { export function isOption(token: string): boolean {
return token?.startsWith("--") || token?.startsWith("-") return token?.startsWith('--') || token?.startsWith('-');
} }
export function extractOptions(command: string = ""): string[] { export function extractOptions(command: string = ''): string[] {
/* /*
aws elb describe-load-balancers --load-balancer-name my-load-balancer
npm i forever -g
docker run -d -p 18123:8123 -p 19000:9000 -e CLICKHOUSE_PASSWORD=changeme --name some-clickhouse-server --ulimit nofile=262144:262144 clickhouse/clickhouse-server
in a CLI, the options are either written with a hyphen or double hyphens, however, 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' script names or package/library sometimes include a hyphen, too, for example 'describe-load-balancers'
*/ */
// split into tokens first // split into tokens first
const tokens = command.split(" "); const tokens = command.split(' ');
// map each token of the command to an option // map each token of the command to an option
const options = tokens.map((token: string) => { const options = tokens.map((token: string) => {
@ -24,7 +21,7 @@ export function extractOptions(command: string = ""): string[] {
return `${token}-${randomId}`; return `${token}-${randomId}`;
} }
return ""; return '';
}).filter((option: string): boolean => !!option); }).filter((option: string): boolean => !!option);
return options; return options;
} }
@ -33,20 +30,22 @@ export function buildOptionsObject(options: string[]): Record<string, string> {
const optionsObject: Record<string, string> = {}; const optionsObject: Record<string, string> = {};
for (const option of options) { for (const option of options) {
optionsObject[option] = ""; optionsObject[option] = '';
} }
return optionsObject; return optionsObject;
} }
export function sanitizeOption(option: string): string { export function sanitizeOption(option: string): string {
return option.split("-id")?.[0]; return option.split('-id')?.[0];
} }
export function buildEditedCommand(options: Record<string, string>, originalOptions: Record<string, string>, command: string): string { export function buildEditedCommand(options: Record<string, string>, originalOptions: Record<string, string>, command: string): string {
if (!Object.keys(options).length) return command; if (!Object.keys(options).length) {
return command;
}
const tokens = command.split(" "); const tokens = command.split(' ');
const editedTokens = []; const editedTokens = [];
// user may input the option value in any order, from the form // user may input the option value in any order, from the form
@ -56,26 +55,26 @@ export function buildEditedCommand(options: Record<string, string>, originalOpti
// command // command
originalOptions = Object.entries(options) originalOptions = Object.entries(options)
.reduce((previousValue: Record<string, string>, currentValue: string[]) => { .reduce((previousValue: Record<string, string>, currentValue: string[]) => {
previousValue[currentValue[0]] = currentValue[1] previousValue[currentValue[0]] = currentValue[1];
return previousValue return previousValue;
}, originalOptions) }, originalOptions);
const defaultValues: Record<string, string> = {}; const defaultValues: Record<string, string> = {};
// replacing the options and their values (if any) with formatter ($i) to // replacing the options and their values (if any) with formatter ($i) to
// help in interpolation of the command // help in interpolation of the command
for (let i = 0, j = 0, n = tokens.length; i < n; ++i) { for (let i = 0, j = 0, n = tokens.length; i < n; ++i) {
const token = tokens[i]; const token = tokens[i];
const nextToken = tokens[i+1]; const nextToken = tokens[i + 1];
if (isOption(token)) { if (isOption(token)) {
editedTokens.push(`$${j}`) editedTokens.push(`$${j}`);
if (!isOption(nextToken)) { if (!isOption(nextToken)) {
++i; ++i;
defaultValues[`$${j}`] = nextToken; defaultValues[`$${j}`] = nextToken;
} }
++j; ++j;
continue; continue;
} }
@ -83,17 +82,18 @@ export function buildEditedCommand(options: Record<string, string>, originalOpti
editedTokens.push(token); editedTokens.push(token);
} }
let editedCommand = editedTokens.join(" "); let editedCommand = editedTokens.join(' ');
const originalOptionKeys = Object.keys(originalOptions); const originalOptionKeys = Object.keys(originalOptions);
for (let i = 0, n = originalOptionKeys.length; i < n; ++i) { for (let i = 0, n = originalOptionKeys.length; i < n; ++i) {
const key = originalOptionKeys[i]; const key = originalOptionKeys[i];
const keyWithoutIdSuffix = key.split("-id-")[0] || key; const keyWithoutIdSuffix = key.split('-id-')[0] || key;
if (originalOptions[key]) { if (originalOptions[key]) {
editedCommand = editedCommand.replace(`$${i}`, `${keyWithoutIdSuffix} ${originalOptions[key]}`); editedCommand = editedCommand.replace(`$${i}`, `${keyWithoutIdSuffix} ${originalOptions[key]}`);
} else { }
else {
const value = defaultValues[`$${i}`]; const value = defaultValues[`$${i}`];
const replaceValue = value ? `${keyWithoutIdSuffix} ${value}` : keyWithoutIdSuffix; const replaceValue = value ? `${keyWithoutIdSuffix} ${value}` : keyWithoutIdSuffix;
editedCommand = editedCommand.replace(`$${i}`, replaceValue); editedCommand = editedCommand.replace(`$${i}`, replaceValue);
@ -101,4 +101,4 @@ export function buildEditedCommand(options: Record<string, string>, originalOpti
} }
return editedCommand; return editedCommand;
} }

View file

@ -1,10 +1,11 @@
<script setup lang="ts"> <script setup lang="ts">
import * as service from "./cli-command-editor.service" import * as service from './cli-command-editor.service';
const inputCommand = ref("");
const options = computed(() => service.extractOptions(inputCommand.value)); const inputCommand = ref('');
const optionsObject = computed(() => service.buildOptionsObject(options.value)); const options = computed(() => service.extractOptions(inputCommand.value));
const optionsInput = ref<{ [k: string]: string }>(optionsObject.value); const optionsObject = computed(() => service.buildOptionsObject(options.value));
let command = ref(""); const optionsInput = ref<{ [k: string]: string }>(optionsObject.value);
const command = ref('');
</script> </script>
<template> <template>
@ -20,13 +21,11 @@
:placeholder="$t('tools.cli-command-editor.placeholder')" :placeholder="$t('tools.cli-command-editor.placeholder')"
:aria-placeholder="$t('tools.cli-command-editor.placeholder')" :aria-placeholder="$t('tools.cli-command-editor.placeholder')"
raw-text raw-text
@update:value="() => { command = inputCommand }"
@update:value="() => {command = inputCommand}"
/> />
<div v-for="option in options" flex justify-center> <div v-for="option in options" :key="option" flex justify-center>
<c-input-text <c-input-text
v-model:value="optionsInput[option]" v-model:value="optionsInput[option]"
:key="option"
label-position="left" label-position="left"
label-width="130px" label-width="130px"
label-align="left" label-align="left"
@ -34,22 +33,19 @@
:aria-label="service.sanitizeOption(option)" :aria-label="service.sanitizeOption(option)"
:placeholder="service.sanitizeOption(option)" :placeholder="service.sanitizeOption(option)"
:aria-placeholder="service.sanitizeOption(option)" :aria-placeholder="service.sanitizeOption(option)"
@update:value="() => {command = service.buildEditedCommand(optionsInput, optionsObject, inputCommand)}"
mt-6 mt-6
@update:value="() => { command = service.buildEditedCommand(optionsInput, optionsObject, inputCommand) }"
/> />
</div> </div>
<c-text-copyable <c-text-copyable
:value="command"
v-if="command" v-if="command"
:value="command"
font-mono font-mono
:show-icon="false" :show-icon="false"
mt-6 mt-6
/> />
</n-gi> </n-gi>
</n-grid> </n-grid>
</c-card> </c-card>
</template> </template>
<style lang="less" scoped>
</style>

View file

@ -9,4 +9,4 @@ export const tool = defineTool({
component: () => import('./cli-command-editor.vue'), component: () => import('./cli-command-editor.vue'),
icon: Terminal2, icon: Terminal2,
createdAt: new Date('2025-06-21'), createdAt: new Date('2025-06-21'),
}); });