Skip to content

Commit

Permalink
Execute functions and await promises (#6)
Browse files Browse the repository at this point in the history
  • Loading branch information
NoriSte authored Mar 31, 2024
1 parent ad285c5 commit 3426d43
Show file tree
Hide file tree
Showing 9 changed files with 98 additions and 20 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
17 changes: 16 additions & 1 deletion manifest.json
Original file line number Diff line number Diff line change
@@ -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"
}
12 changes: 12 additions & 0 deletions src/components/fields.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,15 @@ export function FormatStringifiedEvaluatedExpressions({ defaultValue, onChange }
</Checkbox>
)
}

export function ExecuteFunctionsAndAwaitPromises({ defaultValue, onChange }: { defaultValue: boolean; onChange: (newValue: boolean) => void }) {
const [value, setValue] = useState(defaultValue)

useOnChange(value, onChange)

return (
<Checkbox onValueChange={setValue} value={value}>
<Text>Execute functions and await promises</Text>
</Checkbox>
)
}
13 changes: 9 additions & 4 deletions src/core/createSelectAndInspect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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')
Expand All @@ -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':
Expand Down
50 changes: 37 additions & 13 deletions src/core/processCurrentSelection.ts
Original file line number Diff line number Diff line change
@@ -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<SceneNode>, configuration: LogOptions) {
processItems(
export async function processCurrentSelection(selection: ReadonlyArray<SceneNode>, 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(',')
Expand All @@ -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
Expand Down
1 change: 1 addition & 0 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const defaultConfiguration: LogOptions = {
expressionsToEvaluate: '',
hideExpressionErrors: false,
stringifyEvaluatedExpressions: false,
executeFunctionsAndAwaitPromises: false,
formatStringifiedEvaluatedExpressions: false,
}

Expand Down
9 changes: 7 additions & 2 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export const logOptionsSchema = z.object({
expressionsToEvaluate: z.string(),
hideExpressionErrors: z.boolean(),
stringifyEvaluatedExpressions: z.boolean(),
executeFunctionsAndAwaitPromises: z.boolean(),
formatStringifiedEvaluatedExpressions: z.boolean(),
})

Expand All @@ -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(),
Expand All @@ -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(),
}),
])
Expand Down
10 changes: 10 additions & 0 deletions src/ui.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { type UiEvent, logOptionsSchema, serverEventSchema } from './types'

import {
EnabledDisabled,
ExecuteFunctionsAndAwaitPromises,
ExpressionsToEvaluate,
FormatStringifiedEvaluatedExpressions,
HideExpressionErrors,
Expand Down Expand Up @@ -97,13 +98,22 @@ function UI({ configuration }: { configuration: unknown }) {
emit('uiEvent', event)
}}
/>
</Columns>
<Columns space="extraLarge">
<FormatStringifiedEvaluatedExpressions
defaultValue={configurationRef.current.formatStringifiedEvaluatedExpressions}
onChange={(value) => {
const event: UiEvent = { type: 'formatStringifiedEvaluatedExpressionsChanged', value }
emit('uiEvent', event)
}}
/>
<ExecuteFunctionsAndAwaitPromises
defaultValue={configurationRef.current.executeFunctionsAndAwaitPromises}
onChange={(value) => {
const event: UiEvent = { type: 'executeFunctionsAndAwaitPromisesChanged', value }
emit('uiEvent', event)
}}
/>
</Columns>

<Button
Expand Down
4 changes: 4 additions & 0 deletions src/utils/generic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,7 @@ export function isEmptyArray(value: unknown) {
Array.isArray(value) && value.length === 0
)
}

export function isPromise(obj: unknown) {
return !!obj && (typeof obj === 'object' || typeof obj === 'function') && 'then' in obj && typeof obj.then === 'function'
}

0 comments on commit 3426d43

Please sign in to comment.