Skip to main content
Question

How to get the COMPONENT_SET name from the COMPONENT node?


Josh_Cusick93

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).images[
                  `${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);
      }
    });
  }
}
This topic has been closed for comments

3 replies

jak_e
Figmate
  • Figmate
  • 28 replies
  • April 19, 2023

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


Josh_Cusick93

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();
}


jak_e
Figmate
  • Figmate
  • 28 replies
  • April 19, 2023

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.


Cookie policy

We use cookies to enhance and personalize your experience. If you accept you agree to our full cookie policy. Learn more about our cookies.

 
Cookie settings