You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

generate.ts 3.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. import Rectangle from './rectangle'
  2. import Ellipse from './ellipse'
  3. import Polyline from './polyline'
  4. import Dot from './dot'
  5. import Ray from './ray'
  6. import Line from './line'
  7. import Arrow from './arrow'
  8. import Draw from './draw'
  9. import Text from './text'
  10. import Utils from './utils'
  11. import Vec from 'utils/vec'
  12. import {
  13. NumberControl,
  14. VectorControl,
  15. TextControl,
  16. codeControls,
  17. controls,
  18. } from './control'
  19. import { codeShapes } from './index'
  20. import {
  21. CodeControl,
  22. Data,
  23. Shape,
  24. DashStyle,
  25. ColorStyle,
  26. FontSize,
  27. SizeStyle,
  28. CodeError,
  29. } from 'types'
  30. import tld from 'utils/tld'
  31. import { transform } from 'sucrase'
  32. import { getErrorWithLineAndColumn, getFormattedCode } from 'utils/code'
  33. const baseScope = {
  34. Dot,
  35. Ellipse,
  36. Ray,
  37. Line,
  38. Polyline,
  39. Rectangle,
  40. Vec,
  41. Utils,
  42. Arrow,
  43. Draw,
  44. Text,
  45. TextControl,
  46. VectorControl,
  47. NumberControl,
  48. DashStyle,
  49. ColorStyle,
  50. SizeStyle,
  51. FontSize,
  52. }
  53. /**
  54. * Evaluate code, collecting generated shapes in the shape set. Return the
  55. * collected shapes as an array.
  56. * @param code
  57. */
  58. export async function generateFromCode(
  59. data: Data,
  60. code: string
  61. ): Promise<{
  62. shapes: Shape[]
  63. controls: CodeControl[]
  64. error: CodeError
  65. }> {
  66. codeControls.clear()
  67. codeShapes.clear()
  68. ;(window as any).isUpdatingCode = false
  69. ;(window as any).currentPageId = data.currentPageId
  70. const { currentPageId } = data
  71. const scope = { ...baseScope, controls, currentPageId }
  72. let generatedShapes: Shape[] = []
  73. let generatedControls: CodeControl[] = []
  74. let error: CodeError | null = null
  75. try {
  76. const formattedCode = getFormattedCode(code)
  77. const transformedCode = transform(formattedCode, {
  78. transforms: ['typescript'],
  79. })?.code
  80. new Function(...Object.keys(scope), `${transformedCode}`)(
  81. ...Object.values(scope)
  82. )
  83. const startingChildIndex =
  84. tld
  85. .getShapes(data)
  86. .filter((shape) => shape.parentId === data.currentPageId)
  87. .sort((a, b) => a.childIndex - b.childIndex)[0]?.childIndex || 1
  88. generatedShapes = Array.from(codeShapes.values())
  89. .sort((a, b) => a.shape.childIndex - b.shape.childIndex)
  90. .map((instance, i) => ({
  91. ...instance.shape,
  92. isGenerated: true,
  93. parentId: tld.getPage(data).id,
  94. childIndex: startingChildIndex + i,
  95. }))
  96. generatedControls = Array.from(codeControls.values())
  97. } catch (e) {
  98. error = getErrorWithLineAndColumn(e)
  99. }
  100. return { shapes: generatedShapes, controls: generatedControls, error }
  101. }
  102. /**
  103. * Evaluate code, collecting generated shapes in the shape set. Return the
  104. * collected shapes as an array.
  105. * @param code
  106. */
  107. export async function updateFromCode(
  108. data: Data,
  109. code: string
  110. ): Promise<{
  111. shapes: Shape[]
  112. }> {
  113. codeShapes.clear()
  114. ;(window as any).isUpdatingCode = true
  115. ;(window as any).currentPageId = data.currentPageId
  116. const { currentPageId } = data
  117. const newControls = Object.fromEntries(
  118. Object.entries(data.codeControls).map(([_, control]) => [
  119. control.label,
  120. control.value,
  121. ])
  122. )
  123. const scope = {
  124. ...baseScope,
  125. currentPageId,
  126. controls: newControls,
  127. }
  128. const startingChildIndex =
  129. tld
  130. .getShapes(data)
  131. .filter((shape) => shape.parentId === data.currentPageId)
  132. .sort((a, b) => a.childIndex - b.childIndex)[0]?.childIndex || 1
  133. const transformed = transform(code, {
  134. transforms: ['typescript'],
  135. }).code
  136. new Function(...Object.keys(scope), `${transformed}`)(...Object.values(scope))
  137. const generatedShapes = Array.from(codeShapes.values())
  138. .sort((a, b) => a.shape.childIndex - b.shape.childIndex)
  139. .map((instance, i) => ({
  140. ...instance.shape,
  141. isGenerated: true,
  142. parentId: tld.getPage(data).id,
  143. childIndex: startingChildIndex + i,
  144. }))
  145. return { shapes: generatedShapes }
  146. }