Skip to content

Commit 063e28d

Browse files
authored
DelimiterCase / SnakeCase / ScreamingSnakeCase / KebabCase: Fix instantiations containing punctuations (#1080)
1 parent e5382f0 commit 063e28d

File tree

6 files changed

+110
-2
lines changed

6 files changed

+110
-2
lines changed

source/delimiter-case.d.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type {ApplyDefaultOptions} from './internal';
1+
import type {ApplyDefaultOptions, AsciiPunctuation, StartsWith} from './internal';
22
import type {IsStringLiteral} from './is-literal';
33
import type {Merge} from './merge';
44
import type {DefaultWordsOptions, Words, WordsOptions} from './words';
@@ -16,7 +16,9 @@ type DelimiterCaseFromArray<
1616
infer FirstWord extends string,
1717
...infer RemainingWords extends string[],
1818
]
19-
? DelimiterCaseFromArray<RemainingWords, Delimiter, `${OutputString}${Delimiter}${FirstWord}`>
19+
? DelimiterCaseFromArray<RemainingWords, Delimiter, `${OutputString}${
20+
StartsWith<FirstWord, AsciiPunctuation> extends true ? '' : Delimiter
21+
}${FirstWord}`>
2022
: OutputString;
2123

2224
type RemoveFirstLetter<S extends string> = S extends `${infer _}${infer Rest}`

source/internal/characters.d.ts

+34
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,37 @@ export type Whitespace =
3131
| '\u{FEFF}';
3232

3333
export type WordSeparators = '-' | '_' | Whitespace;
34+
35+
export type AsciiPunctuation =
36+
| '!'
37+
| '"'
38+
| '#'
39+
| '$'
40+
| '%'
41+
| '&'
42+
| '\''
43+
| '('
44+
| ')'
45+
| '*'
46+
| '+'
47+
| ','
48+
| '-'
49+
| '.'
50+
| '/'
51+
| ':'
52+
| ';'
53+
| '<'
54+
| '='
55+
| '>'
56+
| '?'
57+
| '@'
58+
| '['
59+
| '\\'
60+
| ']'
61+
| '^'
62+
| '_'
63+
| '`'
64+
| '{'
65+
| '|'
66+
| '}'
67+
| '~';

test-d/delimiter-case.ts

+18
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,24 @@ expectType<'foo#bar' | 'bar#baz' | 'foo$bar' | 'bar$baz'>(unionValueAndDelimiter
112112
const stringPart: DelimiterCase<`foo${string}`, '#'> = 'fooSomeString';
113113
expectType<`foo${string}`>(stringPart);
114114

115+
declare const withPunctuation: DelimiterCase<'onDialog:close', '#'>;
116+
expectType<'on#dialog:close'>(withPunctuation);
117+
118+
declare const withPunctuation2: DelimiterCase<'foo-bar>>baz', '#'>;
119+
expectType<'foo#bar>>baz'>(withPunctuation2);
120+
121+
declare const withPunctuation3: DelimiterCase<'card::after', '#'>;
122+
expectType<'card::after'>(withPunctuation3);
123+
124+
declare const withPunctuation4: DelimiterCase<'div.card::after', '#'>;
125+
expectType<'div.card::after'>(withPunctuation4);
126+
127+
declare const withPunctuationAndNumber: DelimiterCase<'foo-bar::01', '#'>;
128+
expectType<'foo#bar::01'>(withPunctuationAndNumber);
129+
130+
declare const withPunctuationAndNumber2: DelimiterCase<'foo-bar::01', '#', {splitOnNumbers: true}>;
131+
expectType<'foo#bar::#01'>(withPunctuationAndNumber2);
132+
115133
// Verifying example
116134
type OddCasedProperties<T> = {
117135
[K in keyof T as DelimiterCase<K, '#'>]: T[K];

test-d/kebab-case.ts

+18
Original file line numberDiff line numberDiff line change
@@ -78,3 +78,21 @@ expectType<'fo-o2bar'>(kebabFromNumberInTheMiddleNoSplitOnNumbersEdgeCase2);
7878

7979
const kebabFromNumberInTheMiddleNoSplitOnNumbersEdgeCase3: KebabCase<'FOO22Bar'> = 'foo22-bar';
8080
expectType<'foo22-bar'>(kebabFromNumberInTheMiddleNoSplitOnNumbersEdgeCase3);
81+
82+
declare const withPunctuation: KebabCase<'onDialog:close'>;
83+
expectType<'on-dialog:close'>(withPunctuation);
84+
85+
declare const withPunctuation2: KebabCase<'foo-bar>>baz'>;
86+
expectType<'foo-bar>>baz'>(withPunctuation2);
87+
88+
declare const withPunctuation3: KebabCase<'card::after'>;
89+
expectType<'card::after'>(withPunctuation3);
90+
91+
declare const withPunctuation4: KebabCase<'div.card::after'>;
92+
expectType<'div.card::after'>(withPunctuation4);
93+
94+
declare const withPunctuationAndNumber: KebabCase<'foo-bar::01'>;
95+
expectType<'foo-bar::01'>(withPunctuationAndNumber);
96+
97+
declare const withPunctuationAndNumber2: KebabCase<'foo-bar::01', {splitOnNumbers: true}>;
98+
expectType<'foo-bar::-01'>(withPunctuationAndNumber2);

test-d/screaming-snake-case.ts

+18
Original file line numberDiff line numberDiff line change
@@ -82,3 +82,21 @@ expectType<'FOO22_BAR'>(snakeFromNumberInTheMiddleNoSplitOnNumbersEdgeCase3);
8282

8383
const nonStringFromNonString: ScreamingSnakeCase<[]> = [];
8484
expectType<[]>(nonStringFromNonString);
85+
86+
declare const withPunctuation: ScreamingSnakeCase<'onDialog:close'>;
87+
expectType<'ON_DIALOG:CLOSE'>(withPunctuation);
88+
89+
declare const withPunctuation2: ScreamingSnakeCase<'foo-bar>>baz'>;
90+
expectType<'FOO_BAR>>BAZ'>(withPunctuation2);
91+
92+
declare const withPunctuation3: ScreamingSnakeCase<'card::after'>;
93+
expectType<'CARD::AFTER'>(withPunctuation3);
94+
95+
declare const withPunctuation4: ScreamingSnakeCase<'div.card::after'>;
96+
expectType<'DIV.CARD::AFTER'>(withPunctuation4);
97+
98+
declare const withPunctuationAndNumber: ScreamingSnakeCase<'foo-bar::01'>;
99+
expectType<'FOO_BAR::01'>(withPunctuationAndNumber);
100+
101+
declare const withPunctuationAndNumber2: ScreamingSnakeCase<'foo-bar::01', {splitOnNumbers: true}>;
102+
expectType<'FOO_BAR::_01'>(withPunctuationAndNumber2);

test-d/snake-case.ts

+18
Original file line numberDiff line numberDiff line change
@@ -81,3 +81,21 @@ expectType<'fo_o2bar'>(snakeFromNumberInTheMiddleNoSplitOnNumbersEdgeCase2);
8181

8282
const snakeFromNumberInTheMiddleNoSplitOnNumbersEdgeCase3: SnakeCase<'FOO22Bar'> = 'foo22_bar';
8383
expectType<'foo22_bar'>(snakeFromNumberInTheMiddleNoSplitOnNumbersEdgeCase3);
84+
85+
declare const withPunctuation: SnakeCase<'onDialog:close'>;
86+
expectType<'on_dialog:close'>(withPunctuation);
87+
88+
declare const withPunctuation2: SnakeCase<'foo-bar>>baz'>;
89+
expectType<'foo_bar>>baz'>(withPunctuation2);
90+
91+
declare const withPunctuation3: SnakeCase<'card::after'>;
92+
expectType<'card::after'>(withPunctuation3);
93+
94+
declare const withPunctuation4: SnakeCase<'div.card::after'>;
95+
expectType<'div.card::after'>(withPunctuation4);
96+
97+
declare const withPunctuationAndNumber: SnakeCase<'foo-bar::01'>;
98+
expectType<'foo_bar::01'>(withPunctuationAndNumber);
99+
100+
declare const withPunctuationAndNumber2: SnakeCase<'foo-bar::01', {splitOnNumbers: true}>;
101+
expectType<'foo_bar::_01'>(withPunctuationAndNumber2);

0 commit comments

Comments
 (0)