stringzy 4.1.0 → 4.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/auto-assign.yml +26 -0
- package/CODE_OF_CONDUCT.MD +115 -0
- package/README.md +591 -79
- package/dist/analyzing/checkMultiplePatterns.d.ts +2 -2
- package/dist/analyzing/checkMultiplePatterns.js +43 -31
- package/dist/analyzing/index.d.ts +3 -0
- package/dist/analyzing/index.js +6 -2
- package/dist/analyzing/lexicographicalRank.d.ts +26 -0
- package/dist/analyzing/lexicographicalRank.js +66 -0
- package/dist/formatting/binary.d.ts +24 -0
- package/dist/formatting/binary.js +49 -0
- package/dist/formatting/creditCard.d.ts +8 -0
- package/dist/formatting/creditCard.js +28 -0
- package/dist/formatting/decimal.d.ts +21 -0
- package/dist/formatting/decimal.js +73 -0
- package/dist/formatting/duration.d.ts +27 -0
- package/dist/formatting/duration.js +92 -0
- package/dist/formatting/fileSize.d.ts +18 -0
- package/dist/formatting/fileSize.js +39 -0
- package/dist/formatting/hexadecimal.d.ts +14 -0
- package/dist/formatting/hexadecimal.js +38 -0
- package/dist/formatting/index.d.ts +42 -0
- package/dist/formatting/index.js +57 -1
- package/dist/formatting/listToString.d.ts +17 -0
- package/dist/formatting/listToString.js +35 -0
- package/dist/formatting/octal.d.ts +19 -0
- package/dist/formatting/octal.js +31 -0
- package/dist/formatting/ordinal.d.ts +20 -0
- package/dist/formatting/ordinal.js +43 -0
- package/dist/formatting/percentage.d.ts +19 -0
- package/dist/formatting/percentage.js +31 -0
- package/dist/formatting/romanNumerals.d.ts +20 -0
- package/dist/formatting/romanNumerals.js +53 -0
- package/dist/formatting/scientific.d.ts +14 -0
- package/dist/formatting/scientific.js +24 -0
- package/dist/formatting/temperature.d.ts +6 -0
- package/dist/formatting/temperature.js +27 -0
- package/dist/formatting/trim.d.ts +10 -0
- package/dist/formatting/trim.js +20 -0
- package/dist/index.d.ts +17 -0
- package/dist/tests/analyzing/lexicographicalRank.test.d.ts +1 -0
- package/dist/tests/analyzing/lexicographicalRank.test.js +43 -0
- package/dist/tests/formatting/binary.test.d.ts +1 -0
- package/dist/tests/formatting/binary.test.js +53 -0
- package/dist/tests/formatting/creditCard.test.d.ts +1 -0
- package/dist/tests/formatting/creditCard.test.js +31 -0
- package/dist/tests/formatting/decimal.test.d.ts +1 -0
- package/dist/tests/formatting/decimal.test.js +62 -0
- package/dist/tests/formatting/duration.test.d.ts +1 -0
- package/dist/tests/formatting/duration.test.js +61 -0
- package/dist/tests/formatting/fileSize.test.d.ts +1 -0
- package/dist/tests/formatting/fileSize.test.js +39 -0
- package/dist/tests/formatting/hexadecimal.test.d.ts +1 -0
- package/dist/tests/formatting/hexadecimal.test.js +38 -0
- package/dist/tests/formatting/listToString.test.d.ts +1 -0
- package/dist/tests/formatting/listToString.test.js +37 -0
- package/dist/tests/formatting/octal.test.d.ts +1 -0
- package/dist/tests/formatting/octal.test.js +36 -0
- package/dist/tests/formatting/ordinal.test.d.ts +1 -0
- package/dist/tests/formatting/ordinal.test.js +37 -0
- package/dist/tests/formatting/percentage.test.d.ts +1 -0
- package/dist/tests/formatting/percentage.test.js +38 -0
- package/dist/tests/formatting/romanNumerals.test.d.ts +1 -0
- package/dist/tests/formatting/romanNumerals.test.js +35 -0
- package/dist/tests/formatting/scientific.test.d.ts +1 -0
- package/dist/tests/formatting/scientific.test.js +35 -0
- package/dist/tests/formatting/temperature.test.d.ts +1 -0
- package/dist/tests/formatting/temperature.test.js +34 -0
- package/dist/tests/formatting/trim.test.d.ts +1 -0
- package/dist/tests/formatting/trim.test.js +42 -0
- package/dist/tests/transformations/stringPermutations.test.js +70 -0
- package/dist/tests/validations/isIPv6.test.d.ts +1 -0
- package/dist/tests/validations/isIPv6.test.js +65 -0
- package/dist/transformations/index.d.ts +3 -2
- package/dist/transformations/index.js +3 -1
- package/dist/transformations/stringPermutations.d.ts +23 -1
- package/dist/transformations/stringPermutations.js +127 -1
- package/dist/validations/index.d.ts +3 -0
- package/dist/validations/index.js +5 -1
- package/dist/validations/isIPv6.d.ts +24 -0
- package/dist/validations/isIPv6.js +45 -0
- package/package.json +1 -1
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const node_test_1 = require("node:test");
|
|
7
|
+
const node_assert_1 = __importDefault(require("node:assert"));
|
|
8
|
+
const temperature_1 = require("../../formatting/temperature");
|
|
9
|
+
(0, node_test_1.describe)('formatTemperature', () => {
|
|
10
|
+
(0, node_test_1.it)('should convert Celsius to Fahrenheit', () => {
|
|
11
|
+
node_assert_1.default.strictEqual((0, temperature_1.formatTemperature)(0, { from: 'C', to: 'F' }), '32.00°F');
|
|
12
|
+
});
|
|
13
|
+
(0, node_test_1.it)('should convert Celsius to Kelvin', () => {
|
|
14
|
+
node_assert_1.default.strictEqual((0, temperature_1.formatTemperature)(100, { from: 'C', to: 'K' }), '373.15K');
|
|
15
|
+
});
|
|
16
|
+
(0, node_test_1.it)('should convert Fahrenheit to Celsius', () => {
|
|
17
|
+
node_assert_1.default.strictEqual((0, temperature_1.formatTemperature)(32, { from: 'F', to: 'C' }), '0.00°C');
|
|
18
|
+
});
|
|
19
|
+
(0, node_test_1.it)('should convert Fahrenheit to Kelvin', () => {
|
|
20
|
+
node_assert_1.default.strictEqual((0, temperature_1.formatTemperature)(212, { from: 'F', to: 'K' }), '373.15K');
|
|
21
|
+
});
|
|
22
|
+
(0, node_test_1.it)('should convert Kelvin to Celsius', () => {
|
|
23
|
+
node_assert_1.default.strictEqual((0, temperature_1.formatTemperature)(300, { from: 'K', to: 'C' }), '26.85°C');
|
|
24
|
+
});
|
|
25
|
+
(0, node_test_1.it)('should handle precision settings', () => {
|
|
26
|
+
node_assert_1.default.strictEqual((0, temperature_1.formatTemperature)(100, { from: 'C', to: 'K', precision: 0 }), '373K');
|
|
27
|
+
});
|
|
28
|
+
(0, node_test_1.it)('should throw error for invalid conversions', () => {
|
|
29
|
+
node_assert_1.default.throws(() => (0, temperature_1.formatTemperature)(100, { from: 'C', to: 'X' }), /Invalid conversion from C to X./);
|
|
30
|
+
});
|
|
31
|
+
(0, node_test_1.it)('should throw error for non-numeric value', () => {
|
|
32
|
+
node_assert_1.default.throws(() => (0, temperature_1.formatTemperature)(NaN, { from: 'C', to: 'K' }), /Invalid temperature value./);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const node_test_1 = require("node:test");
|
|
7
|
+
const node_assert_1 = __importDefault(require("node:assert"));
|
|
8
|
+
// NOTE: Adjust this import path to match your project structure
|
|
9
|
+
const trim_1 = require("../../formatting/trim");
|
|
10
|
+
(0, node_test_1.describe)('trim', () => {
|
|
11
|
+
(0, node_test_1.it)('removes simple leading and trailing spaces', () => {
|
|
12
|
+
node_assert_1.default.strictEqual((0, trim_1.trim)(' hello world '), 'hello world');
|
|
13
|
+
node_assert_1.default.strictEqual((0, trim_1.trim)(' leading'), 'leading');
|
|
14
|
+
node_assert_1.default.strictEqual((0, trim_1.trim)('trailing '), 'trailing');
|
|
15
|
+
});
|
|
16
|
+
(0, node_test_1.it)('collapses multiple spaces between words into one', () => {
|
|
17
|
+
node_assert_1.default.strictEqual((0, trim_1.trim)('multiple spaces'), 'multiple spaces');
|
|
18
|
+
node_assert_1.default.strictEqual((0, trim_1.trim)('one two three four'), 'one two three four');
|
|
19
|
+
});
|
|
20
|
+
(0, node_test_1.it)('handles tabs and line breaks as whitespace', () => {
|
|
21
|
+
node_assert_1.default.strictEqual((0, trim_1.trim)('line \n breaks\tand tabs'), 'line breaks and tabs');
|
|
22
|
+
node_assert_1.default.strictEqual((0, trim_1.trim)('tabs\tbetween\twords'), 'tabs between words');
|
|
23
|
+
node_assert_1.default.strictEqual((0, trim_1.trim)('new\nlines\n\nand\r\nwindows'), 'new lines and windows');
|
|
24
|
+
});
|
|
25
|
+
(0, node_test_1.it)('handles a complex mix of all whitespace types', () => {
|
|
26
|
+
const input = ' \n \t hello \n\n world \t ! ';
|
|
27
|
+
const expected = 'hello world !';
|
|
28
|
+
node_assert_1.default.strictEqual((0, trim_1.trim)(input), expected);
|
|
29
|
+
});
|
|
30
|
+
(0, node_test_1.it)('handles edge cases: empty and whitespace-only strings', () => {
|
|
31
|
+
node_assert_1.default.strictEqual((0, trim_1.trim)(''), '');
|
|
32
|
+
node_assert_1.default.strictEqual((0, trim_1.trim)(' '), '');
|
|
33
|
+
node_assert_1.default.strictEqual((0, trim_1.trim)(' \n \t \r\n '), '');
|
|
34
|
+
});
|
|
35
|
+
(0, node_test_1.it)('throws an error if input is not a string', () => {
|
|
36
|
+
node_assert_1.default.throws(() => (0, trim_1.trim)(123), /Input must be a string/);
|
|
37
|
+
node_assert_1.default.throws(() => (0, trim_1.trim)(null), /Input must be a string/);
|
|
38
|
+
node_assert_1.default.throws(() => (0, trim_1.trim)(undefined), /Input must be a string/);
|
|
39
|
+
node_assert_1.default.throws(() => (0, trim_1.trim)({}), /Input must be a string/);
|
|
40
|
+
node_assert_1.default.throws(() => (0, trim_1.trim)([]), /Input must be a string/);
|
|
41
|
+
});
|
|
42
|
+
});
|
|
@@ -37,4 +37,74 @@ const stringPermutations_1 = require("../../transformations/stringPermutations")
|
|
|
37
37
|
node_assert_1.default.throws(() => (0, stringPermutations_1.stringPermutations)(null), /Input must be a string/);
|
|
38
38
|
node_assert_1.default.throws(() => (0, stringPermutations_1.stringPermutations)(undefined), /Input must be a string/);
|
|
39
39
|
});
|
|
40
|
+
(0, node_test_1.it)('respects limit parameter', () => {
|
|
41
|
+
const result = (0, stringPermutations_1.stringPermutations)('abcdef', 3);
|
|
42
|
+
node_assert_1.default.strictEqual(result.length, 3);
|
|
43
|
+
// All results should be valid permutations
|
|
44
|
+
for (const perm of result) {
|
|
45
|
+
node_assert_1.default.strictEqual(perm.length, 6);
|
|
46
|
+
node_assert_1.default.strictEqual([...perm].sort().join(''), 'abcdef');
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
(0, node_test_1.it)('throws error for negative limit', () => {
|
|
50
|
+
node_assert_1.default.throws(() => (0, stringPermutations_1.stringPermutations)('abc', -1), /Limit must be non-negative/);
|
|
51
|
+
});
|
|
52
|
+
(0, node_test_1.it)('handles limit of 0', () => {
|
|
53
|
+
const result = (0, stringPermutations_1.stringPermutations)('abc', 0);
|
|
54
|
+
node_assert_1.default.strictEqual(result.length, 0);
|
|
55
|
+
});
|
|
56
|
+
(0, node_test_1.it)('handles limit larger than total permutations', () => {
|
|
57
|
+
const result = (0, stringPermutations_1.stringPermutations)('abc', 100);
|
|
58
|
+
node_assert_1.default.strictEqual(result.length, 6); // 3! = 6
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
(0, node_test_1.describe)('stringPermutationsGenerator', () => {
|
|
62
|
+
(0, node_test_1.it)('yields correct permutations for small strings', () => {
|
|
63
|
+
const result = Array.from((0, stringPermutations_1.stringPermutationsGenerator)('ab')).sort();
|
|
64
|
+
node_assert_1.default.deepStrictEqual(result, ['ab', 'ba']);
|
|
65
|
+
});
|
|
66
|
+
(0, node_test_1.it)('yields all permutations for 3 unique characters', () => {
|
|
67
|
+
const result = Array.from((0, stringPermutations_1.stringPermutationsGenerator)('abc')).sort();
|
|
68
|
+
const expected = ['abc', 'acb', 'bac', 'bca', 'cab', 'cba'];
|
|
69
|
+
node_assert_1.default.deepStrictEqual(result, expected);
|
|
70
|
+
});
|
|
71
|
+
(0, node_test_1.it)('handles repeated characters correctly', () => {
|
|
72
|
+
const result = Array.from((0, stringPermutations_1.stringPermutationsGenerator)('aab')).sort();
|
|
73
|
+
const expected = ['aab', 'aba', 'baa'];
|
|
74
|
+
node_assert_1.default.deepStrictEqual(result, expected);
|
|
75
|
+
});
|
|
76
|
+
(0, node_test_1.it)('handles single character input', () => {
|
|
77
|
+
const result = Array.from((0, stringPermutations_1.stringPermutationsGenerator)('a'));
|
|
78
|
+
node_assert_1.default.deepStrictEqual(result, ['a']);
|
|
79
|
+
});
|
|
80
|
+
(0, node_test_1.it)('handles empty string input', () => {
|
|
81
|
+
const result = Array.from((0, stringPermutations_1.stringPermutationsGenerator)(''));
|
|
82
|
+
node_assert_1.default.deepStrictEqual(result, ['']);
|
|
83
|
+
});
|
|
84
|
+
(0, node_test_1.it)('is case-sensitive', () => {
|
|
85
|
+
const result = Array.from((0, stringPermutations_1.stringPermutationsGenerator)('Ab')).sort();
|
|
86
|
+
const expected = ['Ab', 'bA'];
|
|
87
|
+
node_assert_1.default.deepStrictEqual(result, expected);
|
|
88
|
+
});
|
|
89
|
+
(0, node_test_1.it)('handles special characters', () => {
|
|
90
|
+
const result = Array.from((0, stringPermutations_1.stringPermutationsGenerator)('!@')).sort();
|
|
91
|
+
const expected = ['!@', '@!'];
|
|
92
|
+
node_assert_1.default.deepStrictEqual(result, expected);
|
|
93
|
+
});
|
|
94
|
+
(0, node_test_1.it)('throws an error if input is not a string', () => {
|
|
95
|
+
// Generator functions throw when first consumed, not when created
|
|
96
|
+
const gen1 = (0, stringPermutations_1.stringPermutationsGenerator)(123);
|
|
97
|
+
node_assert_1.default.throws(() => gen1.next(), /Input must be a string/);
|
|
98
|
+
const gen2 = (0, stringPermutations_1.stringPermutationsGenerator)(null);
|
|
99
|
+
node_assert_1.default.throws(() => gen2.next(), /Input must be a string/);
|
|
100
|
+
const gen3 = (0, stringPermutations_1.stringPermutationsGenerator)(undefined);
|
|
101
|
+
node_assert_1.default.throws(() => gen3.next(), /Input must be a string/);
|
|
102
|
+
});
|
|
103
|
+
(0, node_test_1.it)('can be used with for...of loop', () => {
|
|
104
|
+
const results = [];
|
|
105
|
+
for (const perm of (0, stringPermutations_1.stringPermutationsGenerator)('abc')) {
|
|
106
|
+
results.push(perm);
|
|
107
|
+
}
|
|
108
|
+
node_assert_1.default.strictEqual(results.length, 6);
|
|
109
|
+
});
|
|
40
110
|
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const node_test_1 = require("node:test");
|
|
7
|
+
const node_assert_1 = __importDefault(require("node:assert"));
|
|
8
|
+
const isIPv6_1 = require("../../validations/isIPv6");
|
|
9
|
+
(0, node_test_1.describe)('isIPv6', () => {
|
|
10
|
+
(0, node_test_1.it)('returns true for valid full IPv6 addresses', () => {
|
|
11
|
+
node_assert_1.default.strictEqual((0, isIPv6_1.isIPv6)('2001:0db8:85a3:0000:0000:8a2e:0370:7334'), true);
|
|
12
|
+
node_assert_1.default.strictEqual((0, isIPv6_1.isIPv6)('ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff'), true);
|
|
13
|
+
node_assert_1.default.strictEqual((0, isIPv6_1.isIPv6)('0:0:0:0:0:0:0:1'), true);
|
|
14
|
+
node_assert_1.default.strictEqual((0, isIPv6_1.isIPv6)('fe80:0000:0000:0000:0202:b3ff:fe1e:8329'), true);
|
|
15
|
+
});
|
|
16
|
+
(0, node_test_1.it)('returns true for valid shorthand IPv6 addresses', () => {
|
|
17
|
+
node_assert_1.default.strictEqual((0, isIPv6_1.isIPv6)('2001:db8:85a3::8a2e:370:7334'), true);
|
|
18
|
+
node_assert_1.default.strictEqual((0, isIPv6_1.isIPv6)('::1'), true);
|
|
19
|
+
node_assert_1.default.strictEqual((0, isIPv6_1.isIPv6)('fe80::1'), true);
|
|
20
|
+
node_assert_1.default.strictEqual((0, isIPv6_1.isIPv6)('::'), true);
|
|
21
|
+
});
|
|
22
|
+
(0, node_test_1.it)('returns false for IPv6 addresses with too many groups', () => {
|
|
23
|
+
node_assert_1.default.strictEqual((0, isIPv6_1.isIPv6)('2001:0db8:85a3:0000:0000:8a2e:0370:7334:1234'), false);
|
|
24
|
+
node_assert_1.default.strictEqual((0, isIPv6_1.isIPv6)('1:2:3:4:5:6:7:8:9'), false);
|
|
25
|
+
});
|
|
26
|
+
(0, node_test_1.it)('returns false for IPv6 addresses with too few groups without shorthand', () => {
|
|
27
|
+
node_assert_1.default.strictEqual((0, isIPv6_1.isIPv6)('2001:db8:85a3:8a2e:370:7334'), false);
|
|
28
|
+
node_assert_1.default.strictEqual((0, isIPv6_1.isIPv6)('1:2:3:4:5:6:7'), false);
|
|
29
|
+
});
|
|
30
|
+
(0, node_test_1.it)('returns false for invalid use of shorthand (::)', () => {
|
|
31
|
+
node_assert_1.default.strictEqual((0, isIPv6_1.isIPv6)('2001:db8:::1'), false);
|
|
32
|
+
node_assert_1.default.strictEqual((0, isIPv6_1.isIPv6)(':::1'), false);
|
|
33
|
+
node_assert_1.default.strictEqual((0, isIPv6_1.isIPv6)('2001::85a3::7334'), false);
|
|
34
|
+
});
|
|
35
|
+
(0, node_test_1.it)('returns false for groups longer than 4 hex digits', () => {
|
|
36
|
+
node_assert_1.default.strictEqual((0, isIPv6_1.isIPv6)('12345::abcd'), false);
|
|
37
|
+
node_assert_1.default.strictEqual((0, isIPv6_1.isIPv6)('2001:db8:85a3:00000:0000:8a2e:0370:7334'), false);
|
|
38
|
+
});
|
|
39
|
+
(0, node_test_1.it)('returns false for invalid characters', () => {
|
|
40
|
+
node_assert_1.default.strictEqual((0, isIPv6_1.isIPv6)('2001:db8:85a3:z000:0000:8a2e:0370:7334'), false);
|
|
41
|
+
node_assert_1.default.strictEqual((0, isIPv6_1.isIPv6)('2001:db8:85a3:0000:0000:8a2e:0370:g334'), false);
|
|
42
|
+
node_assert_1.default.strictEqual((0, isIPv6_1.isIPv6)('abcd:efgh:ijkl:mnop:qrst:uvwx:yz12:3456'), false);
|
|
43
|
+
});
|
|
44
|
+
(0, node_test_1.it)('returns false for special characters and malformed strings', () => {
|
|
45
|
+
node_assert_1.default.strictEqual((0, isIPv6_1.isIPv6)('2001:db8:85a3:0000:0000:8a2e:0370:7334:'), false);
|
|
46
|
+
node_assert_1.default.strictEqual((0, isIPv6_1.isIPv6)(':2001:db8:85a3:0000:0000:8a2e:0370:7334'), false);
|
|
47
|
+
node_assert_1.default.strictEqual((0, isIPv6_1.isIPv6)('2001:db8::85a3::7334'), false);
|
|
48
|
+
node_assert_1.default.strictEqual((0, isIPv6_1.isIPv6)('2001:db8::85a3:7334:'), false);
|
|
49
|
+
});
|
|
50
|
+
(0, node_test_1.it)('returns false for empty strings and edge cases', () => {
|
|
51
|
+
node_assert_1.default.strictEqual((0, isIPv6_1.isIPv6)(''), false);
|
|
52
|
+
node_assert_1.default.strictEqual((0, isIPv6_1.isIPv6)(':'), false);
|
|
53
|
+
node_assert_1.default.strictEqual((0, isIPv6_1.isIPv6)(':::'), false);
|
|
54
|
+
node_assert_1.default.strictEqual((0, isIPv6_1.isIPv6)('::::'), false);
|
|
55
|
+
});
|
|
56
|
+
(0, node_test_1.it)('returns true for uppercase valid IPv6 addresses (case-insensitive)', () => {
|
|
57
|
+
node_assert_1.default.strictEqual((0, isIPv6_1.isIPv6)('2001:DB8:85A3::8A2E:370:7334'), true);
|
|
58
|
+
node_assert_1.default.strictEqual((0, isIPv6_1.isIPv6)('FE80::1'), true);
|
|
59
|
+
node_assert_1.default.strictEqual((0, isIPv6_1.isIPv6)('FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF'), true);
|
|
60
|
+
});
|
|
61
|
+
(0, node_test_1.it)('returns false for IPv4-mapped IPv6 (unsupported by this validator)', () => {
|
|
62
|
+
node_assert_1.default.strictEqual((0, isIPv6_1.isIPv6)('::ffff:192.168.1.1'), false);
|
|
63
|
+
node_assert_1.default.strictEqual((0, isIPv6_1.isIPv6)('2001:db8::192.168.1.1'), false);
|
|
64
|
+
});
|
|
65
|
+
});
|
|
@@ -15,7 +15,7 @@ export { escapeHtml } from './escapeHTML';
|
|
|
15
15
|
export { maskSegment } from './maskSegment';
|
|
16
16
|
export { numberToText } from './numberToText/main';
|
|
17
17
|
export { reverseWordsInString } from './reverseWordsInString ';
|
|
18
|
-
export { stringPermutations } from './stringPermutations';
|
|
18
|
+
export { stringPermutations, stringPermutationsGenerator } from './stringPermutations';
|
|
19
19
|
export { stringCombinations } from './stringCombinations';
|
|
20
20
|
import { camelCase } from './camelCase';
|
|
21
21
|
import { capitalizeWords } from './capitalizeWords';
|
|
@@ -35,7 +35,7 @@ import { maskSegment } from './maskSegment';
|
|
|
35
35
|
import { deburr } from './deburr';
|
|
36
36
|
import { numberToText } from './numberToText/main';
|
|
37
37
|
import { reverseWordsInString } from './reverseWordsInString ';
|
|
38
|
-
import { stringPermutations } from './stringPermutations';
|
|
38
|
+
import { stringPermutations, stringPermutationsGenerator } from './stringPermutations';
|
|
39
39
|
import { stringCombinations } from './stringCombinations';
|
|
40
40
|
export declare const transformations: {
|
|
41
41
|
camelCase: typeof camelCase;
|
|
@@ -57,5 +57,6 @@ export declare const transformations: {
|
|
|
57
57
|
numberToText: typeof numberToText;
|
|
58
58
|
reverseWordsInString: typeof reverseWordsInString;
|
|
59
59
|
stringPermutations: typeof stringPermutations;
|
|
60
|
+
stringPermutationsGenerator: typeof stringPermutationsGenerator;
|
|
60
61
|
stringCombinations: typeof stringCombinations;
|
|
61
62
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.transformations = exports.stringCombinations = exports.stringPermutations = exports.reverseWordsInString = exports.numberToText = exports.maskSegment = exports.escapeHtml = exports.truncateText = exports.toSlug = exports.titleCase = exports.snakeCase = exports.removeWords = exports.removeSpecialChars = exports.removeDuplicates = exports.pascalCase = exports.kebabCase = exports.initials = exports.constantCase = exports.capitalizeWords = exports.camelCase = void 0;
|
|
3
|
+
exports.transformations = exports.stringCombinations = exports.stringPermutationsGenerator = exports.stringPermutations = exports.reverseWordsInString = exports.numberToText = exports.maskSegment = exports.escapeHtml = exports.truncateText = exports.toSlug = exports.titleCase = exports.snakeCase = exports.removeWords = exports.removeSpecialChars = exports.removeDuplicates = exports.pascalCase = exports.kebabCase = exports.initials = exports.constantCase = exports.capitalizeWords = exports.camelCase = void 0;
|
|
4
4
|
var camelCase_1 = require("./camelCase");
|
|
5
5
|
Object.defineProperty(exports, "camelCase", { enumerable: true, get: function () { return camelCase_1.camelCase; } });
|
|
6
6
|
var capitalizeWords_1 = require("./capitalizeWords");
|
|
@@ -37,6 +37,7 @@ var reverseWordsInString_1 = require("./reverseWordsInString ");
|
|
|
37
37
|
Object.defineProperty(exports, "reverseWordsInString", { enumerable: true, get: function () { return reverseWordsInString_1.reverseWordsInString; } });
|
|
38
38
|
var stringPermutations_1 = require("./stringPermutations");
|
|
39
39
|
Object.defineProperty(exports, "stringPermutations", { enumerable: true, get: function () { return stringPermutations_1.stringPermutations; } });
|
|
40
|
+
Object.defineProperty(exports, "stringPermutationsGenerator", { enumerable: true, get: function () { return stringPermutations_1.stringPermutationsGenerator; } });
|
|
40
41
|
var stringCombinations_1 = require("./stringCombinations");
|
|
41
42
|
Object.defineProperty(exports, "stringCombinations", { enumerable: true, get: function () { return stringCombinations_1.stringCombinations; } });
|
|
42
43
|
const camelCase_2 = require("./camelCase");
|
|
@@ -79,5 +80,6 @@ exports.transformations = {
|
|
|
79
80
|
numberToText: main_2.numberToText,
|
|
80
81
|
reverseWordsInString: reverseWordsInString_2.reverseWordsInString,
|
|
81
82
|
stringPermutations: stringPermutations_2.stringPermutations,
|
|
83
|
+
stringPermutationsGenerator: stringPermutations_2.stringPermutationsGenerator,
|
|
82
84
|
stringCombinations: stringCombinations_2.stringCombinations
|
|
83
85
|
};
|
|
@@ -4,9 +4,14 @@
|
|
|
4
4
|
* Handles repeated characters by ensuring only unique permutations
|
|
5
5
|
* are included in the result. The order of permutations is not guaranteed.
|
|
6
6
|
*
|
|
7
|
+
* Performance optimized version using iterative approach and efficient
|
|
8
|
+
* character frequency tracking to avoid duplicate permutations.
|
|
9
|
+
*
|
|
7
10
|
* @param {string} str - The input string to generate permutations for.
|
|
11
|
+
* @param {number} [limit] - Optional limit on number of permutations to generate.
|
|
8
12
|
* @returns {string[]} An array of unique permutations of the input string.
|
|
9
13
|
* @throws {TypeError} If the input is not a string.
|
|
14
|
+
* @throws {RangeError} If limit is negative.
|
|
10
15
|
*
|
|
11
16
|
* @example
|
|
12
17
|
* stringPermutations("ab");
|
|
@@ -21,6 +26,10 @@
|
|
|
21
26
|
* // ["aab", "aba", "baa"]
|
|
22
27
|
*
|
|
23
28
|
* @example
|
|
29
|
+
* stringPermutations("abcdef", 10);
|
|
30
|
+
* // Returns first 10 permutations
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
24
33
|
* stringPermutations("");
|
|
25
34
|
* // [""]
|
|
26
35
|
*
|
|
@@ -28,4 +37,17 @@
|
|
|
28
37
|
* stringPermutations("a");
|
|
29
38
|
* // ["a"]
|
|
30
39
|
*/
|
|
31
|
-
export declare function stringPermutations(str: string): string[];
|
|
40
|
+
export declare function stringPermutations(str: string, limit?: number): string[];
|
|
41
|
+
/**
|
|
42
|
+
* Generator function for permutations - yields permutations one at a time.
|
|
43
|
+
* This is the most memory-efficient approach for very large strings.
|
|
44
|
+
*
|
|
45
|
+
* @param {string} str - The input string to generate permutations for.
|
|
46
|
+
* @yields {string} Each unique permutation.
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* for (const perm of stringPermutationsGenerator("abc")) {
|
|
50
|
+
* console.log(perm);
|
|
51
|
+
* }
|
|
52
|
+
*/
|
|
53
|
+
export declare function stringPermutationsGenerator(str: string): Generator<string, void, unknown>;
|
|
@@ -1,15 +1,21 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.stringPermutations = stringPermutations;
|
|
4
|
+
exports.stringPermutationsGenerator = stringPermutationsGenerator;
|
|
4
5
|
/**
|
|
5
6
|
* Generates all unique permutations of a given string.
|
|
6
7
|
*
|
|
7
8
|
* Handles repeated characters by ensuring only unique permutations
|
|
8
9
|
* are included in the result. The order of permutations is not guaranteed.
|
|
9
10
|
*
|
|
11
|
+
* Performance optimized version using iterative approach and efficient
|
|
12
|
+
* character frequency tracking to avoid duplicate permutations.
|
|
13
|
+
*
|
|
10
14
|
* @param {string} str - The input string to generate permutations for.
|
|
15
|
+
* @param {number} [limit] - Optional limit on number of permutations to generate.
|
|
11
16
|
* @returns {string[]} An array of unique permutations of the input string.
|
|
12
17
|
* @throws {TypeError} If the input is not a string.
|
|
18
|
+
* @throws {RangeError} If limit is negative.
|
|
13
19
|
*
|
|
14
20
|
* @example
|
|
15
21
|
* stringPermutations("ab");
|
|
@@ -24,6 +30,10 @@ exports.stringPermutations = stringPermutations;
|
|
|
24
30
|
* // ["aab", "aba", "baa"]
|
|
25
31
|
*
|
|
26
32
|
* @example
|
|
33
|
+
* stringPermutations("abcdef", 10);
|
|
34
|
+
* // Returns first 10 permutations
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
27
37
|
* stringPermutations("");
|
|
28
38
|
* // [""]
|
|
29
39
|
*
|
|
@@ -31,19 +41,40 @@ exports.stringPermutations = stringPermutations;
|
|
|
31
41
|
* stringPermutations("a");
|
|
32
42
|
* // ["a"]
|
|
33
43
|
*/
|
|
34
|
-
function stringPermutations(str) {
|
|
44
|
+
function stringPermutations(str, limit) {
|
|
35
45
|
if (typeof str !== 'string') {
|
|
36
46
|
throw new TypeError('Input must be a string');
|
|
37
47
|
}
|
|
48
|
+
if (limit !== undefined && limit < 0) {
|
|
49
|
+
throw new RangeError('Limit must be non-negative');
|
|
50
|
+
}
|
|
38
51
|
if (str.length === 0)
|
|
39
52
|
return [''];
|
|
53
|
+
// For small strings, use the original approach for simplicity
|
|
54
|
+
if (str.length <= 6) {
|
|
55
|
+
return generatePermutationsSmall(str, limit);
|
|
56
|
+
}
|
|
57
|
+
// For larger strings, use optimized approach
|
|
58
|
+
return generatePermutationsOptimized(str, limit);
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Generates permutations for small strings (≤6 characters) using recursive approach.
|
|
62
|
+
* This is more memory efficient for small inputs.
|
|
63
|
+
*/
|
|
64
|
+
function generatePermutationsSmall(str, limit) {
|
|
40
65
|
const results = new Set();
|
|
66
|
+
let count = 0;
|
|
41
67
|
const permute = (prefix, remaining) => {
|
|
68
|
+
if (limit !== undefined && count >= limit)
|
|
69
|
+
return;
|
|
42
70
|
if (remaining.length === 0) {
|
|
43
71
|
results.add(prefix);
|
|
72
|
+
count++;
|
|
44
73
|
}
|
|
45
74
|
else {
|
|
46
75
|
for (let i = 0; i < remaining.length; i++) {
|
|
76
|
+
if (limit !== undefined && count >= limit)
|
|
77
|
+
break;
|
|
47
78
|
permute(prefix + remaining[i], remaining.slice(0, i) + remaining.slice(i + 1));
|
|
48
79
|
}
|
|
49
80
|
}
|
|
@@ -51,3 +82,98 @@ function stringPermutations(str) {
|
|
|
51
82
|
permute('', str);
|
|
52
83
|
return Array.from(results);
|
|
53
84
|
}
|
|
85
|
+
/**
|
|
86
|
+
* Generates permutations for larger strings using optimized iterative approach.
|
|
87
|
+
* Uses character frequency tracking to avoid duplicate permutations efficiently.
|
|
88
|
+
*/
|
|
89
|
+
function generatePermutationsOptimized(str, limit) {
|
|
90
|
+
// Count character frequencies
|
|
91
|
+
const charCount = new Map();
|
|
92
|
+
for (const char of str) {
|
|
93
|
+
charCount.set(char, (charCount.get(char) || 0) + 1);
|
|
94
|
+
}
|
|
95
|
+
const results = [];
|
|
96
|
+
const chars = Array.from(charCount.keys());
|
|
97
|
+
const counts = chars.map(char => charCount.get(char));
|
|
98
|
+
// Use iterative approach with stack to avoid recursion
|
|
99
|
+
const stack = [{
|
|
100
|
+
permutation: '',
|
|
101
|
+
remainingCounts: [...counts],
|
|
102
|
+
depth: 0
|
|
103
|
+
}];
|
|
104
|
+
while (stack.length > 0) {
|
|
105
|
+
if (limit !== undefined && results.length >= limit)
|
|
106
|
+
break;
|
|
107
|
+
const current = stack.pop();
|
|
108
|
+
if (current.depth === str.length) {
|
|
109
|
+
results.push(current.permutation);
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
// Generate next level permutations
|
|
113
|
+
for (let i = 0; i < chars.length; i++) {
|
|
114
|
+
if (current.remainingCounts[i] > 0) {
|
|
115
|
+
const newCounts = [...current.remainingCounts];
|
|
116
|
+
newCounts[i]--;
|
|
117
|
+
stack.push({
|
|
118
|
+
permutation: current.permutation + chars[i],
|
|
119
|
+
remainingCounts: newCounts,
|
|
120
|
+
depth: current.depth + 1
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return results;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Generator function for permutations - yields permutations one at a time.
|
|
129
|
+
* This is the most memory-efficient approach for very large strings.
|
|
130
|
+
*
|
|
131
|
+
* @param {string} str - The input string to generate permutations for.
|
|
132
|
+
* @yields {string} Each unique permutation.
|
|
133
|
+
*
|
|
134
|
+
* @example
|
|
135
|
+
* for (const perm of stringPermutationsGenerator("abc")) {
|
|
136
|
+
* console.log(perm);
|
|
137
|
+
* }
|
|
138
|
+
*/
|
|
139
|
+
function* stringPermutationsGenerator(str) {
|
|
140
|
+
if (typeof str !== 'string') {
|
|
141
|
+
throw new TypeError('Input must be a string');
|
|
142
|
+
}
|
|
143
|
+
if (str.length === 0) {
|
|
144
|
+
yield '';
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
// Count character frequencies
|
|
148
|
+
const charCount = new Map();
|
|
149
|
+
for (const char of str) {
|
|
150
|
+
charCount.set(char, (charCount.get(char) || 0) + 1);
|
|
151
|
+
}
|
|
152
|
+
const chars = Array.from(charCount.keys());
|
|
153
|
+
const counts = chars.map(char => charCount.get(char));
|
|
154
|
+
// Use iterative approach with stack
|
|
155
|
+
const stack = [{
|
|
156
|
+
permutation: '',
|
|
157
|
+
remainingCounts: [...counts],
|
|
158
|
+
depth: 0
|
|
159
|
+
}];
|
|
160
|
+
while (stack.length > 0) {
|
|
161
|
+
const current = stack.pop();
|
|
162
|
+
if (current.depth === str.length) {
|
|
163
|
+
yield current.permutation;
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
// Generate next level permutations
|
|
167
|
+
for (let i = 0; i < chars.length; i++) {
|
|
168
|
+
if (current.remainingCounts[i] > 0) {
|
|
169
|
+
const newCounts = [...current.remainingCounts];
|
|
170
|
+
newCounts[i]--;
|
|
171
|
+
stack.push({
|
|
172
|
+
permutation: current.permutation + chars[i],
|
|
173
|
+
remainingCounts: newCounts,
|
|
174
|
+
depth: current.depth + 1
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
@@ -5,6 +5,7 @@ export { isEmpty } from './isEmpty';
|
|
|
5
5
|
export { isSlug } from './isSlug';
|
|
6
6
|
export { isURL } from './isURL';
|
|
7
7
|
export { isIPv4 } from './isIPv4';
|
|
8
|
+
export { isIPv6 } from './isIPv6';
|
|
8
9
|
export { isHexColor } from './isHexColor';
|
|
9
10
|
export { isPalindrome } from './isPalindrome';
|
|
10
11
|
export { isLowerCase } from './isLowerCase';
|
|
@@ -21,6 +22,7 @@ import { isEmpty } from './isEmpty';
|
|
|
21
22
|
import { isSlug } from './isSlug';
|
|
22
23
|
import { isURL } from './isURL';
|
|
23
24
|
import { isIPv4 } from './isIPv4';
|
|
25
|
+
import { isIPv6 } from './isIPv6';
|
|
24
26
|
import { isHexColor } from './isHexColor';
|
|
25
27
|
import { isPalindrome } from './isPalindrome';
|
|
26
28
|
import { isLowerCase } from './isLowerCase';
|
|
@@ -38,6 +40,7 @@ export declare const validations: {
|
|
|
38
40
|
isSlug: typeof isSlug;
|
|
39
41
|
isURL: typeof isURL;
|
|
40
42
|
isIPv4: typeof isIPv4;
|
|
43
|
+
isIPv6: typeof isIPv6;
|
|
41
44
|
isHexColor: typeof isHexColor;
|
|
42
45
|
isPalindrome: typeof isPalindrome;
|
|
43
46
|
isLowerCase: typeof isLowerCase;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.validations = exports.isMacAddress = exports.isPanagram = exports.isAnagram = exports.isAlphaNumeric = exports.isAlphabetic = exports.isUpperCase = exports.isLowerCase = exports.isPalindrome = exports.isHexColor = exports.isIPv4 = exports.isURL = exports.isSlug = exports.isEmpty = exports.isEmail = exports.isDate = exports.isCoordinates = void 0;
|
|
3
|
+
exports.validations = exports.isMacAddress = exports.isPanagram = exports.isAnagram = exports.isAlphaNumeric = exports.isAlphabetic = exports.isUpperCase = exports.isLowerCase = exports.isPalindrome = exports.isHexColor = exports.isIPv6 = exports.isIPv4 = exports.isURL = exports.isSlug = exports.isEmpty = exports.isEmail = exports.isDate = exports.isCoordinates = void 0;
|
|
4
4
|
var isCoordinates_1 = require("./isCoordinates");
|
|
5
5
|
Object.defineProperty(exports, "isCoordinates", { enumerable: true, get: function () { return isCoordinates_1.isCoordinates; } });
|
|
6
6
|
var isDate_1 = require("./isDate");
|
|
@@ -15,6 +15,8 @@ var isURL_1 = require("./isURL");
|
|
|
15
15
|
Object.defineProperty(exports, "isURL", { enumerable: true, get: function () { return isURL_1.isURL; } });
|
|
16
16
|
var isIPv4_1 = require("./isIPv4");
|
|
17
17
|
Object.defineProperty(exports, "isIPv4", { enumerable: true, get: function () { return isIPv4_1.isIPv4; } });
|
|
18
|
+
var isIPv6_1 = require("./isIPv6");
|
|
19
|
+
Object.defineProperty(exports, "isIPv6", { enumerable: true, get: function () { return isIPv6_1.isIPv6; } });
|
|
18
20
|
var isHexColor_1 = require("./isHexColor");
|
|
19
21
|
Object.defineProperty(exports, "isHexColor", { enumerable: true, get: function () { return isHexColor_1.isHexColor; } });
|
|
20
22
|
var isPalindrome_1 = require("./isPalindrome");
|
|
@@ -40,6 +42,7 @@ const isEmpty_2 = require("./isEmpty");
|
|
|
40
42
|
const isSlug_2 = require("./isSlug");
|
|
41
43
|
const isURL_2 = require("./isURL");
|
|
42
44
|
const isIPv4_2 = require("./isIPv4");
|
|
45
|
+
const isIPv6_2 = require("./isIPv6");
|
|
43
46
|
const isHexColor_2 = require("./isHexColor");
|
|
44
47
|
const isPalindrome_2 = require("./isPalindrome");
|
|
45
48
|
const isLowerCase_2 = require("./isLowerCase");
|
|
@@ -57,6 +60,7 @@ exports.validations = {
|
|
|
57
60
|
isSlug: isSlug_2.isSlug,
|
|
58
61
|
isURL: isURL_2.isURL,
|
|
59
62
|
isIPv4: isIPv4_2.isIPv4,
|
|
63
|
+
isIPv6: isIPv6_2.isIPv6,
|
|
60
64
|
isHexColor: isHexColor_2.isHexColor,
|
|
61
65
|
isPalindrome: isPalindrome_2.isPalindrome,
|
|
62
66
|
isLowerCase: isLowerCase_2.isLowerCase,
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checks if a given string is a valid IPv6 address.
|
|
3
|
+
*
|
|
4
|
+
* Valid IPv6 addresses consist of eight groups of four hexadecimal digits (0-9, a-f, A-F)
|
|
5
|
+
* separated by colons (:). Each group can have 1 to 4 hex digits.
|
|
6
|
+
* Leading zeros are allowed. IPv6 addresses can also use the "::" shorthand once
|
|
7
|
+
* to represent one or more groups of zeros.
|
|
8
|
+
*
|
|
9
|
+
* @param {string} str - The string to validate as an IPv6 address.
|
|
10
|
+
* @returns {boolean} `true` if the string is a valid IPv6 address, otherwise `false`.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* isIPv6("2001:0db8:85a3:0000:0000:8a2e:0370:7334"); // true
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* isIPv6("2001:db8:85a3::8a2e:370:7334"); // true (uses shorthand)
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* isIPv6("2001:db8:::1"); // false (invalid use of shorthand)
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* isIPv6("12345::abcd"); // false (group too long)
|
|
23
|
+
*/
|
|
24
|
+
export declare function isIPv6(str: string): boolean;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isIPv6 = isIPv6;
|
|
4
|
+
/**
|
|
5
|
+
* Checks if a given string is a valid IPv6 address.
|
|
6
|
+
*
|
|
7
|
+
* Valid IPv6 addresses consist of eight groups of four hexadecimal digits (0-9, a-f, A-F)
|
|
8
|
+
* separated by colons (:). Each group can have 1 to 4 hex digits.
|
|
9
|
+
* Leading zeros are allowed. IPv6 addresses can also use the "::" shorthand once
|
|
10
|
+
* to represent one or more groups of zeros.
|
|
11
|
+
*
|
|
12
|
+
* @param {string} str - The string to validate as an IPv6 address.
|
|
13
|
+
* @returns {boolean} `true` if the string is a valid IPv6 address, otherwise `false`.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* isIPv6("2001:0db8:85a3:0000:0000:8a2e:0370:7334"); // true
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* isIPv6("2001:db8:85a3::8a2e:370:7334"); // true (uses shorthand)
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* isIPv6("2001:db8:::1"); // false (invalid use of shorthand)
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* isIPv6("12345::abcd"); // false (group too long)
|
|
26
|
+
*/
|
|
27
|
+
function isIPv6(str) {
|
|
28
|
+
const lower = str.toLowerCase();
|
|
29
|
+
if (!/^[0-9a-f:]+$/.test(lower))
|
|
30
|
+
return false;
|
|
31
|
+
const parts = lower.split("::");
|
|
32
|
+
if (parts.length > 2)
|
|
33
|
+
return false;
|
|
34
|
+
const left = parts[0] ? parts[0].split(":") : [];
|
|
35
|
+
const right = parts[1] ? parts[1].split(":") : [];
|
|
36
|
+
// Each part (excluding shorthand) must be 1–4 hex digits
|
|
37
|
+
const validGroup = (g) => /^[0-9a-f]{1,4}$/.test(g);
|
|
38
|
+
if (!left.every(validGroup) || !right.every(validGroup))
|
|
39
|
+
return false;
|
|
40
|
+
const totalGroups = left.length + right.length;
|
|
41
|
+
if (parts.length === 1)
|
|
42
|
+
return totalGroups === 8;
|
|
43
|
+
else
|
|
44
|
+
return totalGroups < 8;
|
|
45
|
+
}
|