Skip to content

Commit

Permalink
rewrote design lint to use a generator function and cleaned up additi…
Browse files Browse the repository at this point in the history
…onal lint function calls
  • Loading branch information
Daniel Destefanis committed Apr 3, 2023
1 parent 0a76f77 commit 4bcdef5
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 60 deletions.
60 changes: 25 additions & 35 deletions src/app/components/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -119,13 +119,6 @@ const App = ({}) => {
);
};

const onRunApp = React.useCallback(() => {
parent.postMessage(
{ pluginMessage: { type: "run-app", lintVectors: lintVectors } },
"*"
);
}, []);

function updateVisibility() {
if (isVisible === true) {
setIsVisible(false);
Expand Down Expand Up @@ -155,32 +148,21 @@ const App = ({}) => {
}
}, [ignoredErrorArray]);

const onRunApp = React.useCallback(() => {
parent.postMessage(
{ pluginMessage: { type: "run-app", lintVectors: lintVectors } },
"*"
);
}, []);

React.useEffect(() => {
onRunApp();

window.onmessage = event => {
const { type, message, errors, storage } = event.data.pluginMessage;

// Plugin code returns this message after we return the first node
// for performance, then we lint the remaining layers.
if (type === "complete") {
let nodeObject = JSON.parse(message);

updateErrorArray(errors);

parent.postMessage(
{
pluginMessage: {
type: "fetch-layer-data",
id: nodeObject[0].id,
nodeArray: nodeObject
}
},
"*"
);

setInitialLoad(true);
} else if (type === "first node") {
if (type === "step-1") {
// Lint the very first selected node.
let nodeObject = JSON.parse(message);

setNodeArray(nodeObject);
Expand All @@ -196,28 +178,36 @@ const App = ({}) => {
return activeNodeIds.concat(nodeObject[0].id);
});

// After we have the first node, we want to
// lint the remaining selection.
// Fetch the properties of the first layers within our selection
// And select them in Figma.
parent.postMessage(
{
pluginMessage: {
type: "lint-all",
nodes: nodeObject
type: "step-2",
id: nodeObject[0].id,
nodeArray: nodeObject
}
},
"*"
);
} else if (type === "step-2-complete") {
// Grabs the properties of the first layer to display in our UI.
setSelectedNode(() => JSON.parse(message));

// After we have the first node, we want to
// lint the all the remaining nodes/layers in our original selection.
parent.postMessage(
{
pluginMessage: {
type: "fetch-layer-data",
id: nodeObject[0].id,
nodeArray: nodeObject
type: "step-3"
}
},
"*"
);
} else if (type === "step-3-complete") {
// Once all layers are linted, we update the error array.
updateErrorArray(errors);
setInitialLoad(true);
} else if (type === "fetched storage") {
let clientStorage = JSON.parse(storage);

Expand All @@ -237,7 +227,6 @@ const App = ({}) => {
setIgnoreErrorArray([]);
parent.postMessage({ pluginMessage: { type: "update-errors" } }, "*");
} else if (type === "fetched layer") {
// Grabs the properties of the first layer.
setSelectedNode(() => JSON.parse(message));

// Ask the controller to lint the layers for errors.
Expand Down Expand Up @@ -286,6 +275,7 @@ const App = ({}) => {
ignoredErrors={ignoredErrorArray}
onClick={updateVisibility}
onSelectedListUpdate={updateSelectedList}
initialLoad={initialLoad}
/>
)}
</div>
Expand Down
93 changes: 68 additions & 25 deletions src/plugin/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ const documentUUID = getDocumentUUID();

figma.on("documentchange", _event => {
// When a change happens in the document
// send a message to the plugin to look for changes.
// send a message to the plugin to look for changes.'
figma.ui.postMessage({
type: "change"
});
Expand All @@ -56,6 +56,54 @@ figma.ui.onmessage = msg => {
figma.closePlugin();
}

if (msg.type === "step-2") {
let layer = figma.getNodeById(msg.id);
let layerArray = [];

// Using figma UI selection and scroll to viewport requires an array.
layerArray.push(layer);

// Moves the layer into focus and selects so the user can update it.
// uncomment the line below if you want to notify something has been selected.
// figma.notify(`Layer ${layer.name} selected`, { timeout: 750 });
figma.currentPage.selection = layerArray;
figma.viewport.scrollAndZoomIntoView(layerArray);

let layerData = JSON.stringify(layer, [
"id",
"name",
"description",
"fills",
"key",
"type",
"remote",
"paints",
"fontName",
"fontSize",
"font"
]);

figma.ui.postMessage({
type: "step-2-complete",
message: layerData
});
}

// if (msg.type === "step-3") {
// // Pass the array back to the UI to be displayed.
// figma.ui.postMessage({
// type: "step-3-complete",
// errors: lint(originalNodeTree),
// message: serializeNodes(originalNodeTree),
// });

// console.log('step 3 complete, legacy lint');

// figma.notify(`Design lint is running and will auto refresh for changes`, {
// timeout: 2000
// });
// }

// Fetch a specific node by ID.
if (msg.type === "fetch-layer-data") {
let layer = figma.getNodeById(msg.id);
Expand Down Expand Up @@ -90,7 +138,8 @@ figma.ui.onmessage = msg => {
});
}

// Could this be made less expensive?
// Called when an update in the Figma file happens
// so we can check what changed.
if (msg.type === "update-errors") {
figma.ui.postMessage({
type: "updated errors",
Expand Down Expand Up @@ -206,6 +255,7 @@ figma.ui.onmessage = msg => {
for (const node of nodes) {
// Determine if the layer or its parent is locked.
const isLayerLocked = lockedParentNode || node.locked;
const nodeChildren = node.children;

// Create a new object.
const newObject = {
Expand All @@ -215,7 +265,7 @@ figma.ui.onmessage = msg => {
};

// Check if the node has children.
if (node.children) {
if (nodeChildren) {
// Recursively run this function to flatten out children and grandchildren nodes.
newObject.children = node.children.map(childNode => childNode.id);
errorArray.push(...lint(node.children, isLayerLocked));
Expand All @@ -227,29 +277,17 @@ figma.ui.onmessage = msg => {
return errorArray;
}

// if (msg.type === "lint-all") {
// // Pass the array back to the UI to be displayed.
// figma.ui.postMessage({
// type: "complete",
// errors: lint(originalNodeTree),
// message: serializeNodes(msg.nodes)
// });

// figma.notify(`Design lint is running and will auto refresh for changes`, {
// timeout: 2000
// });
// }

// Generator explorations
function delay(time) {
return new Promise(resolve => setTimeout(resolve, time));
}

// Counter to keep track of the total number of processed nodes
let nodeCounter = 0;

async function* lintAsync(nodes, lockedParentNode = false) {
let errorArray = [];

for (let i = 0; i < nodes.length; i++) {
const node = nodes[i];
for (const node of nodes) {
// Determine if the layer or its parent is locked.
const isLayerLocked = lockedParentNode || node.locked;

Expand All @@ -271,11 +309,16 @@ figma.ui.onmessage = msg => {

errorArray.push(newObject);

// Increment the node counter
nodeCounter++;
console.log(nodeCounter);

// Yield the result after processing a certain number of nodes
if (i % 100 === 0) {
if (nodeCounter % 2000 === 0) {
console.log("yield");
yield errorArray;
errorArray = [];
await delay(40); // Pause for 40ms every 100 items to allow UI to update
await delay(0);
}
}

Expand All @@ -285,7 +328,7 @@ figma.ui.onmessage = msg => {
}
}

if (msg.type === "lint-all") {
if (msg.type === "step-3") {
// Use an async function to handle the asynchronous generator
async function processLint() {
const finalResult = [];
Expand All @@ -295,9 +338,9 @@ figma.ui.onmessage = msg => {

// Pass the final result back to the UI to be displayed.
figma.ui.postMessage({
type: "complete",
type: "step-3-complete",
errors: finalResult,
message: serializeNodes(msg.nodes)
message: serializeNodes(originalNodeTree)
});

figma.notify(`Scan Complete`, {
Expand Down Expand Up @@ -331,7 +374,7 @@ figma.ui.onmessage = msg => {
// We want to immediately render the first selection
// to avoid freezing up the UI.
figma.ui.postMessage({
type: "first node",
type: "step-1",
message: serializeNodes(nodes),
errors: lint(firstNode)
});
Expand Down

0 comments on commit 4bcdef5

Please sign in to comment.