From 3426d4311deec5a50af51284ddddb2cf05c82595 Mon Sep 17 00:00:00 2001 From: Stefano Magni Date: Sun, 31 Mar 2024 14:57:13 +0200 Subject: [PATCH] Execute functions and await promises (#6) --- README.md | 2 ++ manifest.json | 17 +++++++++- src/components/fields.tsx | 12 +++++++ src/core/createSelectAndInspect.ts | 13 +++++--- src/core/processCurrentSelection.ts | 50 +++++++++++++++++++++-------- src/main.ts | 1 + src/types.ts | 9 ++++-- src/ui.tsx | 10 ++++++ src/utils/generic.ts | 4 +++ 9 files changed, 98 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index ba484cc..ab56c8d 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,8 @@ This plugin aims to solve this problem by making logging as easy as possible! 1. Select one or more Figma elements to get them logged in the Console 2. Add expressions to be evaluated on the selected Figma elements (`name,id,reactions[0].actions` results in each expression to be evaluated and logged in the Console) + - And if the value is a function, invoke it + - And if the returned value is a promise, await it 3. Stringy and format the result for better readability 4. Preferences are stored locally diff --git a/manifest.json b/manifest.json index 8ee5366..391b81d 100644 --- a/manifest.json +++ b/manifest.json @@ -1 +1,16 @@ -{ "api": "1.0.0", "editorType": ["figma"], "id": "1348339696557868933", "name": "Select and Inspect", "main": "build/main.js", "ui": "build/ui.js", "networkAccess": { "allowedDomains": ["none"] }, "documentAccess": "dynamic-page" } +{ + "api": "1.0.0", + "editorType": [ + "figma" + ], + "id": "1348339696557868933", + "name": "Select and Inspect", + "main": "build/main.js", + "ui": "build/ui.js", + "networkAccess": { + "allowedDomains": [ + "none" + ] + }, + "documentAccess": "dynamic-page" +} diff --git a/src/components/fields.tsx b/src/components/fields.tsx index 0b29877..f203b32 100644 --- a/src/components/fields.tsx +++ b/src/components/fields.tsx @@ -80,3 +80,15 @@ export function FormatStringifiedEvaluatedExpressions({ defaultValue, onChange } ) } + +export function ExecuteFunctionsAndAwaitPromises({ defaultValue, onChange }: { defaultValue: boolean; onChange: (newValue: boolean) => void }) { + const [value, setValue] = useState(defaultValue) + + useOnChange(value, onChange) + + return ( + + Execute functions and await promises + + ) +} diff --git a/src/core/createSelectAndInspect.ts b/src/core/createSelectAndInspect.ts index 9ffe5a0..2bd46bf 100644 --- a/src/core/createSelectAndInspect.ts +++ b/src/core/createSelectAndInspect.ts @@ -4,7 +4,7 @@ import type { CreateFigmaPluginEmit, CreateFigmaPluginShowUI, FigmaPluginApi, Lo import { createAreReferencesChanged } from '../utils/areReferencesChanged' import { processCurrentSelection } from './processCurrentSelection' -const uiOptions = { width: 480, height: 260 } as const +const uiOptions = { width: 480, height: 290 } as const interface Params { configuration: LogOptions @@ -69,6 +69,11 @@ export function createSelectAndInspect(params: Params) { break } + case 'hideExpressionErrorsChanged': + currentConfiguration.hideExpressionErrors = event.value + logChange('Hide evaluated expressions errors changed') + break + case 'expressionsToEvaluateChanged': currentConfiguration.expressionsToEvaluate = event.value logChange('Expressions to evaluate changed') @@ -79,9 +84,9 @@ export function createSelectAndInspect(params: Params) { logChange('Stringify evaluated expressions changed') break - case 'hideExpressionErrorsChanged': - currentConfiguration.hideExpressionErrors = event.value - logChange('Hide evaluated expressions errors changed') + case 'executeFunctionsAndAwaitPromisesChanged': + currentConfiguration.executeFunctionsAndAwaitPromises = event.value + logChange('Execute functions and await promises changed') break case 'formatStringifiedEvaluatedExpressionsChanged': diff --git a/src/core/processCurrentSelection.ts b/src/core/processCurrentSelection.ts index 81edc94..5304f9e 100644 --- a/src/core/processCurrentSelection.ts +++ b/src/core/processCurrentSelection.ts @@ -1,29 +1,42 @@ import { logExpression, logExpressionError, logStringifiedExpression } from '../utils/loggers' -import { stringifiedValueIsTheSame, stringifyError } from '../utils/generic' +import { isPromise, stringifiedValueIsTheSame, stringifyError } from '../utils/generic' import type { LogOptions } from '../types' -export function processCurrentSelection(selection: ReadonlyArray, configuration: LogOptions) { - processItems( +export async function processCurrentSelection(selection: ReadonlyArray, configuration: LogOptions) { + await processItems( selection, configuration, ) } -function processItems(items: readonly unknown[], logOptions: LogOptions) { +async function processItems(items: readonly unknown[], logOptions: LogOptions) { for (const item of items) { - processItem( + await processItem( item, logOptions, ) } } -function evaluateExpression(item: unknown, expression: string) { +function evaluateExpression(item: unknown, expression: string, options: { invokeFunctions: boolean }) { + const { invokeFunctions } = options // eslint-disable-next-line no-new-func - return new Function('obj', `return obj.${expression}`)(item) + return new Function('obj', ` + function evaluator(obj) { + let value = obj.${expression} + + if(typeof value === 'function' && ${invokeFunctions}) { + return obj.${expression}() + } + + return value + } + + return evaluator(obj) +`)(item) } -function processItem(item: unknown, logOptions: LogOptions) { +async function processItem(item: unknown, logOptions: LogOptions) { console.log(item) const expressions = logOptions.expressionsToEvaluate.split(',') @@ -32,23 +45,34 @@ function processItem(item: unknown, logOptions: LogOptions) { const trimmedExpression = expression.trim() if (expression === '') continue - processExpression(item, trimmedExpression, logOptions) + await processExpression(item, trimmedExpression, logOptions) } } -function processExpression( +async function processExpression( item: unknown, expression: string, logOptions: LogOptions, ) { - const { stringifyEvaluatedExpressions, hideExpressionErrors, formatStringifiedEvaluatedExpressions } = logOptions + const { stringifyEvaluatedExpressions, hideExpressionErrors, formatStringifiedEvaluatedExpressions, executeFunctionsAndAwaitPromises } = logOptions let value let stringifiedValue = '' let errored = false try { - value = evaluateExpression(item, expression) - logExpression(expression, value) + value = evaluateExpression(item, expression, { invokeFunctions: executeFunctionsAndAwaitPromises }) + if (executeFunctionsAndAwaitPromises) { + if (isPromise(value)) { + const resolvedValue = await value + logExpression(expression, resolvedValue) + } + else { + logExpression(expression, value) + } + } + else { + logExpression(expression, value) + } } catch (e) { errored = true diff --git a/src/main.ts b/src/main.ts index af7ee9b..26fc6b8 100644 --- a/src/main.ts +++ b/src/main.ts @@ -8,6 +8,7 @@ const defaultConfiguration: LogOptions = { expressionsToEvaluate: '', hideExpressionErrors: false, stringifyEvaluatedExpressions: false, + executeFunctionsAndAwaitPromises: false, formatStringifiedEvaluatedExpressions: false, } diff --git a/src/types.ts b/src/types.ts index 61c7e46..a1c6d67 100644 --- a/src/types.ts +++ b/src/types.ts @@ -25,6 +25,7 @@ export const logOptionsSchema = z.object({ expressionsToEvaluate: z.string(), hideExpressionErrors: z.boolean(), stringifyEvaluatedExpressions: z.boolean(), + executeFunctionsAndAwaitPromises: z.boolean(), formatStringifiedEvaluatedExpressions: z.boolean(), }) @@ -37,6 +38,10 @@ export const uiEventSchema = z.union([ type: z.literal('enabledChanged'), value: z.boolean(), }), + z.object({ + type: z.literal('hideExpressionErrorsChanged'), + value: z.boolean(), + }), z.object({ type: z.literal('expressionsToEvaluateChanged'), value: z.string(), @@ -46,11 +51,11 @@ export const uiEventSchema = z.union([ value: z.boolean(), }), z.object({ - type: z.literal('formatStringifiedEvaluatedExpressionsChanged'), + type: z.literal('executeFunctionsAndAwaitPromisesChanged'), value: z.boolean(), }), z.object({ - type: z.literal('hideExpressionErrorsChanged'), + type: z.literal('formatStringifiedEvaluatedExpressionsChanged'), value: z.boolean(), }), ]) diff --git a/src/ui.tsx b/src/ui.tsx index ef9b15a..f702bf8 100644 --- a/src/ui.tsx +++ b/src/ui.tsx @@ -17,6 +17,7 @@ import { type UiEvent, logOptionsSchema, serverEventSchema } from './types' import { EnabledDisabled, + ExecuteFunctionsAndAwaitPromises, ExpressionsToEvaluate, FormatStringifiedEvaluatedExpressions, HideExpressionErrors, @@ -97,6 +98,8 @@ function UI({ configuration }: { configuration: unknown }) { emit('uiEvent', event) }} /> + + { @@ -104,6 +107,13 @@ function UI({ configuration }: { configuration: unknown }) { emit('uiEvent', event) }} /> + { + const event: UiEvent = { type: 'executeFunctionsAndAwaitPromisesChanged', value } + emit('uiEvent', event) + }} + />