tldraw/state/code/generate.ts

165 lines
3.7 KiB
TypeScript
Raw Normal View History

2021-06-08 10:32:20 +00:00
import Rectangle from './rectangle'
import Ellipse from './ellipse'
import Polyline from './polyline'
import Dot from './dot'
import Ray from './ray'
import Line from './line'
2021-06-23 22:32:21 +00:00
import Arrow from './arrow'
import Draw from './draw'
import Text from './text'
2021-06-08 10:32:20 +00:00
import Utils from './utils'
2021-06-23 22:32:21 +00:00
import Vec from 'utils/vec'
2021-06-27 13:53:06 +00:00
import {
NumberControl,
VectorControl,
TextControl,
codeControls,
controls,
} from './control'
2021-06-08 10:32:20 +00:00
import { codeShapes } from './index'
import {
CodeControl,
Data,
Shape,
DashStyle,
ColorStyle,
2021-06-25 12:21:33 +00:00
FontSize,
SizeStyle,
CodeError,
} from 'types'
import { getPage, getShapes } from 'utils'
2021-06-24 14:59:56 +00:00
import { transform } from 'sucrase'
import { getErrorWithLineAndColumn, getFormattedCode } from 'utils/code'
2021-05-15 13:02:13 +00:00
2021-05-17 10:01:11 +00:00
const baseScope = {
2021-05-16 08:33:08 +00:00
Dot,
Ellipse,
Ray,
Line,
Polyline,
Rectangle,
2021-06-23 22:32:21 +00:00
Vec,
2021-05-16 08:33:08 +00:00
Utils,
2021-06-23 22:32:21 +00:00
Arrow,
Draw,
Text,
2021-06-27 13:53:06 +00:00
TextControl,
2021-05-17 10:01:11 +00:00
VectorControl,
NumberControl,
DashStyle,
ColorStyle,
SizeStyle,
2021-06-25 12:21:33 +00:00
FontSize,
2021-05-16 08:33:08 +00:00
}
2021-05-15 13:02:13 +00:00
/**
* Evaluate code, collecting generated shapes in the shape set. Return the
* collected shapes as an array.
* @param code
*/
export async function generateFromCode(
2021-06-21 21:35:28 +00:00
data: Data,
code: string
): Promise<{
2021-06-21 21:35:28 +00:00
shapes: Shape[]
controls: CodeControl[]
error: CodeError
}> {
2021-05-17 10:01:11 +00:00
codeControls.clear()
2021-05-15 13:02:13 +00:00
codeShapes.clear()
2021-05-17 10:01:11 +00:00
;(window as any).isUpdatingCode = false
2021-06-08 10:32:20 +00:00
;(window as any).currentPageId = data.currentPageId
2021-05-17 10:01:11 +00:00
2021-06-08 10:32:20 +00:00
const { currentPageId } = data
const scope = { ...baseScope, controls, currentPageId }
2021-05-17 10:01:11 +00:00
let generatedShapes: Shape[] = []
let generatedControls: CodeControl[] = []
let error: CodeError | null = null
2021-06-24 14:59:56 +00:00
try {
const formattedCode = getFormattedCode(code)
2021-05-17 10:01:11 +00:00
const transformedCode = transform(formattedCode, {
transforms: ['typescript'],
})?.code
new Function(...Object.keys(scope), `${transformedCode}`)(
...Object.values(scope)
)
2021-05-17 10:01:11 +00:00
const startingChildIndex =
getShapes(data)
.filter((shape) => shape.parentId === data.currentPageId)
.sort((a, b) => a.childIndex - b.childIndex)[0]?.childIndex || 1
2021-05-17 10:01:11 +00:00
generatedShapes = Array.from(codeShapes.values())
.sort((a, b) => a.shape.childIndex - b.shape.childIndex)
.map((instance, i) => ({
...instance.shape,
isGenerated: true,
parentId: getPage(data).id,
childIndex: startingChildIndex + i,
}))
generatedControls = Array.from(codeControls.values())
} catch (e) {
error = getErrorWithLineAndColumn(e)
}
return { shapes: generatedShapes, controls: generatedControls, error }
2021-05-17 10:01:11 +00:00
}
/**
* Evaluate code, collecting generated shapes in the shape set. Return the
* collected shapes as an array.
* @param code
*/
export async function updateFromCode(
2021-06-21 21:35:28 +00:00
data: Data,
code: string
): Promise<{
2021-06-21 21:35:28 +00:00
shapes: Shape[]
}> {
2021-05-17 10:01:11 +00:00
codeShapes.clear()
;(window as any).isUpdatingCode = true
2021-06-08 10:32:20 +00:00
;(window as any).currentPageId = data.currentPageId
const { currentPageId } = data
2021-05-17 10:01:11 +00:00
const newControls = Object.fromEntries(
Object.entries(data.codeControls).map(([_, control]) => [
control.label,
control.value,
])
)
2021-05-17 10:01:11 +00:00
const scope = {
...baseScope,
2021-06-08 10:32:20 +00:00
currentPageId,
controls: newControls,
2021-05-17 10:01:11 +00:00
}
2021-05-15 13:02:13 +00:00
const startingChildIndex =
getShapes(data)
.filter((shape) => shape.parentId === data.currentPageId)
.sort((a, b) => a.childIndex - b.childIndex)[0]?.childIndex || 1
2021-05-15 13:02:13 +00:00
const transformed = transform(code, {
transforms: ['typescript'],
}).code
new Function(...Object.keys(scope), `${transformed}`)(...Object.values(scope))
const generatedShapes = Array.from(codeShapes.values())
.sort((a, b) => a.shape.childIndex - b.shape.childIndex)
.map((instance, i) => ({
...instance.shape,
isGenerated: true,
parentId: getPage(data).id,
childIndex: startingChildIndex + i,
}))
2021-05-15 13:02:13 +00:00
2021-05-17 10:01:11 +00:00
return { shapes: generatedShapes }
2021-05-15 13:02:13 +00:00
}