feat: Introduce fe modular build system

This commit is contained in:
divocat
2025-10-02 21:40:16 +03:00
parent 4ef15f7340
commit 294cb21e91
21 changed files with 2294 additions and 17 deletions

View File

@@ -0,0 +1,24 @@
import { describe, expect, it } from 'vitest';
import { validateDNS } from '../validateDns.js';
import { invalidIPs, validIPs } from './validateIp.test';
import { invalidDomains, validDomains } from './validateDomain.test';
const validDns = [...validIPs, ...validDomains];
const invalidDns = [...invalidIPs, ...invalidDomains];
describe('validateDns', () => {
describe.each(validDns)('Valid dns: %s', (_desc, domain) => {
it(`returns valid=true for "${domain}"`, () => {
const res = validateDNS(domain);
expect(res.valid).toBe(true);
});
});
describe.each(invalidDns)('Invalid dns: %s', (_desc, domain) => {
it(`returns valid=false for "${domain}"`, () => {
const res = validateDNS(domain);
expect(res.valid).toBe(false);
});
});
});

View File

@@ -0,0 +1,46 @@
import { describe, expect, it } from 'vitest';
import { validateDomain } from '../validateDomain';
export const validDomains = [
['Simple domain', 'example.com'],
['Subdomain', 'sub.example.com'],
['With dash', 'my-site.org'],
['With numbers', 'site123.net'],
['Deep subdomain', 'a.b.c.example.co.uk'],
['With path', 'example.com/path/to/resource'],
['Punycode RU', 'xn--d1acufc.xn--p1ai'],
['Adguard dns', 'dns.adguard-dns.com'],
['Nextdns dns', 'dns.nextdns.io/xxxxxxx'],
['Long domain (63 chars in label)', 'a'.repeat(63) + '.com'],
];
export const invalidDomains = [
['No TLD', 'localhost'],
['Only TLD', '.com'],
['Double dot', 'example..com'],
['Illegal chars', 'exa!mple.com'],
['Space inside', 'exa mple.com'],
['Ending with dash', 'example-.com'],
['Starting with dash', '-example.com'],
['Trailing dot', 'example.com.'],
['Too short TLD', 'example.c'],
['With protocol (not allowed)', 'http://example.com'],
['Too long label (>63 chars)', 'a'.repeat(64) + '.com'],
['Too long domain (>253 chars)', Array(40).fill('abcdef').join('.') + '.com'],
];
describe('validateDomain', () => {
describe.each(validDomains)('Valid domain: %s', (_desc, domain) => {
it(`returns valid=true for "${domain}"`, () => {
const res = validateDomain(domain);
expect(res.valid).toBe(true);
});
});
describe.each(invalidDomains)('Invalid domain: %s', (_desc, domain) => {
it(`returns valid=false for "${domain}"`, () => {
const res = validateDomain(domain);
expect(res.valid).toBe(false);
});
});
});

View File

@@ -0,0 +1,38 @@
import { describe, it, expect } from 'vitest';
import { validateIPV4 } from '../validateIp';
export const validIPs = [
['Private LAN', '192.168.1.1'],
['All zeros', '0.0.0.0'],
['Broadcast', '255.255.255.255'],
['Simple', '1.2.3.4'],
['Loopback', '127.0.0.1'],
];
export const invalidIPs = [
['Octet too large', '256.0.0.1'],
['Too few octets', '192.168.1'],
['Too many octets', '1.2.3.4.5'],
['Leading zero (1st octet)', '01.2.3.4'],
['Leading zero (2nd octet)', '1.02.3.4'],
['Leading zero (3rd octet)', '1.2.003.4'],
['Leading zero (4th octet)', '1.2.3.004'],
['Four digits in octet', '1.2.3.0004'],
['Trailing dot', '1.2.3.'],
];
describe('validateIPV4', () => {
describe.each(validIPs)('Valid IP: %s', (_desc, ip) => {
it(`returns {valid:true for "${ip}"`, () => {
const res = validateIPV4(ip);
expect(res.valid).toBe(true);
});
});
describe.each(invalidIPs)('Invalid IP: %s', (_desc, ip) => {
it(`returns {valid:false for "${ip}"`, () => {
const res = validateIPV4(ip);
expect(res.valid).toBe(false);
});
});
});

View File

@@ -0,0 +1,40 @@
import { describe, it, expect } from 'vitest';
import { validateUrl } from '../validateUrl';
const validUrls = [
['Simple HTTP', 'http://example.com'],
['Simple HTTPS', 'https://example.com'],
['With path', 'https://example.com/path/to/page'],
['With query', 'https://example.com/?q=test'],
['With port', 'http://example.com:8080'],
['With subdomain', 'https://sub.example.com'],
];
const invalidUrls = [
['Invalid format', 'not a url'],
['Missing protocol', 'example.com'],
['Unsupported protocol (ftp)', 'ftp://example.com'],
['Unsupported protocol (ws)', 'ws://example.com'],
['Empty string', ''],
];
describe('validateUrl', () => {
describe.each(validUrls)('Valid URL: %s', (_desc, url) => {
it(`returns valid=true for "${url}"`, () => {
const res = validateUrl(url);
expect(res.valid).toBe(true);
});
});
describe.each(invalidUrls)('Invalid URL: %s', (_desc, url) => {
it(`returns valid=false for "${url}"`, () => {
const res = validateUrl(url);
expect(res.valid).toBe(false);
});
});
it('allows custom protocol list (ftp)', () => {
const res = validateUrl('ftp://example.com', ['ftp:']);
expect(res.valid).toBe(true);
});
});