Skip to content

Commit

Permalink
feat: add utils to normalise and create new structure for figma api
Browse files Browse the repository at this point in the history
  • Loading branch information
braposo committed May 26, 2019
1 parent 00f138b commit a527739
Show file tree
Hide file tree
Showing 5 changed files with 210 additions and 70 deletions.
70 changes: 0 additions & 70 deletions src/utils.js

This file was deleted.

51 changes: 51 additions & 0 deletions src/utils/figma.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
const Figma = require("figma-js");
const { processNodes, groupNodes } = require("./nodes");

const client = Figma.Client({
personalAccessToken: process.env.FIGMA_TOKEN,
});

const { file, fileImages, comments, postComment, teamProjects, projectFiles } = client;

function getFigma(label, fn, id, params, normalise = false) {
return new Promise((resolve, reject) => {
const withParams = params ? { ...params } : null;

// eslint-disable-next-line no-console
console.log("fetching", label, id);
fn(id, withParams)
.then(({ data }) => {
if (normalise) {
const { name, lastModified, thumbnailUrl, version, document, styles } = data;

const [processedNodes, processedShortcuts] = processNodes(document, styles);

const result = {
name,
lastModified,
thumbnailUrl,
version,
children: processedNodes,
shortcuts: groupNodes(processedShortcuts),
};

resolve(result);
} else {
resolve(data);
}
})
.catch(reject);
});
}

exports.loadFigmaFile = id => getFigma("file", file, id, null, true);

exports.loadFigmaComments = id => getFigma("comments", comments, id, null, false);

exports.loadFigmaImages = (id, params) => getFigma("images", fileImages, id, params, false);

exports.loadTeamProjects = id => getFigma("projects", teamProjects, id);

exports.loadProjectFiles = id => getFigma("projectFiles", projectFiles, id);

exports.createComment = (id, params) => getFigma("postComment", postComment, id, params);
16 changes: 16 additions & 0 deletions src/utils/helpers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
exports.getPosition = node => ({
x: node.absoluteBoundingBox.x,
y: node.absoluteBoundingBox.y,
});

exports.getSize = node => ({
width: node.absoluteBoundingBox.width,
height: node.absoluteBoundingBox.height,
});

exports.getFileId = str => {
const regex = /file\(id: "(\w+)"\)/g;
const res = regex.exec(str);

return res && res[1];
};
87 changes: 87 additions & 0 deletions src/utils/nodes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
const groupBy = require("lodash/groupBy");
const uniqBy = require("lodash/uniqBy");

const groupNodes = nodes => groupBy(uniqBy(nodes, "id"), "type");
exports.groupNodes = groupNodes;

exports.getNodes = (data, nodeType, filterBy) => {
const { name: filterByName, type: filterByType } = filterBy;
let dataNodes;

if (nodeType !== "ALL") {
dataNodes = data.shortcuts[nodeType];
} else {
dataNodes =
filterByType == null
? data.children
: data.children.filter(node => filterByType.includes(node.type));
}

if (dataNodes == null) {
return [];
}

if (filterByName != null) {
// TODO: compare by regex instead so we can have smarter matches
return dataNodes.filter(node => node.name === filterByName);
}

return dataNodes;
};

exports.processNodes = (nodes, documentStyles) => {
const parsedStyles = new Map(Object.entries(documentStyles));

const traverseChildren = (node, parentId) => {
const { id, styles, children, ...rest } = node;
let nodeStyles = [];

// If node has styles definitions populate that with the actual styles
if (styles != null) {
nodeStyles = Object.entries(styles).map(([key, styleId]) => {
const documentStyle = parsedStyles.get(styleId);

return {
id: styleId,
...documentStyle,
style: node[`${key}s`],
type: "STYLE",
};
});
}

// Reached a leaf so returning the simplified node
if (children == null || children.length === 0) {
return [[{ id, parentId, ...rest }], nodeStyles];
}

// If it gets here then it means it has children
// so we're going to recursively go through them
// and combine everything
const [parsedChildren, shortcuts] = children.reduce(
(acc, child) => {
const [accChildren, accShortcuts] = acc;
const [tChildren, tShortcuts] = traverseChildren(child, id);
return [
[...accChildren, ...tChildren],
[...accShortcuts, ...tChildren, ...tShortcuts],
];
},
[[], []]
);

// Finally we return the parsed node with the
// parsed children grouped by type
const parsedNode = {
id,
parentId,
...rest,
children: parsedChildren,
shortcuts: groupNodes(shortcuts),
};

return [[parsedNode], shortcuts];
};

return traverseChildren(nodes);
};
56 changes: 56 additions & 0 deletions src/utils/shortcuts.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
const camelCase = require("lodash/camelCase");
const { nodeTypes } = require("../types/node");
const { getNodes } = require("./nodes");

const shortcutTypes = nodeTypes.map(type => {
const convertedType = type === "CANVAS" ? "PAGE" : type;
return camelCase(convertedType);
});

const mapTypeToFigmaType = nodeTypes.reduce(
(acc, type) => {
const figmaType = type === "CANVAS" ? "PAGE" : type;
const key = `${camelCase(figmaType)}s`;
return {
...acc,
[key]: type,
};
},
{
children: "ALL",
}
);

const mapTypeToQuery = nodeTypes.reduce(
(acc, type) => {
const convertedType = type === "CANVAS" ? "PAGE" : type;
const formattedType = camelCase(convertedType);
const key = `${formattedType}s`;
const returnType = formattedType.charAt(0).toUpperCase() + formattedType.slice(1);
return {
...acc,
[key]: `${key}(name: String): [${returnType}!]`,
};
},
{
children: "children(type: [NodeType], name: String): [Node!]",
}
);

exports.generateResolversForShortcuts = () =>
[...shortcutTypes, "children"].reduce((acc, resolverType) => {
const key = resolverType === "children" ? resolverType : `${resolverType}s`;
return {
...acc,
[key]: (root, { type, name }) =>
getNodes(root, mapTypeToFigmaType[key], { type, name }),
};
}, {});

exports.generateQueriesForShortcuts = () =>
[...shortcutTypes, "children"]
.map(type => {
const key = type === "children" ? type : `${type}s`;
return mapTypeToQuery[key];
})
.join("\n");

0 comments on commit a527739

Please sign in to comment.