ui(deploy): add deriveAppName pure function + tests

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-04-22 22:46:52 +02:00
parent 52ff385b04
commit d067490f71
2 changed files with 78 additions and 0 deletions

View File

@@ -0,0 +1,40 @@
import { describe, it, expect } from 'vitest';
import { deriveAppName } from './deriveAppName';
describe('deriveAppName', () => {
it('truncates at first digit', () => {
expect(deriveAppName('payment-gateway-1.2.0.jar')).toBe('Payment Gateway');
});
it('returns clean title-cased name without digits', () => {
expect(deriveAppName('order-service.jar')).toBe('Order Service');
});
it('strips orphan 1-char token after truncation (v from my-app-v2)', () => {
expect(deriveAppName('my-app-v2.jar')).toBe('My App');
});
it('treats underscore like dash', () => {
expect(deriveAppName('acme_billing-3.jar')).toBe('Acme Billing');
});
it('strips the .jar extension when no digits present', () => {
expect(deriveAppName('acme-billing.jar')).toBe('Acme Billing');
});
it('returns empty string for empty input', () => {
expect(deriveAppName('')).toBe('');
});
it('returns empty string when filename starts with a digit', () => {
expect(deriveAppName('1-my-thing.jar')).toBe('');
});
it('mixed separators are both collapsed to spaces', () => {
expect(deriveAppName('foo_bar-baz.jar')).toBe('Foo Bar Baz');
});
it('strips trailing orphan regardless of letter identity', () => {
expect(deriveAppName('release-x9.jar')).toBe('Release');
});
});

View File

@@ -0,0 +1,38 @@
/**
* Derive a human-readable app name from a JAR filename.
*
* Rule:
* 1. Strip the `.jar` extension.
* 2. Truncate at the first digit (0-9) or `.`.
* 3. Replace `-` and `_` with spaces.
* 4. Collapse multiple spaces and trim.
* 5. Drop 1-char orphan tokens (e.g. the trailing `v` in `my-app-v2`).
* 6. Title-case each remaining word.
*
* The result is a suggestion — the caller is expected to let the user override.
*/
export function deriveAppName(filename: string): string {
if (!filename) return '';
let stem = filename.replace(/\.jar$/i, '');
// Truncate at first digit or dot
const match = stem.match(/[0-9.]/);
if (match && match.index !== undefined) {
stem = stem.slice(0, match.index);
}
// Separators → space
stem = stem.replace(/[-_]+/g, ' ');
// Collapse whitespace + trim
stem = stem.replace(/\s+/g, ' ').trim();
if (!stem) return '';
// Drop 1-char orphan tokens
const tokens = stem.split(' ').filter((t) => t.length > 1);
if (tokens.length === 0) return '';
// Title-case
return tokens.map((t) => t.charAt(0).toUpperCase() + t.slice(1).toLowerCase()).join(' ');
}