Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions packages/tokens-studio-for-figma/src/app/components/utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,22 @@ describe('isSingleToken', () => {

expect(isSingleToken(wrongToken)).toBe(false);
});
it('rejects token groups with name and value child tokens', () => {
const tokenGroup = {
name: {
type: 'typography',
name: 'included-link.contract.chip.text.label.name',
value: { fontFamily: 'Inter' },
},
value: {
type: 'typography',
name: 'included-link.contract.chip.text.label.value',
value: { fontFamily: 'Inter' },
},
};

expect(isSingleToken(tokenGroup)).toBe(false);
});
});

describe('isSingleTypographyToken', () => {
Expand Down
50 changes: 50 additions & 0 deletions packages/tokens-studio-for-figma/src/utils/convertTokens.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,4 +141,54 @@ describe('convertToTokenArray', () => {
{ name: 'global.nestGroupWithType.font.big', value: '24px', type: 'dimension' },
]);
});

it('ignores non-string name properties in token JSON', () => {
expect(convertToTokenArray({
tokens: {
global: {
color: {
primary: {
$value: '#ff0000',
$type: 'color',
name: 123,
},
},
},
},
})).toEqual([
{
name: 'global.color.primary',
value: '#ff0000',
type: 'color',
},
]);
});

it('normalizes new Studio type aliases to plugin token types', () => {
expect(convertToTokenArray({
tokens: {
global: {
gap: {
$value: '8px',
$type: 'space',
},
width: {
$value: '16px',
$type: 'size',
},
},
},
})).toEqual([
{
name: 'global.gap',
value: '8px',
type: 'spacing',
},
{
name: 'global.width',
value: '16px',
type: 'sizing',
},
]);
});
});
27 changes: 20 additions & 7 deletions packages/tokens-studio-for-figma/src/utils/convertTokens.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,17 @@ export type Tokens =
$description?: string;
};

function normalizeTokenType(type: unknown): TokenTypes | undefined {
switch (type) {
case 'space':
return TokenTypes.SPACING;
case 'size':
return TokenTypes.SIZING;
default:
return typeof type === 'string' ? type as TokenTypes : undefined;
}
}

// @TODO fix typings
function checkForTokens({
obj,
Expand Down Expand Up @@ -83,16 +94,17 @@ function checkForTokens({
if (isSingleTokenInJSON(token)) {
returnValue = token as SingleToken<false>;
returnValue.value = token[TokenFormat.tokenValueKey];
const tokenType = normalizeTokenType(token[TokenFormat.tokenTypeKey]);

if (token[TokenFormat.tokenDescriptionKey] && typeof token[TokenFormat.tokenDescriptionKey] === 'string') {
returnValue.description = token[TokenFormat.tokenDescriptionKey] as string;
}
if (!token[TokenFormat.tokenTypeKey] && inheritType) {
if (!tokenType && inheritType) {
returnValue.type = inheritType as TokenTypes;
returnValue.inheritTypeLevel = currentTypeLevel as number;
} else {
returnValue.type = token[TokenFormat.tokenTypeKey];
if (inheritType === token[TokenFormat.tokenTypeKey] && currentTypeLevel > 0) {
returnValue.type = tokenType as TokenTypes;
if (inheritType === tokenType && currentTypeLevel > 0) {
returnValue.inheritTypeLevel = currentTypeLevel as number;
}
}
Expand All @@ -107,14 +119,15 @@ function checkForTokens({
acc[key] = isSingleTokenValueObject(val) && returnValuesOnly ? val[TokenFormat.tokenValueKey] : val;
return acc;
}, {});
const tokenType = normalizeTokenType(token[TokenFormat.tokenTypeKey]);
if (token[TokenFormat.tokenDescriptionKey] && typeof token[TokenFormat.tokenDescriptionKey] === 'string') {
returnValue.description = token[TokenFormat.tokenDescriptionKey] as string;
}
if (!token[TokenFormat.tokenTypeKey] && inheritType) {
if (!tokenType && inheritType) {
returnValue.type = inheritType as TokenTypes;
returnValue.inheritTypeLevel = currentTypeLevel as number;
} else {
returnValue.type = token[TokenFormat.tokenTypeKey] as TokenTypes;
returnValue.type = tokenType as TokenTypes;
}
} else if (typeof token === 'object') {
// We dont have a single token value key yet, so it's likely a group which we need to iterate over
Expand All @@ -124,7 +137,7 @@ function checkForTokens({
// When token groups are typed, we need to inherit the type to their children
if (isTokenGroupWithType(token)) {
const { [TokenFormat.tokenTypeKey]: groupType, ...tokenValues } = token;
inheritType = groupType as unknown as TokenTypes;
inheritType = normalizeTokenType(groupType);
currentTypeLevel = groupLevel;
tokenToCheck = tokenValues as Tokens;
}
Expand Down Expand Up @@ -159,7 +172,7 @@ function checkForTokens({
};
}

if (typeof returnValue === 'object' && 'name' in returnValue && returnValue?.name) {
if (typeof returnValue === 'object' && 'name' in returnValue && typeof returnValue?.name === 'string') {
returnValue.name = returnValue.name.split('/').join('.');
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ export function isSingleToken(token: SingleToken | any): token is SingleToken {
&& typeof token === 'object'
&& 'value' in token
&& 'name' in token
&& typeof token.name === 'string'
);
}
Loading