IOweb/node_modules/@iconify/tools/lib/import/figma/query.mjs
2026-07-03 15:07:38 -05:00

256 lines
6.7 KiB
JavaScript

import { sendAPIQuery } from '../../download/api/index.mjs';
import { apiCacheKey, getAPICache, clearAPICache } from '../../download/api/cache.mjs';
import { runConcurrentQueries } from '../../download/api/queue.mjs';
import '../../download/api/config.mjs';
import '../../download/api/fetch.mjs';
import 'fs';
import 'crypto';
import '../../misc/scan.mjs';
function identicalDates(actual, expected) {
if (typeof actual !== "string") {
return false;
}
if (actual === expected) {
return true;
}
return new Date(actual).toString() === new Date(expected).toString();
}
async function figmaFilesQuery(options, cache) {
if (!options.token) {
throw new Error("Missing Figma API token");
}
const params = new URLSearchParams();
if (options.ids) {
params.set("ids", options.ids.join(","));
}
if (options.version) {
params.set("version", options.version);
}
if (options.depth) {
params.set("depth", options.depth.toString());
}
const queryParams = {
uri: "https://api.figma.com/v1/files/" + options.file,
params,
headers: {
"X-FIGMA-TOKEN": options.token
}
};
const isModified = async () => {
if (!cache || !options.ifModifiedSince) {
return true;
}
const cacheKey = apiCacheKey(queryParams);
const cachedData = await getAPICache(cache.dir, cacheKey);
if (!cachedData) {
return true;
}
let ifModifiedSince;
if (options.ifModifiedSince === true) {
try {
const parsedData2 = JSON.parse(cachedData);
if (typeof parsedData2.lastModified !== "string") {
await clearAPICache(cache.dir);
return true;
}
ifModifiedSince = parsedData2.lastModified;
} catch (err) {
await clearAPICache(cache.dir);
return true;
}
} else {
ifModifiedSince = options.ifModifiedSince;
}
const versionCheckParams = {
...queryParams,
params: new URLSearchParams(params)
};
versionCheckParams.params.set("depth", "1");
const data2 = await sendAPIQuery(versionCheckParams);
try {
if (typeof data2 === "string") {
const parsedData2 = JSON.parse(data2);
if (identicalDates(parsedData2.lastModified, ifModifiedSince)) {
return false;
}
}
} catch (err) {
}
await clearAPICache(cache.dir);
return true;
};
if (!await isModified()) {
return "not_modified";
}
const data = await sendAPIQuery(queryParams, cache);
if (typeof data === "number") {
throw new Error(`Error retrieving document from API: ${data}`);
}
let parsedData;
try {
parsedData = JSON.parse(data);
} catch (err) {
throw new Error(`Error retrieving document from API: invalid data`);
}
if (typeof parsedData.status === "number") {
const figmaError = parsedData;
throw new Error(
`Error retrieving document from API: ${figmaError.err}`
);
}
const document = parsedData;
if (document.editorType !== "figma") {
throw new Error(
`Error retrieving document from API: document is for ${document.editorType}`
);
}
if (identicalDates(options.ifModifiedSince, document.lastModified)) {
return "not_modified";
}
return document;
}
async function figmaImagesQuery(options, nodes, cache) {
const uri = "https://api.figma.com/v1/images/" + options.file;
const maxLength = 2048 - uri.length;
const svgOptions = options.svgOptions || {};
const query = (ids2) => {
return new Promise((resolve, reject) => {
const params = new URLSearchParams({
ids: ids2.join(","),
format: "svg"
});
if (options.version) {
params.set("version", options.version);
}
params.set(
"svg_include_id",
svgOptions.includeID ? "true" : "false"
);
params.set(
"svg_simplify_stroke",
svgOptions.simplifyStroke ? "true" : "false"
);
params.set(
"use_absolute_bounds",
svgOptions.useAbsoluteBounds ? "true" : "false"
);
sendAPIQuery(
{
uri,
params,
headers: {
"X-FIGMA-TOKEN": options.token
}
},
cache
).then((data) => {
if (typeof data === "number") {
reject(data);
return;
}
let parsedData;
try {
parsedData = JSON.parse(data);
} catch {
reject("Bad API response");
return;
}
resolve(parsedData);
}).catch(reject);
});
};
let ids = [];
let idsLength = 0;
const allKeys = Object.keys(nodes.icons);
const queue = [];
for (let i = 0; i < allKeys.length; i++) {
const id = allKeys[i];
ids.push(id);
idsLength += id.length + 1;
if (idsLength >= maxLength) {
queue.push(ids.slice(0));
ids = [];
idsLength = 0;
}
}
if (idsLength) {
queue.push(ids.slice(0));
}
const queryParams = {
// Params
total: queue.length,
callback: (index) => query(queue[index]),
// Payload to identify failed items in onfail callback
function: "figmaImagesQuery",
payload: queue
};
const results = await runConcurrentQueries(queryParams);
let found = 0;
results.forEach((data) => {
if (!data) {
return;
}
const images = data.images;
for (const id in images) {
const node = nodes.icons[id];
const target = images[id];
if (node && target) {
node.url = target;
found++;
}
}
});
if (!found) {
throw new Error("No valid icon layers were found");
}
nodes.generatedIconsCount = found;
return nodes;
}
async function figmaDownloadImages(nodes, cache) {
const icons = nodes.icons;
const ids = Object.keys(icons);
let count = 0;
const filtered = [];
for (let i = 0; i < ids.length; i++) {
const id = ids[i];
const item = icons[id];
if (item.url) {
filtered.push(item);
}
}
const params = {
// Params
total: filtered.length,
callback: (index) => {
return new Promise((resolve, reject) => {
const item = filtered[index];
sendAPIQuery(
{
uri: item.url
},
cache
).then((data) => {
if (typeof data === "string") {
count++;
item.content = data;
resolve(void 0);
} else {
reject(data);
}
}).catch(reject);
});
},
// Payload to identify failed items in onfail callback
function: "figmaDownloadImages",
payload: filtered
};
await runConcurrentQueries(params);
if (!count) {
throw new Error("Error retrieving images");
}
nodes.downloadedIconsCount = count;
return nodes;
}
export { figmaDownloadImages, figmaFilesQuery, figmaImagesQuery };