Skip to main content

I am trying to access the COMPONENT_SET name for each COMPONENT node. When I run this script I get the names of the properties for each variant but not the parent or main frame name. Halpppppppp


const axios = require("axios");
const fs = require("fs");
const path = require("path");
require("dotenv").config();

// the api key stored in .env
const figmaApiKey = process.env.FIGMA_API_KEY;
// the doc id stored in .env
const figmaDocId = process.env.FIGMA_DOC_ID;

const options = {
headers: {
"X-Figma-Token": figmaApiKey,
},
};

axios(`https://api.figma.com/v1/files/${figmaDocId}`, options).then((res) => {
const file = res.data;
const ids = Object.keys(file.components).toString();

// Save existing component names to an array
const existingComponentNames = fs
.readdirSync(path.join(__dirname, "src/svgs"))
.map((fileName) => {
return fileName.replace(".svg", "");
});

(async () => {
const res = await axios(
`https://api.figma.com/v1/images/${figmaDocId}/?ids=${ids}&format=svg`,
options
);
const urls = res.data.images;
let totalIconsAdded = 0;
let totalIconsRemoved = 0;

for (const [componentId, componentUrl] of Object.entries(urls)) {
const componentNode = file.components[componentId];
const componentName = componentNode.name;
const fileName = `${componentName}.svg`;

const filePath = path.join(__dirname, "src/svgs", fileName);

console.log(
`Component Name: ${componentName} - Component ID: ${componentId}`
);

if (fs.existsSync(filePath)) {
const existingSvg = fs.readFileSync(filePath, "utf-8");
const newSvg = (await axios(componentUrl)).data;

if (existingSvg === newSvg) {
console.log(`👌 No changes needed for ${fileName}`);
} else {
fs.writeFileSync(filePath, newSvg);
console.log(`✅ Updated ${fileName}`);
}

// Remove the component name from the existingComponentNames array
const index = existingComponentNames.indexOf(componentName);
if (index > -1) {
existingComponentNames.splice(index, 1);
}
} else {
const svg = (await axios(componentUrl)).data;
fs.writeFileSync(filePath, svg);
console.log(`✅ Created ${fileName}`);
totalIconsAdded++;
}
}

let iconsAddedPluralOrSingle = totalIconsAdded === 1 ? "icon" : "icons";

console.log(`${totalIconsAdded} ${iconsAddedPluralOrSingle} added`);

// Delete old SVG files that are no longer used
for (const componentName of existingComponentNames) {
const fileName = `${componentName}.svg`;
const filePath = path.join(__dirname, "src/svgs", fileName);
fs.unlinkSync(filePath);
console.log(`❌ Removed ${fileName}`);
totalIconsRemoved++;
}
let iconsRemovedPluralOrSingle = totalIconsRemoved === 1 ? "icon" : "icons";
console.log(`${totalIconsRemoved} ${iconsRemovedPluralOrSingle} removed`);
})();
});

This is the component set I am trying to get. So the final outputs could be named as such error-outlined-24.svg



s


Additonally this works to get the name but the output is a URL for the image


const fs = require("fs");
require("dotenv").config();

// the api key stored in .env
const figmaApiKey = process.env.FIGMA_API_KEY;
// the doc id stored in .env
const figmaDocId = process.env.FIGMA_DOC_ID;

// set up the API endpoint URL and your personal access token
const apiUrl = "https://api.figma.com/v1";

// set up the file key for the file you want to access
const fileKey = process.env.FIGMA_DOC_ID;

// make the API request to get the file
axios
.get(`${apiUrl}/files/${fileKey}`, {
headers: {
"X-Figma-Token": process.env.FIGMA_API_KEY,
},
})
.then((response) => {
// get the root node of the file
const rootNode = response.data.document;

// recursively list out all the child nodes of the root node
listNodes(rootNode);
})
.catch((error) => {
console.log(error);
});

// recursive function to list out all the child nodes of a given node
function listNodes(node) {
// check if the node has any children
if (node.children) {
// loop through each child node
node.children.forEach((child) => {
// check if the child is a ComponentSet
if (child.type === "COMPONENT_SET") {
// loop through each child of the ComponentSet
child.children.forEach((component) => {
// check if the child is a Component
if (component.type === "COMPONENT") {
// make the API request to get the SVG for the Component
axios
.get(
`${apiUrl}/images/${figmaDocId}?ids=${component.id}&format=svg`,

{
headers: {
"X-Figma-Token": figmaApiKey,
},
responseType: "text",
}
)
.then((response) => {
// get the SVG path from the response
const svgPath = JSON.parse(response.data).imagesa
`${component.id}`
];

// save the SVG path to a file
const fileName = `./src/svgs/${child.name}-${component.name}.svg`;
fs.writeFile(fileName, svgPath, (error) => {
if (error) {
console.log(error);
} else {
console.log(`File saved: ${fileName}`);
}
});
})
.catch((error) => {
console.log(error);
});
}
});
} else {
// recursively call this function on each child node
listNodes(child);
}
});
}
}

I believe all you need here is componentNode.parent.name.


I tried that and it is getting an error, this works though:


const axios = require("axios");
const fs = require("fs");
require("dotenv").config();
const path = require("path");

// the api key stored in .env
const figmaApiKey = process.env.FIGMA_API_KEY;
// the doc id stored in .env
const figmaDocId = process.env.FIGMA_DOC_ID;

// set up the API endpoint URL and your personal access token
const apiUrl = "https://api.figma.com/v1";

// set up the file key for the file you want to access
const fileKey = process.env.FIGMA_DOC_ID;

// make the API request to get the file
axios
.get(`${apiUrl}/files/${fileKey}`, {
headers: {
"X-Figma-Token": process.env.FIGMA_API_KEY,
},
})
.then((response) => {
// get the root node of the file
const rootNode = response.data.document;

// recursively list out all the child nodes of the root node
listNodes(rootNode);
})
.catch((error) => {
console.log(error);
});

// recursive function to list out all the child nodes of a given node
function listNodes(node, componentName) {
// check if the node has any children
if (node.children) {
// loop through each child node
node.children.forEach((child) => {
// check if the child is a ComponentSet
if (child.type === "COMPONENT_SET") {
// update the componentName variable
componentName = child.name;
// recursively list out all the child nodes of the ComponentSet
listNodes(child, componentName);
} else if (child.type === "COMPONENT") {
// make the API request to get the image URL for the Component
axios
.get(`${apiUrl}/images/${figmaDocId}?ids=${child.id}&format=svg`, {
headers: {
"X-Figma-Token": figmaApiKey,
},
})
.then((response) => {
// extract the image URL from the response
const imageUrl = response.data.images[child.id];
// make another API request to get the SVG data
axios
.get(imageUrl)
.then((response) => {
const componentNameFormatted = componentName
.toLowerCase()
.replace(/\s+/g, "-");

const childNameFormatted = child.name
.split(",")
.map((arg) => arg.split("=")[1])
.join("-");
// create the file name in the desired format
const fileName = `${componentNameFormatted}-${childNameFormatted}.svg`;
const filePath = path.join(__dirname, "src/svgs", fileName);
fs.writeFile(filePath, response.data, (error) => {
if (error) {
console.log(error);
} else {
console.log(`✅ Created ${fileName}`);
}
});
})
.catch((error) => {
console.log(error);
});
})
.catch((error) => {
console.log(error);
});
} else {
// recursively list out all the child nodes of the current node
listNodes(child, componentName);
}
});
}
}

function formatFileName(name) {
const args = name.split(",");
const formattedArgs = args.map((arg) => arg.split("=")"1]);
return formattedArgs.join("-").toLowerCase();
}


i understand now. yeah, parent isnt going to exist on nodes as an attribute in this case. you’ll want to provide any relevant parent info as arguments to your recursive function like you are here.