forked from primer/figma-action
-
Notifications
You must be signed in to change notification settings - Fork 0
/
entrypoint.js
143 lines (131 loc) · 4.07 KB
/
entrypoint.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
const got = require('got')
const {ensureDir, writeFile} = require('fs-extra')
const {join, resolve} = require('path')
const Figma = require('figma-js')
const {FIGMA_TOKEN, FIGMA_FILE_URL} = process.env
const PQueue = require('p-queue')
const sanitize = require("sanitize-filename")
const options = {
format: 'jpg',
outputDir: './build/',
scale: '1'
}
for(const arg of process.argv.slice(2)) {
const [param, value] = arg.split('=')
if(options[param]) {
options[param] = value
}
}
if(!FIGMA_TOKEN) {
throw Error('Cannot find FIGMA_TOKEN in process!')
}
const client = Figma.Client({
personalAccessToken: FIGMA_TOKEN
})
// Fail if there's no figma file key
let fileId = null
if (!fileId) {
try {
fileId = FIGMA_FILE_URL.match(/file\/([a-z0-9]+)\//i)[1]
} catch (e) {
throw Error('Cannot find FIGMA_FILE_URL key in process!')
}
}
console.log(`Exporting ${FIGMA_FILE_URL} components`)
client.file(fileId)
.then(({ data }) => {
console.log('Processing response')
const components = {}
function check(c) {
if (c.type === 'COMPONENT') {
const {name, id} = c
const {description = '', key} = data.components[c.id]
const {width, height} = c.absoluteBoundingBox
const filename = `${sanitize(name).toLowerCase()}.${options.format}`;
components[id] = {
name,
filename,
id,
key,
file: fileId,
description,
width,
height
}
} else if (c.children) {
// eslint-disable-next-line github/array-foreach
c.children.forEach(check)
}
}
data.document.children.forEach(check)
if (Object.values(components).length === 0) {
throw Error('No components found!')
}
console.log(`${Object.values(components).length} components found in the figma file`)
return components
})
.then(components => {
console.log('Getting export urls')
const allComponentIds = Object.keys(components)
console.log('The number of components: ', allComponentIds.length)
console.log('The number of components with image: ', allComponentIds.filter(id => components[id].image).length)
const getFileImages = chunkArray(allComponentIds).map(ids => {
return client.fileImages(
fileId,
{
ids,
format: options.format,
scale: options.scale
}
).then(({data}) => {
for(const id of Object.keys(data.images)) {
components[id].image = data.images[id]
}
return components
})
})
return Promise.all(getFileImages).then(() => components)
})
.then(components => {
console.log('The number of components with image after request: ', Object.keys(components).filter(id => components[id].image).length)
return ensureDir(join(options.outputDir))
.then(() => writeFile(resolve(options.outputDir, 'data.json'), JSON.stringify(components), 'utf8'))
.then(() => components)
})
.then(components => {
const contentTypes = {
'svg': 'image/svg+xml',
'png': 'image/png',
'jpg': 'image/jpeg'
}
return queueTasks(Object.values(components).map(component => () => {
return got.get(component.image, {
headers: {
'Content-Type': contentTypes[options.format]
},
encoding: (options.format === 'svg' ? 'utf8' : null)
})
.then(response => {
return ensureDir(join(options.outputDir, options.format))
.then(() => writeFile(join(options.outputDir, options.format, component.filename), response.body, (options.format === 'svg' ? 'utf8' : 'binary')))
})
}))
})
.catch(error => {
throw Error(`Error fetching components from Figma: ${error}`)
})
function queueTasks(tasks, options) {
const queue = new PQueue(Object.assign({concurrency: 3}, options))
for (const task of tasks) {
queue.add(task)
}
queue.start()
return queue.onIdle()
}
function chunkArray(arr, chunkSize = 100) {
const chunks = [];
for (let i = 0; i < arr.length; i += chunkSize) {
chunks.push(arr.slice(i, i + chunkSize));
}
return chunks;
}