0
Fork 0
mirror of https://github.com/penpot/penpot-exporter-figma-plugin.git synced 2024-12-21 21:23:06 -05:00

Attempt to use Queues

This commit is contained in:
Jordi Sala Morales 2024-06-19 09:38:57 +00:00
parent c692b8834d
commit c49fa97dbf
No known key found for this signature in database
GPG key ID: C5127140107F55FD
8 changed files with 70 additions and 66 deletions

3
package-lock.json generated
View file

@ -12,6 +12,7 @@
"@create-figma-plugin/ui": "^3.2",
"base64-js": "^1.5",
"classnames": "^2.5",
"fastq": "^1.17.1",
"lru-cache": "^10.2",
"preact": "^10.22",
"react-hook-form": "^7.51",
@ -4821,7 +4822,6 @@
"version": "1.17.1",
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz",
"integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==",
"dev": true,
"dependencies": {
"reusify": "^1.0.4"
}
@ -7129,7 +7129,6 @@
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
"integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
"dev": true,
"engines": {
"iojs": ">=1.0.0",
"node": ">=0.10.0"

View file

@ -25,6 +25,7 @@
"@create-figma-plugin/ui": "^3.2",
"base64-js": "^1.5",
"classnames": "^2.5",
"fastq": "^1.17.1",
"lru-cache": "^10.2",
"preact": "^10.22",
"react-hook-form": "^7.51",

30
plugin-src/Queue.ts Normal file
View file

@ -0,0 +1,30 @@
import * as fastq from 'fastq';
import type { queueAsPromised } from 'fastq';
import { transformSceneNode } from '@plugin/transformers';
import { PenpotNode } from '@ui/types';
class Queue<T, R> {
private queue: queueAsPromised<T, R>;
constructor(worker: fastq.asyncWorker<unknown, T, R>, concurrency: number) {
this.queue = fastq.promise(worker, concurrency);
}
public enqueue(task: T): Promise<R> {
return this.queue.push(task);
}
public async waitIdle() {
await this.queue.drain();
}
}
export const nodeQueue = new Queue(
async ([sceneNode, position]: [SceneNode, number]): Promise<[PenpotNode | undefined, number]> => [
await transformSceneNode(sceneNode),
position
],
1
);

View file

@ -1,33 +1,27 @@
import { PenpotNode } from '@ui/types';
class RemoteComponentsLibrary {
private components: Record<string, ComponentNode | ComponentSetNode> = {};
private queue: string[] = [];
private components: PenpotNode[] = [];
private registry: Record<string, null> = {};
public register(id: string, component: ComponentNode | ComponentSetNode) {
if (!Object.prototype.hasOwnProperty.call(this.components, id)) {
this.queue.push(id);
}
this.components[id] = component;
public add(component: PenpotNode) {
this.components.push(component);
}
public get(id: string): ComponentNode | ComponentSetNode | undefined {
return this.components[id];
public register(id: string) {
this.registry[id] = null;
}
public next(): ComponentNode | ComponentSetNode {
const lastKey = this.queue.pop();
if (!lastKey) throw new Error('No components to pop');
return this.components[lastKey];
}
public remaining(): number {
return this.queue.length;
public has(id: string): boolean {
return this.registry[id] === null;
}
public total(): number {
return Object.keys(this.components).length;
return this.components.length;
}
public all(): PenpotNode[] {
return this.components;
}
}

View file

@ -1,5 +1,6 @@
import { componentsLibrary } from '@plugin/ComponentLibrary';
import { imagesLibrary } from '@plugin/ImageLibrary';
import { nodeQueue } from '@plugin/Queue';
import { remoteComponentLibrary } from '@plugin/RemoteComponentLibrary';
import { translateRemoteChildren } from '@plugin/translators';
import { sleep } from '@plugin/utils';
@ -75,10 +76,12 @@ const processPages = async (node: DocumentNode): Promise<PenpotPage[]> => {
export const transformDocumentNode = async (node: DocumentNode): Promise<PenpotDocument> => {
const children = await processPages(node);
if (remoteComponentLibrary.remaining() > 0) {
await nodeQueue.waitIdle();
if (remoteComponentLibrary.total() > 0) {
children.push({
name: 'External Components',
children: translateRemoteChildren()
children: remoteComponentLibrary.all()
});
}

View file

@ -1,4 +1,5 @@
import { overridesLibrary } from '@plugin/OverridesLibrary';
import { nodeQueue } from '@plugin/Queue';
import { remoteComponentLibrary } from '@plugin/RemoteComponentLibrary';
import {
transformAutoLayout,
@ -78,11 +79,15 @@ const getPrimaryComponent = (mainComponent: ComponentNode): ComponentNode | Comp
};
const registerExternalComponents = (primaryComponent: ComponentNode | ComponentSetNode): void => {
if (remoteComponentLibrary.get(primaryComponent.id) !== undefined) {
if (remoteComponentLibrary.has(primaryComponent.id)) {
return;
}
remoteComponentLibrary.register(primaryComponent.id, primaryComponent);
remoteComponentLibrary.register(primaryComponent.id);
nodeQueue.enqueue([primaryComponent, 0]).then(([penpotNode, _]) => {
if (penpotNode) remoteComponentLibrary.add(penpotNode);
});
};
const getComponentTextPropertyOverrides = (

View file

@ -1,8 +1,7 @@
import { remoteComponentLibrary } from '@plugin/RemoteComponentLibrary';
import { transformGroupNodeLike, transformSceneNode } from '@plugin/transformers';
import { nodeQueue } from '@plugin/Queue';
import { transformGroupNodeLike } from '@plugin/transformers';
import { transformMaskFigmaIds } from '@plugin/transformers/partials';
import { GroupShape } from '@ui/lib/types/shapes/groupShape';
import { PenpotNode } from '@ui/types';
/**
@ -17,7 +16,7 @@ import { PenpotNode } from '@ui/types';
export const translateMaskChildren = (
children: readonly SceneNode[],
maskIndex: number
): Promise<PenpotNode | undefined>[] => {
): PenpotNode[] => {
const maskChild = children[maskIndex];
const unmaskedChildren = translateChildren(children.slice(0, maskIndex));
@ -38,50 +37,23 @@ export const translateMaskChildren = (
return [...unmaskedChildren, ...maskedChildren];
}
const maskGroup = Promise.resolve<GroupShape>({
const maskGroup = {
...transformMaskFigmaIds(maskChild),
...transformGroupNodeLike(maskChild),
children: maskedChildren,
maskedGroup: true
});
};
return [...unmaskedChildren, maskGroup];
};
export const translateChildren = (
children: readonly SceneNode[]
): Promise<PenpotNode | undefined>[] => {
const transformedChildren: Promise<PenpotNode | undefined>[] = [];
export const translateChildren = (children: readonly SceneNode[]): PenpotNode[] => {
const transformedChildren: PenpotNode[] = [];
let count = 0;
for (const child of children) {
transformedChildren.push(transformSceneNode(child));
}
return transformedChildren;
};
export const translateRemoteChildren = (): Promise<PenpotNode | undefined>[] => {
const transformedChildren: Promise<PenpotNode | undefined>[] = [];
let currentRemote = 1;
figma.ui.postMessage({
type: 'PROGRESS_STEP',
data: 'remote'
});
while (remoteComponentLibrary.remaining() > 0) {
figma.ui.postMessage({
type: 'PROGRESS_TOTAL_ITEMS',
data: remoteComponentLibrary.total()
});
const child = remoteComponentLibrary.next();
transformedChildren.push(transformSceneNode(child));
figma.ui.postMessage({
type: 'PROGRESS_PROCESSED_ITEMS',
data: currentRemote++
nodeQueue.enqueue([child, count++]).then(([penpotNode, position]) => {
if (penpotNode) transformedChildren[position] = penpotNode;
});
}

View file

@ -1,3 +1,3 @@
import { PenpotNode } from '@ui/types';
export type Children = { children: Promise<PenpotNode | undefined>[] | (PenpotNode | undefined)[] };
export type Children = { children?: PenpotNode[] };