Skip to content

Commit 56ba227

Browse files
Adding pascalCase transform to be used by brand (#1036)
* adding pascalCase * added changeset * extracting function
1 parent 4ce3bcf commit 56ba227

File tree

8 files changed

+159
-12
lines changed

8 files changed

+159
-12
lines changed

.changeset/dry-walls-marry.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@primer/primitives': minor
3+
---
4+
5+
Adding a pascalCase trasnformer
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import {getMockToken} from '../test-utilities'
2+
import {namePathToPascalCase} from './namePathToPascalCase'
3+
4+
describe('Transformer: namePathToPascalCase', () => {
5+
it('converts path elements to dot.notation and ignores name proprty', () => {
6+
const input = [
7+
getMockToken({
8+
name: 'tokenName',
9+
path: ['path', 'to', 'token'],
10+
}),
11+
getMockToken({
12+
name: 'tokenName',
13+
path: ['PATH', 'tO', 'Token'],
14+
}),
15+
getMockToken({
16+
name: 'tokenName',
17+
path: ['path', 'toToken'],
18+
}),
19+
getMockToken({
20+
name: 'tokenName',
21+
path: ['pathtoToken'],
22+
}),
23+
]
24+
const expectedOutput = ['PathToToken', 'PATHTOToken', 'PathToToken', 'PathtoToken']
25+
26+
expect(input.map(item => namePathToPascalCase.transformer(item, {}))).toStrictEqual(expectedOutput)
27+
})
28+
29+
it('removes `@`, so we can use it for the default hack', () => {
30+
const input = [
31+
getMockToken({
32+
name: 'tokenName',
33+
path: ['fgColor', 'accent', '@'],
34+
}),
35+
getMockToken({
36+
name: 'tokenName',
37+
path: ['fgColor', '@', 'muted'],
38+
}),
39+
]
40+
const expectedOutput = ['FgColorAccent', 'FgColorMuted']
41+
expect(input.map(item => namePathToPascalCase.transformer(item, {}))).toStrictEqual(expectedOutput)
42+
})
43+
44+
it('adds prefix to token name', () => {
45+
const platform = {
46+
prefix: 'PRIMER',
47+
}
48+
const input = getMockToken({
49+
name: 'tokenName',
50+
path: ['start', 'pathTo', 'token'],
51+
})
52+
const expectedOutput = 'PRIMERStartPathToToken'
53+
expect(namePathToPascalCase.transformer(input, platform)).toStrictEqual(expectedOutput)
54+
})
55+
})
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import type StyleDictionary from 'style-dictionary'
2+
import {toPascalCase} from '../utilities/toPascalCase'
3+
/**
4+
* @description converts the [TransformedToken's](https://github.com/amzn/style-dictionary/blob/main/types/TransformedToken.d.ts) `.path` array to a PascalCase string, preserves casing of parts
5+
* @type name transformer — [StyleDictionary.NameTransform](https://github.com/amzn/style-dictionary/blob/main/types/Transform.d.ts)
6+
* @matcher omitted to match all tokens
7+
* @transformer returns `string` PascalCase
8+
*/
9+
export const namePathToPascalCase: StyleDictionary.Transform = {
10+
type: `name`,
11+
transformer: (token: StyleDictionary.TransformedToken, options?: StyleDictionary.Platform): string =>
12+
toPascalCase([options?.prefix || '', ...token.path]),
13+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import {filterStringArray} from './filterStringArray'
2+
3+
describe('Utilities: filterStringArray', () => {
4+
it('keeps words', () => {
5+
expect(filterStringArray(['primer', 'test'])).toStrictEqual(['primer', 'test'])
6+
})
7+
8+
it('it filters out undefined, etc.', () => {
9+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
10+
// @ts-ignore
11+
expect(filterStringArray(['primer', false, null, undefined, ''])).toStrictEqual(['primer'])
12+
})
13+
14+
it('remove special chars', () => {
15+
expect(filterStringArray(['primer@test', 'Y_e-s', 'with space'])).toStrictEqual([
16+
'primer',
17+
'test',
18+
'Y',
19+
'e',
20+
's',
21+
'with',
22+
'space',
23+
])
24+
})
25+
})

src/utilities/filterStringArray.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
export const filterStringArray = (string: string[]): string[] => {
2+
// match unsupported characters
3+
const regex = /[^a-zA-Z0-9]+/g
4+
// replace any non-letter and non-number character and split into word array
5+
const stringArray = string
6+
.filter(Boolean)
7+
.join(' ')
8+
.replace(regex, ' ')
9+
.split(' ')
10+
// remove undefined if exists
11+
.filter((part: unknown): part is string => Boolean(part) && typeof part === 'string')
12+
13+
return stringArray
14+
}

src/utilities/toCamelCase.ts

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,13 @@
1+
import {filterStringArray} from './filterStringArray'
12
import {upperCaseFirstCharacter} from './upperCaseFirstCharacter'
23

34
export const toCamelCase = (string: string | string[]) => {
45
if (!Array.isArray(string)) {
56
string = [string]
67
}
7-
// match unsupported characters
8-
const regex = /[^a-zA-Z0-9]+/g
9-
// replace any non-letter and non-number character and split into word array
10-
const stringArray = string
11-
.filter(part => part !== '@')
12-
.filter(Boolean)
13-
.join(' ')
14-
.replace(regex, ' ')
15-
.split(' ')
8+
169
return (
17-
stringArray
18-
// remove undefined if exists
19-
.filter((part: unknown): part is string => typeof part === 'string')
10+
filterStringArray(string)
2011
// ucFirst all but first part
2112
.map((part: string, index: number) => {
2213
if (index > 0) {

src/utilities/toPascalCase.test.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import {toPascalCase} from './toPascalCase'
2+
3+
describe('Utilities: toPascalCase', () => {
4+
it('it transforms all lowercase word', () => {
5+
expect(toPascalCase('primer')).toStrictEqual('Primer')
6+
})
7+
8+
it('it transforms all lowercase sentence (words with spaces)', () => {
9+
expect(toPascalCase('primer design token')).toStrictEqual('PrimerDesignToken')
10+
})
11+
12+
it('it transforms all words with special chars', () => {
13+
expect(toPascalCase('primer_design-token+edition')).toStrictEqual('PrimerDesignTokenEdition')
14+
})
15+
16+
it('it preserves casing for words that are already all uppercased', () => {
17+
expect(toPascalCase('PRIMER')).toStrictEqual('PRIMER')
18+
})
19+
20+
it('it transforms all camelCase word', () => {
21+
expect(toPascalCase('camelCase')).toStrictEqual('CamelCase')
22+
})
23+
24+
it('it transforms array of words', () => {
25+
expect(toPascalCase(['primer', 'design', 'token'])).toStrictEqual('PrimerDesignToken')
26+
})
27+
})

src/utilities/toPascalCase.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import {filterStringArray} from './filterStringArray'
2+
import {upperCaseFirstCharacter} from './upperCaseFirstCharacter'
3+
4+
export const toPascalCase = (string: string | string[]) => {
5+
if (!Array.isArray(string)) {
6+
string = [string]
7+
}
8+
9+
return (
10+
filterStringArray(string)
11+
// ucFirst all but first part
12+
.map((part: string) => {
13+
return upperCaseFirstCharacter(part)
14+
})
15+
.join('')
16+
)
17+
}

0 commit comments

Comments
 (0)