Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 117 additions & 0 deletions tests/website/cliCommand.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import { describe, expect, test } from 'vitest';
import { type CliCommandPackOptions, generateCliCommand } from '../../website/client/components/utils/cliCommand.js';

const createOptions = (overrides: Partial<CliCommandPackOptions> = {}): CliCommandPackOptions => ({
format: 'xml',
removeComments: false,
removeEmptyLines: false,
showLineNumbers: false,
fileSummary: true,
directoryStructure: true,
includePatterns: '',
ignorePatterns: '',
outputParsable: false,
compress: false,
...overrides,
});

describe('generateCliCommand', () => {
test('should generate basic command without options', () => {
expect(generateCliCommand(undefined)).toBe('npx repomix');
});

test('should add --remote for valid GitHub shorthand', () => {
const result = generateCliCommand('yamadashy/repomix');
expect(result).toBe("npx repomix --remote 'yamadashy/repomix'");
});

test('should add --remote for valid URL', () => {
const result = generateCliCommand('https://github.com/yamadashy/repomix');
expect(result).toBe("npx repomix --remote 'https://github.com/yamadashy/repomix'");
});

test('should not add --remote for uploaded file names', () => {
const result = generateCliCommand('project.zip');
expect(result).toBe('npx repomix');
});

test('should add format option when not default xml', () => {
const result = generateCliCommand(undefined, createOptions({ format: 'markdown' }));
expect(result).toBe('npx repomix --style markdown');
});

test('should not add format option when xml (default)', () => {
const result = generateCliCommand(undefined, createOptions({ format: 'xml' }));
expect(result).toBe('npx repomix');
});

test('should add boolean flags', () => {
const result = generateCliCommand(
undefined,
createOptions({
removeComments: true,
removeEmptyLines: true,
showLineNumbers: true,
outputParsable: true,
compress: true,
}),
);
expect(result).toBe(
'npx repomix --remove-comments --remove-empty-lines --output-show-line-numbers --parsable-style --compress',
);
});

test('should add no- flags for disabled defaults', () => {
const result = generateCliCommand(
undefined,
createOptions({
fileSummary: false,
directoryStructure: false,
}),
);
expect(result).toBe('npx repomix --no-file-summary --no-directory-structure');
});

test('should shell-escape include and ignore patterns', () => {
const result = generateCliCommand(
undefined,
createOptions({
includePatterns: '**/*.ts',
ignorePatterns: "test's dir",
}),
);
expect(result).toBe("npx repomix --include '**/*.ts' --ignore 'test'\\''s dir'");
});

test('should skip empty patterns', () => {
const result = generateCliCommand(
undefined,
createOptions({
includePatterns: ' ',
ignorePatterns: '',
}),
);
expect(result).toBe('npx repomix');
});

test('should combine all options', () => {
const result = generateCliCommand(
'yamadashy/repomix',
createOptions({
format: 'markdown',
removeComments: true,
compress: true,
fileSummary: false,
includePatterns: 'src/**',
}),
);
expect(result).toBe(
"npx repomix --remote 'yamadashy/repomix' --style markdown --remove-comments --compress --no-file-summary --include 'src/**'",
);
});

test('should escape shell metacharacters in repository URL', () => {
const result = generateCliCommand('https://example.com/repo;rm -rf /', undefined);
expect(result).toBe("npx repomix --remote 'https://example.com/repo;rm -rf /'");
});
});
67 changes: 22 additions & 45 deletions website/client/components/Home/SupportMessage.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script setup lang="ts">
import { HeartHandshake, Star } from 'lucide-vue-next';
import { Star } from 'lucide-vue-next';
import { computed, ref } from 'vue';

const messages = [
Expand All @@ -26,73 +26,50 @@ const supportMessage = computed(() => messages[currentMessageIndex.value]);
</script>

<template>
<div class="support-notice">
<div class="support-message">
<a :href="supportMessage.link" target="_blank" rel="noopener noreferrer" class="support-link">
<component :is="supportMessage.icon" :size="14" class="support-icon" />
<span class="link-text">{{ supportMessage.linkText }}</span>{{ supportMessage.suffix }}
</a>
</div>
<div class="support-banner">
<a :href="supportMessage.link" target="_blank" rel="noopener noreferrer" class="support-link">
<component :is="supportMessage.icon" :size="14" class="support-icon" />
<span class="link-text">{{ supportMessage.linkText }}</span>{{ supportMessage.suffix }}
</a>
</div>
</template>

<style scoped>
.support-notice {
padding: 8px;
background: var(--vp-c-bg-soft);
border-top: 1px solid var(--vp-c-border);
display: flex;
justify-content: center;
align-items: center;
text-align: center;
min-height: 45px;
}

.support-message {
.support-banner {
display: flex;
align-items: center;
justify-content: center;
color: var(--vp-c-text-2);
font-size: 12px;
width: 100%;
}

.support-icon {
flex-shrink: 0;
transition: color 0.3s ease;
color: v-bind('supportMessage.color');
padding: 10px 16px;
background: linear-gradient(135deg, rgba(255, 140, 0, 0.05) 0%, var(--vp-c-bg-soft) 100%);
border-top: 1px solid var(--vp-c-border);
}

.support-link {
text-decoration: none;
font-weight: normal;
transition: color 0.3s ease;
display: flex;
align-items: center;
gap: 6px;
font-size: 12px;
color: var(--vp-c-text-2);
text-decoration: none;
transition: color 0.2s ease;
}

.support-link:hover {
color: var(--vp-c-brand-1);
color: var(--vp-c-text-1);
}

.support-icon {
flex-shrink: 0;
color: v-bind('supportMessage.color');
}

.link-text {
text-decoration: underline;
text-decoration-color: var(--vp-c-text-3);
transition: text-decoration-color 0.3s ease;
transition: text-decoration-color 0.2s ease;
}

.support-link:hover .link-text {
text-decoration-color: var(--vp-c-brand-1);
}

@media (max-width: 768px) {
.support-notice {
padding: 16px;
}

.support-message {
max-width: 100%;
}
text-decoration-color: var(--vp-c-text-1);
}
</style>
1 change: 1 addition & 0 deletions website/client/components/Home/TryIt.vue
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@
:error="error"
:error-type="errorType"
:repository-url="inputRepositoryUrl"
:pack-options="packOptions"
@repack="handleRepack"
/>
</div>
Expand Down
5 changes: 4 additions & 1 deletion website/client/components/Home/TryItResult.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<script setup lang="ts">
import { computed, ref } from 'vue';
import type { PackOptions } from '../../composables/usePackOptions';
import type { TabType } from '../../types/ui';
import type { FileInfo, PackResult } from '../api/client';
import SupportMessage from './SupportMessage.vue';
Expand All @@ -14,6 +15,7 @@ interface Props {
error?: string | null;
errorType?: 'error' | 'warning';
repositoryUrl?: string;
packOptions?: PackOptions;
}

interface Emits {
Expand Down Expand Up @@ -57,6 +59,7 @@ const handleRepack = (selectedFiles: FileInfo[]) => {
:message="error"
:error-type="errorType"
:repository-url="repositoryUrl"
:pack-options="packOptions"
/>
<div v-else-if="result" class="result-content">
<!-- Tab Navigation -->
Expand All @@ -81,7 +84,7 @@ const handleRepack = (selectedFiles: FileInfo[]) => {

<!-- Tab Content -->
<div v-show="activeTab === 'result' || !hasFileSelection">
<TryItResultContent :result="result" />
<TryItResultContent :result="result" :pack-options="packOptions" />
</div>
<div v-show="activeTab === 'files' && hasFileSelection">
<TryItFileSelection
Expand Down
Loading
Loading