Skip to content

Commit 46b5f56

Browse files
committed
chore: refactor
1 parent 350118a commit 46b5f56

File tree

6 files changed

+290
-204
lines changed

6 files changed

+290
-204
lines changed
Lines changed: 101 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,68 +1,113 @@
1-
import { AndroidTypographyParams, FontHandler } from "./types.mjs";
1+
import { AndroidTypographyParams, Entry, Handler } from "./types.mjs";
22
import { pascalCase, snakeCase } from "change-case";
3-
import { findNode } from "./utils.js";
3+
import { fetchFile, findNode, handleLetterSpacing, walkNodes } from "./utils.js";
44
import { SectionNode, TextNode } from "@figma/rest-api-spec";
55

6-
const androidFontHandler: FontHandler<AndroidTypographyParams> = {
7-
mapToParams({ characters, style }, documentNode) {
8-
const name = pascalCase(characters);
9-
const textAllCaps = style.textCase === "UPPER";
10-
const { fontFamily, fontSize, lineHeightPx: lineHeight } = style;
11-
let { letterSpacing } = style;
12-
let lineSpacing: number | undefined;
13-
let lineSpacingExtra: number | undefined;
14-
let firstBaselineToTopHeight: number | undefined;
15-
let lastBaselineToBottomHeight: number | undefined;
16-
/**
17-
* Magic number
18-
*/
19-
const NATURAL_LINE_HEIGHT = 1.17;
6+
type TypographyEntry = Entry<AndroidTypographyParams>;
207

21-
if (letterSpacing) {
22-
letterSpacing = parseFloat(letterSpacing.toFixed(2));
23-
}
8+
const handler: Handler = async (fileKeys: string[]) => {
9+
const alfasansTypography: TypographyEntry[] = [];
10+
const alfasansFixedTypography: TypographyEntry[] = [];
11+
const systemTypography: TypographyEntry[] = [];
12+
const systemFixedTypography: TypographyEntry[] = [];
2413

25-
if (typeof fontSize === "number" && typeof lineHeight === "number") {
26-
lineSpacing = Math.floor(lineHeight - fontSize * NATURAL_LINE_HEIGHT);
27-
lineSpacingExtra = Math.round(lineHeight - fontSize * NATURAL_LINE_HEIGHT);
14+
for (const fileKey of fileKeys) {
15+
const file = await fetchFile(fileKey);
2816

29-
const baselineNode = findNode(
30-
[documentNode],
31-
(node): node is SectionNode => node.type === "SECTION" && node.name === "BaselineExport"
32-
);
17+
walkNodes([file.document], (node) => {
18+
if (node.type === "SECTION" && node.name.startsWith("TextStylesExport")) {
19+
const target = node.name.endsWith("AlfaSans")
20+
? alfasansTypography
21+
: node.name.endsWith("AlfaSansFixed")
22+
? alfasansFixedTypography
23+
: node.name.endsWith("Fixed")
24+
? systemFixedTypography
25+
: systemTypography;
3326

34-
if (baselineNode) {
35-
const node = baselineNode.children.find(
36-
(child): child is TextNode =>
37-
child.type === "TEXT" && child.characters.startsWith(`${fontSize}-${lineHeight}`)
38-
);
27+
target.push(
28+
...node.children
29+
.filter((childNode) => childNode.type === "TEXT")
30+
.map<TypographyEntry>(({ characters, style }) => {
31+
const name = pascalCase(characters);
32+
const textAllCaps = style.textCase === "UPPER";
33+
const { fontSize, fontStyle, lineHeightPx: lineHeight } = style;
34+
const fontFamily =
35+
typeof style.fontFamily === "string"
36+
? `${snakeCase(style.fontFamily)}${fontStyle ? `_${fontStyle.toLowerCase()}` : ""}`
37+
: style.fontFamily;
38+
const letterSpacing = handleLetterSpacing(style.letterSpacing);
39+
let lineSpacing: number | undefined;
40+
let lineSpacingExtra: number | undefined;
41+
let firstBaselineToTopHeight: number | undefined;
42+
let lastBaselineToBottomHeight: number | undefined;
43+
44+
if (typeof fontSize === "number" && typeof lineHeight === "number") {
45+
/**
46+
* Magic number
47+
*/
48+
const NATURAL_LINE_HEIGHT = 1.17;
49+
lineSpacing = Math.floor(lineHeight - fontSize * NATURAL_LINE_HEIGHT);
50+
lineSpacingExtra = Math.round(lineHeight - fontSize * NATURAL_LINE_HEIGHT);
51+
52+
const baselineNode = findNode(
53+
[file.document],
54+
(node): node is SectionNode =>
55+
node.type === "SECTION" && node.name === "BaselineExport"
56+
);
3957

40-
if (node) {
41-
[, , firstBaselineToTopHeight, lastBaselineToBottomHeight] = node.characters
42-
.split("-")
43-
.map((val) => parseInt(val, 10));
44-
}
58+
if (baselineNode) {
59+
const node = baselineNode.children.find(
60+
(child): child is TextNode =>
61+
child.type === "TEXT" &&
62+
child.characters.startsWith(`${fontSize}-${lineHeight}`)
63+
);
64+
65+
if (node) {
66+
[, , firstBaselineToTopHeight, lastBaselineToBottomHeight] = node.characters
67+
.split("-")
68+
.map((val) => parseInt(val, 10));
69+
}
70+
}
71+
}
72+
73+
return [
74+
name,
75+
{
76+
font_size: fontSize,
77+
line_height: lineHeight,
78+
line_spacing: lineSpacing,
79+
line_spacing_extra: lineSpacingExtra,
80+
font_family: fontFamily,
81+
text_all_caps: textAllCaps,
82+
letter_spacing: letterSpacing,
83+
first_baseline_to_top_height: firstBaselineToTopHeight,
84+
last_baseline_to_bottom_height: lastBaselineToBottomHeight,
85+
},
86+
];
87+
})
88+
);
4589
}
46-
}
90+
});
91+
}
4792

48-
return [
49-
name,
50-
{
51-
font_size: fontSize,
52-
line_height: lineHeight,
53-
line_spacing: lineSpacing,
54-
line_spacing_extra: lineSpacingExtra,
55-
font_family: fontFamily,
56-
text_all_caps: textAllCaps,
57-
letter_spacing: letterSpacing,
58-
first_baseline_to_top_height: firstBaselineToTopHeight,
59-
last_baseline_to_bottom_height: lastBaselineToBottomHeight,
60-
},
61-
];
62-
},
63-
mapFontFamily(fontFamily) {
64-
return typeof fontFamily === "string" ? snakeCase(fontFamily) : fontFamily;
65-
},
93+
return [
94+
{
95+
file: "styles/typography_alfasans_android.json",
96+
entries: alfasansTypography,
97+
},
98+
{
99+
file: "styles/typography_alfasans_fixed_android.json",
100+
entries: alfasansFixedTypography,
101+
},
102+
{
103+
file: "styles/typography_android.json",
104+
entries: systemTypography,
105+
},
106+
{
107+
file: "styles/typography_fixed_android.json",
108+
entries: systemFixedTypography,
109+
},
110+
];
66111
};
67112

68-
export default androidFontHandler;
113+
export default handler;

scripts/export-typography-ios.mts

Lines changed: 67 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,70 @@
11
import { pascalCase } from "change-case";
2-
import { FontFamily, FontHandler, IOSTypographyParams } from "./types.mjs";
3-
4-
const iosFontHandler: FontHandler<IOSTypographyParams> = {
5-
mapToParams({ characters, style }) {
6-
const name = pascalCase(characters);
7-
const monospace = characters.toLowerCase().includes("mono");
8-
const textAllCaps = style.textCase === "UPPER";
9-
const { fontFamily, fontSize, lineHeightPx: lineHeight, fontStyle } = style;
10-
const fontWeight = fontStyle?.toLowerCase();
11-
let { letterSpacing } = style;
12-
let lineSpacing: number | undefined;
13-
14-
if (letterSpacing) {
15-
letterSpacing = parseFloat(letterSpacing.toFixed(2));
16-
}
17-
18-
if (typeof fontSize === "number" && typeof lineHeight === "number") {
19-
const NATURAL_LINE_HEIGHT = 1.2;
20-
lineSpacing = Math.round(lineHeight - fontSize * NATURAL_LINE_HEIGHT);
21-
}
22-
23-
return [
24-
name,
25-
{
26-
font_size: fontSize,
27-
line_height: lineHeight,
28-
line_spacing: lineSpacing,
29-
font_family: fontFamily,
30-
font_weight: fontWeight,
31-
text_all_caps: textAllCaps,
32-
letter_spacing: letterSpacing,
33-
monospace,
34-
},
35-
];
36-
},
37-
mapFontFamily(fontFamily) {
38-
switch (fontFamily) {
39-
case FontFamily.ALFASANS:
40-
return fontFamily;
41-
default:
42-
return "System";
43-
}
44-
},
2+
import { FontFamily, IOSTypographyParams, Handler, Entry } from "./types.mjs";
3+
import { fetchFile, handleLetterSpacing, walkNodes } from "./utils.js";
4+
5+
type TypographyEntry = Entry<IOSTypographyParams>;
6+
7+
const handler: Handler = async (fileKeys: string[]) => {
8+
const alfasansTypography: TypographyEntry[] = [];
9+
const systemTypography: TypographyEntry[] = [];
10+
11+
for (const fileKey of fileKeys) {
12+
const file = await fetchFile(fileKey);
13+
14+
walkNodes([file.document], (node) => {
15+
if (node.type === "SECTION" && node.name.startsWith("TextStylesExport")) {
16+
const target = node.name.endsWith("AlfaSans") ? alfasansTypography : systemTypography;
17+
18+
target.push(
19+
...node.children
20+
.filter((childNode) => childNode.type === "TEXT")
21+
.map<TypographyEntry>(({ characters, style }) => {
22+
const name = pascalCase(characters);
23+
const monospace = characters.toLowerCase().includes("mono");
24+
const textAllCaps = style.textCase === "UPPER";
25+
const { fontSize, lineHeightPx: lineHeight, fontStyle } = style;
26+
const fontFamily = style.fontFamily === FontFamily.ALFASANS ? style.fontFamily : "System";
27+
const fontWeight = fontStyle?.toLowerCase();
28+
const letterSpacing = handleLetterSpacing(style.letterSpacing);
29+
let lineSpacing: number | undefined;
30+
31+
if (typeof fontSize === "number" && typeof lineHeight === "number") {
32+
/**
33+
* Magic number
34+
*/
35+
const NATURAL_LINE_HEIGHT = 1.2;
36+
lineSpacing = Math.round(lineHeight - fontSize * NATURAL_LINE_HEIGHT);
37+
}
38+
39+
return [
40+
name,
41+
{
42+
font_size: fontSize,
43+
line_height: lineHeight,
44+
line_spacing: lineSpacing,
45+
font_family: fontFamily,
46+
font_weight: fontWeight,
47+
text_all_caps: textAllCaps,
48+
letter_spacing: letterSpacing,
49+
monospace,
50+
},
51+
];
52+
})
53+
);
54+
}
55+
});
56+
}
57+
58+
return [
59+
{
60+
file: "styles/typography_ios.json",
61+
entries: systemTypography,
62+
},
63+
{
64+
file: "styles/typography_alfasans_ios.json",
65+
entries: alfasansTypography,
66+
},
67+
];
4568
};
4669

47-
export default iosFontHandler;
70+
export default handler;

0 commit comments

Comments
 (0)