Created
June 21, 2018 19:17
-
-
Save rsms/3ed1e3feb6abc5200ae269602a814f31 to your computer and use it in GitHub Desktop.
Revisions
-
rsms created this gist
Jun 21, 2018 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,186 @@ // // Figma project stats // Pulls statistics like number of files, frames, versions etc for a project. // // Usage: // export FIGMA_API_ACCESS_TOKEN='your-token' // node figma-project-stats.js <project-id> // // You can generate tokens in your account settings or at // https://www.figma.com/developers/explorer#personal-access-token // // <project-id> is the last number in the URL path of a project. // For instance, in this URL: // https://www.figma.com/files/5027479082769520/project/712/Project-Title // The project id is "712" // const http = require('https') let FIGMA_API_ACCESS_TOKEN = '' // populated from env let FIGMA_API_HOST = 'api.figma.com' // may be populated from env function findfkey(url) { return url.match(/\.com\/file\/([^\/]+)/)[1] } function apiget(path) { return new Promise((resolve, reject) => { let shortCircuited = false let req = http.request( { protocol: 'https:', host: FIGMA_API_HOST, method: 'GET', path: '/v1/' + path, headers: { 'X-FIGMA-TOKEN': FIGMA_API_ACCESS_TOKEN, }, }, res => { if (res.statusCode == 504 || res.statusCode == '504') { console.log(`${path} failed with status ${res.statusCode} -- retrying...`) shortCircuited = true return setTimeout(() => { apiget(path).then(resolve).catch(reject) }, 1000) } // console.log(`STATUS: ${res.statusCode}`) // console.log(`HEADERS:`, JSON.parse(JSON.stringify(res.headers))) let buf = '' res.setEncoding('utf8') res.on('data', chunk => { buf += chunk }) res.on('end', () => { let r = null try { r = JSON.parse(buf) } catch (err) { console.error(`failed to parse response body: ${err}`) console.error(`original body:\n------${buf}\n------`) return reject(err) } resolve(r, { status: res.statusCode }) }) } ) req.on('error', err => { if (!shortCircuited) { reject(err) } }) req.end() }) // promise } const frameLikeTypes = new Set('FRAME GROUP COMPONENT INSTANCE'.split(' ')) function countFrameLikeNodes(parent) { let n = 0 for (let node of parent.children) { if (frameLikeTypes.has(node.type)) { n++ } } return n } function usage() { console.error( `usage: ${require('path').basename(__filename)} <project-id>\n` + `Environment variables:\n` + ` FIGMA_API_ACCESS_TOKEN API access token (required)\n` + ` FIGMA_API_HOST API server hostname (e.g. "local-api.figma.com")\n` ) process.exit(1) } function main(args) { FIGMA_API_ACCESS_TOKEN = process.env['FIGMA_API_ACCESS_TOKEN'] || '' FIGMA_API_HOST = process.env['FIGMA_API_HOST'] || FIGMA_API_HOST if (args.length < 1) { console.error('missing project id') usage() } if (args.indexOf('-h') != -1 || args.indexOf('--help') != -1) { usage() } if (FIGMA_API_ACCESS_TOKEN.length == 0) { console.error( `Missing env variable FIGMA_API_ACCESS_TOKEN\n` + `Visit the following URL to generate a token:\n` + ` https://www.figma.com/developers/explorer#personal-access-token\n` ) usage() } let projectId = args[0].replace(/[^\d]+/g, '') console.log(`collecting stats for project ${projectId} on ${FIGMA_API_HOST}`) apiget(`projects/${projectId}/files`).then(r => { console.log(`inspecting ${r.files.length} project files...`) let nextFileIndex = 0 let nTotalPages = 0 let nTotalVersions = 0 let nTotalFrames = 0 let doNextFile = (key) => { let file = r.files[nextFileIndex++] if (!file) { // done console.log('project summary:') console.log('files: ', r.files.length) console.log('pages: ', nTotalPages) console.log('versions: ', nTotalVersions) console.log('top-level frames:', nTotalFrames) return } console.log(`file ${file.key} "${file.name}":`) let nversions = 0 let npages = 0 let nTopLevelFrames = 0 Promise.all([ apiget(`files/${file.key}/versions`).then(r => { nversions = r.versions.length }), apiget(`files/${file.key}`).then(r => { let pages = r.document.children npages = pages.length for (let page of pages) { nTopLevelFrames += countFrameLikeNodes(page) } }), ]).then(() => { console.log(' versions: ', nversions) console.log(' pages: ', npages) console.log(' top-level frames:', nTopLevelFrames) nTotalPages += npages nTotalVersions += nversions nTotalFrames += nTopLevelFrames doNextFile() }).catch(err => { console.error(err.stack || String(err)) }) } doNextFile() }) } main(process.argv.slice(2))