@doenet/doenetml 0.6.0-alpha1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (549) hide show
  1. package/.prettierrc +3 -0
  2. package/LICENSE +661 -0
  3. package/README.md +146 -0
  4. package/cypress/e2e/ActivityViewer/activityVariants.cy.js +1770 -0
  5. package/cypress/e2e/ActivityViewer/compiledActivity.cy.js +83 -0
  6. package/cypress/e2e/ActivityViewer/relationshipsAmongPages.cy.js +697 -0
  7. package/cypress/e2e/answerValidation/errorinnumbers.cy.js +2125 -0
  8. package/cypress/e2e/answerValidation/factoring.cy.js +1945 -0
  9. package/cypress/e2e/answerValidation/factoringOldAlgorithm.cy.js +892 -0
  10. package/cypress/e2e/answerValidation/functionanswers.cy.js +314 -0
  11. package/cypress/e2e/answerValidation/matchingpatterns.cy.js +287 -0
  12. package/cypress/e2e/answerValidation/matchpartial.cy.js +6711 -0
  13. package/cypress/e2e/answerValidation/pointlocation.cy.js +3989 -0
  14. package/cypress/e2e/answerValidation/symbolicequality.cy.js +1893 -0
  15. package/cypress/e2e/answerValidation/videoProgress.cy.js +210 -0
  16. package/cypress/e2e/assignNames/basiccopy.cy.js +2376 -0
  17. package/cypress/e2e/assignNames/collections.cy.js +9247 -0
  18. package/cypress/e2e/assignNames/selects.cy.js +105 -0
  19. package/cypress/e2e/assignNames/sequences.cy.js +1964 -0
  20. package/cypress/e2e/baseComponent/basecomponentproperties.cy.js +999 -0
  21. package/cypress/e2e/baseComponent/doenetMLtext.cy.js +427 -0
  22. package/cypress/e2e/chemistry/atom.cy.js +201 -0
  23. package/cypress/e2e/chemistry/ion.cy.js +608 -0
  24. package/cypress/e2e/chemistry/ioniccompound.cy.js +133 -0
  25. package/cypress/e2e/dynamicalsystem/cobwebpolyline.cy.js +2653 -0
  26. package/cypress/e2e/dynamicalsystem/equilibriumcurve.cy.js +311 -0
  27. package/cypress/e2e/dynamicalsystem/equilibriumline.cy.js +279 -0
  28. package/cypress/e2e/dynamicalsystem/equilibriumpoint.cy.js +283 -0
  29. package/cypress/e2e/dynamicalsystem/odesystem.cy.js +1834 -0
  30. package/cypress/e2e/equality/mathexpressions.cy.js +948 -0
  31. package/cypress/e2e/graphing/graphreferences.cy.js +978 -0
  32. package/cypress/e2e/graphing/graphreferences2.cy.js +615 -0
  33. package/cypress/e2e/linearAlgebra/eigenDecomposition.cy.js +401 -0
  34. package/cypress/e2e/tagSpecific/angle.cy.js +3898 -0
  35. package/cypress/e2e/tagSpecific/animatefromsequence.cy.js +2306 -0
  36. package/cypress/e2e/tagSpecific/answer.cy.js +31647 -0
  37. package/cypress/e2e/tagSpecific/bestfitline.cy.js +612 -0
  38. package/cypress/e2e/tagSpecific/blockquote.cy.js +30 -0
  39. package/cypress/e2e/tagSpecific/boolean.cy.js +742 -0
  40. package/cypress/e2e/tagSpecific/booleaninput.cy.js +1283 -0
  41. package/cypress/e2e/tagSpecific/booleanlist.cy.js +588 -0
  42. package/cypress/e2e/tagSpecific/booleanoperators.cy.js +596 -0
  43. package/cypress/e2e/tagSpecific/booleanoperatorsonmath.cy.js +498 -0
  44. package/cypress/e2e/tagSpecific/callaction.cy.js +2835 -0
  45. package/cypress/e2e/tagSpecific/choiceinput.cy.js +3205 -0
  46. package/cypress/e2e/tagSpecific/circle.cy.js +22036 -0
  47. package/cypress/e2e/tagSpecific/codeeditor.cy.js +1995 -0
  48. package/cypress/e2e/tagSpecific/collect.cy.js +5035 -0
  49. package/cypress/e2e/tagSpecific/componentsize.cy.js +502 -0
  50. package/cypress/e2e/tagSpecific/conditionalcontent.cy.js +3495 -0
  51. package/cypress/e2e/tagSpecific/contentBrowser.cy.js +335 -0
  52. package/cypress/e2e/tagSpecific/contentpicker.cy.js +261 -0
  53. package/cypress/e2e/tagSpecific/copy.cy.js +12627 -0
  54. package/cypress/e2e/tagSpecific/copy2.cy.js +5698 -0
  55. package/cypress/e2e/tagSpecific/curve.bezier.cy.js +12440 -0
  56. package/cypress/e2e/tagSpecific/curve.cy.js +1716 -0
  57. package/cypress/e2e/tagSpecific/curve.function.cy.js +1471 -0
  58. package/cypress/e2e/tagSpecific/curve.parametrized.cy.js +920 -0
  59. package/cypress/e2e/tagSpecific/document.cy.js +234 -0
  60. package/cypress/e2e/tagSpecific/endpoint.cy.js +197 -0
  61. package/cypress/e2e/tagSpecific/evaluate.cy.js +8895 -0
  62. package/cypress/e2e/tagSpecific/extract.cy.js +2282 -0
  63. package/cypress/e2e/tagSpecific/feedback.cy.js +2941 -0
  64. package/cypress/e2e/tagSpecific/function.cy.js +9450 -0
  65. package/cypress/e2e/tagSpecific/functioniterates.cy.js +1178 -0
  66. package/cypress/e2e/tagSpecific/functionoperators.cy.js +4047 -0
  67. package/cypress/e2e/tagSpecific/graph.cy.js +2491 -0
  68. package/cypress/e2e/tagSpecific/group.cy.js +683 -0
  69. package/cypress/e2e/tagSpecific/hint.cy.js +204 -0
  70. package/cypress/e2e/tagSpecific/image.cy.js +770 -0
  71. package/cypress/e2e/tagSpecific/integer.cy.js +206 -0
  72. package/cypress/e2e/tagSpecific/label.cy.js +800 -0
  73. package/cypress/e2e/tagSpecific/legend.cy.js +1001 -0
  74. package/cypress/e2e/tagSpecific/line.cy.js +12167 -0
  75. package/cypress/e2e/tagSpecific/linesegment.cy.js +4749 -0
  76. package/cypress/e2e/tagSpecific/lorem.cy.js +289 -0
  77. package/cypress/e2e/tagSpecific/map.cy.js +4476 -0
  78. package/cypress/e2e/tagSpecific/matchespattern.cy.js +693 -0
  79. package/cypress/e2e/tagSpecific/math.cy.js +10990 -0
  80. package/cypress/e2e/tagSpecific/mathdisplay.cy.js +2689 -0
  81. package/cypress/e2e/tagSpecific/mathinput.cy.js +15628 -0
  82. package/cypress/e2e/tagSpecific/mathinputgraph.cy.js +566 -0
  83. package/cypress/e2e/tagSpecific/mathlist.cy.js +4073 -0
  84. package/cypress/e2e/tagSpecific/mathoperators.cy.js +13851 -0
  85. package/cypress/e2e/tagSpecific/matrix.cy.js +8825 -0
  86. package/cypress/e2e/tagSpecific/matrixinput.cy.js +16277 -0
  87. package/cypress/e2e/tagSpecific/module.cy.js +1771 -0
  88. package/cypress/e2e/tagSpecific/number.cy.js +2221 -0
  89. package/cypress/e2e/tagSpecific/numberlist.cy.js +1285 -0
  90. package/cypress/e2e/tagSpecific/p.cy.js +72 -0
  91. package/cypress/e2e/tagSpecific/paginator.cy.js +2983 -0
  92. package/cypress/e2e/tagSpecific/parabola.cy.js +14331 -0
  93. package/cypress/e2e/tagSpecific/paragraphmarkup.cy.js +104 -0
  94. package/cypress/e2e/tagSpecific/periodicset.cy.js +1439 -0
  95. package/cypress/e2e/tagSpecific/piecewisefunction.cy.js +1055 -0
  96. package/cypress/e2e/tagSpecific/pluralize.cy.js +274 -0
  97. package/cypress/e2e/tagSpecific/point.cy.js +8895 -0
  98. package/cypress/e2e/tagSpecific/point2.cy.js +10259 -0
  99. package/cypress/e2e/tagSpecific/polygon.cy.js +5039 -0
  100. package/cypress/e2e/tagSpecific/polyline.cy.js +4704 -0
  101. package/cypress/e2e/tagSpecific/problem.cy.js +2768 -0
  102. package/cypress/e2e/tagSpecific/ray.cy.js +10770 -0
  103. package/cypress/e2e/tagSpecific/rectangle.cy.js +2143 -0
  104. package/cypress/e2e/tagSpecific/ref.cy.js +420 -0
  105. package/cypress/e2e/tagSpecific/regularPolygon.cy.js +1006 -0
  106. package/cypress/e2e/tagSpecific/regularPolygon2.cy.js +100 -0
  107. package/cypress/e2e/tagSpecific/regularPolygon3.cy.js +777 -0
  108. package/cypress/e2e/tagSpecific/samplerandomnumbers.cy.js +3619 -0
  109. package/cypress/e2e/tagSpecific/sectioning.cy.js +3530 -0
  110. package/cypress/e2e/tagSpecific/select.cy.js +5376 -0
  111. package/cypress/e2e/tagSpecific/selectfromsequence.cy.js +3846 -0
  112. package/cypress/e2e/tagSpecific/selectrandomnumbers.cy.js +2914 -0
  113. package/cypress/e2e/tagSpecific/sequence.cy.js +2093 -0
  114. package/cypress/e2e/tagSpecific/shuffle.cy.js +490 -0
  115. package/cypress/e2e/tagSpecific/sidebyside.cy.js +8057 -0
  116. package/cypress/e2e/tagSpecific/singlecharactercomponents.cy.js +72 -0
  117. package/cypress/e2e/tagSpecific/slider.cy.js +914 -0
  118. package/cypress/e2e/tagSpecific/solution.cy.js +109 -0
  119. package/cypress/e2e/tagSpecific/solveequations.cy.js +1026 -0
  120. package/cypress/e2e/tagSpecific/sort.cy.js +1685 -0
  121. package/cypress/e2e/tagSpecific/spreadsheet.cy.js +5971 -0
  122. package/cypress/e2e/tagSpecific/subsetofreals.cy.js +2725 -0
  123. package/cypress/e2e/tagSpecific/substitute.cy.js +2646 -0
  124. package/cypress/e2e/tagSpecific/tabular.cy.js +36 -0
  125. package/cypress/e2e/tagSpecific/text.cy.js +975 -0
  126. package/cypress/e2e/tagSpecific/textinput.cy.js +2177 -0
  127. package/cypress/e2e/tagSpecific/textlist.cy.js +369 -0
  128. package/cypress/e2e/tagSpecific/triangle.cy.js +1936 -0
  129. package/cypress/e2e/tagSpecific/triggerset.cy.js +2023 -0
  130. package/cypress/e2e/tagSpecific/updatevalue.cy.js +3288 -0
  131. package/cypress/e2e/tagSpecific/vector.cy.js +20183 -0
  132. package/cypress/e2e/tagSpecific/video.cy.js +612 -0
  133. package/cypress/e2e/tagSpecific/when.cy.js +202 -0
  134. package/cypress/e2e/variants/specifysinglevariant.cy.js +6726 -0
  135. package/cypress/e2e/variants/uniquevariants.cy.js +4846 -0
  136. package/cypress/fixtures/example.json +5 -0
  137. package/cypress/support/commands.js +32 -0
  138. package/cypress/support/e2e.js +31 -0
  139. package/cypress.config.js +18 -0
  140. package/docs/codeSnippet.jsx +11 -0
  141. package/docs/index.html +133 -0
  142. package/docs/index.jsx +138 -0
  143. package/docs/prism.css +3 -0
  144. package/index.html +14 -0
  145. package/index.js +21 -0
  146. package/media/answer_example.png +0 -0
  147. package/media/graph_example.png +0 -0
  148. package/media/graph_markup_example.png +0 -0
  149. package/package.json +83 -0
  150. package/public/favicon.ico +0 -0
  151. package/public/fonts/files/open-sans-v18-latin-700.woff +0 -0
  152. package/public/fonts/files/open-sans-v18-latin-700.woff2 +0 -0
  153. package/public/fonts/files/open-sans-v18-latin-700italic.woff +0 -0
  154. package/public/fonts/files/open-sans-v18-latin-700italic.woff2 +0 -0
  155. package/public/fonts/files/open-sans-v18-latin-italic.woff +0 -0
  156. package/public/fonts/files/open-sans-v18-latin-italic.woff2 +0 -0
  157. package/public/fonts/files/open-sans-v18-latin-light-italic.woff +0 -0
  158. package/public/fonts/files/open-sans-v18-latin-light-italic.woff2 +0 -0
  159. package/public/fonts/files/open-sans-v18-latin-light.woff +0 -0
  160. package/public/fonts/files/open-sans-v18-latin-light.woff2 +0 -0
  161. package/public/fonts/files/open-sans-v18-latin-regular.woff +0 -0
  162. package/public/fonts/files/open-sans-v18-latin-regular.woff2 +0 -0
  163. package/src/Core/ComponentTypes.js +426 -0
  164. package/src/Core/Core.js +11852 -0
  165. package/src/Core/CoreWorker.js +127 -0
  166. package/src/Core/Dependencies.js +8226 -0
  167. package/src/Core/Numerics.js +473 -0
  168. package/src/Core/ParameterStack.js +36 -0
  169. package/src/Core/ReadOnlyProxyHandler.js +41 -0
  170. package/src/Core/StateProxyHandler.js +88 -0
  171. package/src/Core/components/Aliases.js +67 -0
  172. package/src/Core/components/Angle.js +758 -0
  173. package/src/Core/components/AnimateFromSequence.js +922 -0
  174. package/src/Core/components/Answer.js +2087 -0
  175. package/src/Core/components/AsList.js +83 -0
  176. package/src/Core/components/AttractTo.js +245 -0
  177. package/src/Core/components/AttractToAngles.js +262 -0
  178. package/src/Core/components/AttractToConstraint.js +104 -0
  179. package/src/Core/components/AttractToGrid.js +315 -0
  180. package/src/Core/components/Award.js +906 -0
  181. package/src/Core/components/BestFitLine.js +318 -0
  182. package/src/Core/components/BezierControls.js +719 -0
  183. package/src/Core/components/BlockQuote.js +35 -0
  184. package/src/Core/components/Boolean.js +500 -0
  185. package/src/Core/components/BooleanInput.js +330 -0
  186. package/src/Core/components/BooleanList.js +396 -0
  187. package/src/Core/components/BooleanOperators.js +35 -0
  188. package/src/Core/components/BooleanOperatorsOfMath.js +148 -0
  189. package/src/Core/components/CallAction.js +261 -0
  190. package/src/Core/components/Caption.js +73 -0
  191. package/src/Core/components/Case.js +56 -0
  192. package/src/Core/components/Cell.js +439 -0
  193. package/src/Core/components/CellBlock.js +64 -0
  194. package/src/Core/components/Chart.js +795 -0
  195. package/src/Core/components/Choice.js +266 -0
  196. package/src/Core/components/ChoiceInput.js +1407 -0
  197. package/src/Core/components/Circle.js +2884 -0
  198. package/src/Core/components/CodeEditor.js +647 -0
  199. package/src/Core/components/CodeViewer.js +294 -0
  200. package/src/Core/components/CollaborateGroupSetup.js +46 -0
  201. package/src/Core/components/CollaborateGroups.js +119 -0
  202. package/src/Core/components/Collect.js +850 -0
  203. package/src/Core/components/Column.js +608 -0
  204. package/src/Core/components/ConditionalContent.js +468 -0
  205. package/src/Core/components/ConsiderAsResponses.js +49 -0
  206. package/src/Core/components/ConstrainTo.js +161 -0
  207. package/src/Core/components/ConstrainToAngles.js +244 -0
  208. package/src/Core/components/ConstrainToGraph.js +142 -0
  209. package/src/Core/components/ConstrainToGrid.js +175 -0
  210. package/src/Core/components/ConstraintUnion.js +119 -0
  211. package/src/Core/components/Constraints.js +497 -0
  212. package/src/Core/components/ContentBrowser.js +441 -0
  213. package/src/Core/components/ContentPicker.js +263 -0
  214. package/src/Core/components/ControlVectors.js +25 -0
  215. package/src/Core/components/Coords.js +63 -0
  216. package/src/Core/components/Copy.js +3412 -0
  217. package/src/Core/components/Curve.js +4130 -0
  218. package/src/Core/components/CustomAttribute.js +175 -0
  219. package/src/Core/components/DataFrame.js +357 -0
  220. package/src/Core/components/DiscreteSimulationResultList.js +342 -0
  221. package/src/Core/components/DiscreteSimulationResultPolyline.js +581 -0
  222. package/src/Core/components/Divisions.js +55 -0
  223. package/src/Core/components/Document.js +888 -0
  224. package/src/Core/components/Embed.js +65 -0
  225. package/src/Core/components/Endpoint.js +62 -0
  226. package/src/Core/components/Evaluate.js +321 -0
  227. package/src/Core/components/Extract.js +656 -0
  228. package/src/Core/components/Extrema.js +556 -0
  229. package/src/Core/components/Feedback.js +200 -0
  230. package/src/Core/components/FeedbackDefinitions.js +97 -0
  231. package/src/Core/components/Figure.js +148 -0
  232. package/src/Core/components/Footnote.js +73 -0
  233. package/src/Core/components/Function.js +5344 -0
  234. package/src/Core/components/FunctionIterates.js +306 -0
  235. package/src/Core/components/FunctionOperators.js +702 -0
  236. package/src/Core/components/Graph.js +1679 -0
  237. package/src/Core/components/Group.js +7 -0
  238. package/src/Core/components/HasSameFactoring.js +407 -0
  239. package/src/Core/components/Hint.js +241 -0
  240. package/src/Core/components/Image.js +524 -0
  241. package/src/Core/components/Indexing.js +79 -0
  242. package/src/Core/components/IntComma.js +64 -0
  243. package/src/Core/components/Integer.js +81 -0
  244. package/src/Core/components/Intersection.js +328 -0
  245. package/src/Core/components/Interval.js +29 -0
  246. package/src/Core/components/Label.js +492 -0
  247. package/src/Core/components/Latex.js +104 -0
  248. package/src/Core/components/Legend.js +329 -0
  249. package/src/Core/components/Line.js +2040 -0
  250. package/src/Core/components/LineSegment.js +882 -0
  251. package/src/Core/components/Lists.js +180 -0
  252. package/src/Core/components/Lorem.js +249 -0
  253. package/src/Core/components/MMeMen.js +377 -0
  254. package/src/Core/components/Map.js +873 -0
  255. package/src/Core/components/Markers.js +101 -0
  256. package/src/Core/components/MatchesPattern.js +339 -0
  257. package/src/Core/components/Math.js +2552 -0
  258. package/src/Core/components/MathInput.js +948 -0
  259. package/src/Core/components/MathList.js +828 -0
  260. package/src/Core/components/MathOperators.js +1286 -0
  261. package/src/Core/components/Matrix.js +497 -0
  262. package/src/Core/components/MatrixInput.js +3157 -0
  263. package/src/Core/components/MdMdnMrow.js +394 -0
  264. package/src/Core/components/Module.js +16 -0
  265. package/src/Core/components/Number.js +1031 -0
  266. package/src/Core/components/NumberList.js +550 -0
  267. package/src/Core/components/Option.js +24 -0
  268. package/src/Core/components/P.js +71 -0
  269. package/src/Core/components/Paginator.js +338 -0
  270. package/src/Core/components/Panel.js +126 -0
  271. package/src/Core/components/Parabola.js +1561 -0
  272. package/src/Core/components/ParagraphMarkup.js +59 -0
  273. package/src/Core/components/Pegboard.js +43 -0
  274. package/src/Core/components/PeriodicSet.js +291 -0
  275. package/src/Core/components/PiecewiseFunction.js +832 -0
  276. package/src/Core/components/Pluralize.js +198 -0
  277. package/src/Core/components/Point.js +1295 -0
  278. package/src/Core/components/Polygon.js +408 -0
  279. package/src/Core/components/Polyline.js +841 -0
  280. package/src/Core/components/RandomizedTextList.js +225 -0
  281. package/src/Core/components/Ray.js +1737 -0
  282. package/src/Core/components/Rectangle.js +1535 -0
  283. package/src/Core/components/Ref.js +350 -0
  284. package/src/Core/components/RegionBetweenCurveXAxis.js +124 -0
  285. package/src/Core/components/RegionHalfPlane.js +107 -0
  286. package/src/Core/components/RegularPolygon.js +2118 -0
  287. package/src/Core/components/RenderDoenetML.js +181 -0
  288. package/src/Core/components/Row.js +780 -0
  289. package/src/Core/components/SampleRandomNumbers.js +653 -0
  290. package/src/Core/components/Sectioning.js +303 -0
  291. package/src/Core/components/Select.js +947 -0
  292. package/src/Core/components/SelectFromSequence.js +1242 -0
  293. package/src/Core/components/SelectRandomNumbers.js +225 -0
  294. package/src/Core/components/Sequence.js +444 -0
  295. package/src/Core/components/Setup.js +53 -0
  296. package/src/Core/components/Shuffle.js +470 -0
  297. package/src/Core/components/SideBySide.js +2130 -0
  298. package/src/Core/components/SingleCharacterComponents.js +41 -0
  299. package/src/Core/components/Slider.js +819 -0
  300. package/src/Core/components/SolutionContainer.js +67 -0
  301. package/src/Core/components/Solutions.js +334 -0
  302. package/src/Core/components/SolveEquations.js +568 -0
  303. package/src/Core/components/Sort.js +398 -0
  304. package/src/Core/components/Sources.js +108 -0
  305. package/src/Core/components/Split.js +205 -0
  306. package/src/Core/components/Spreadsheet.js +1507 -0
  307. package/src/Core/components/StyleDefinitions.js +111 -0
  308. package/src/Core/components/SubsetOfReals.js +348 -0
  309. package/src/Core/components/SubsetOfRealsInput.js +1474 -0
  310. package/src/Core/components/Substitute.js +496 -0
  311. package/src/Core/components/SummaryStatistics.js +652 -0
  312. package/src/Core/components/Table.js +145 -0
  313. package/src/Core/components/Tabular.js +384 -0
  314. package/src/Core/components/Template.js +360 -0
  315. package/src/Core/components/Text.js +341 -0
  316. package/src/Core/components/TextInput.js +566 -0
  317. package/src/Core/components/TextList.js +442 -0
  318. package/src/Core/components/TextListFromString.js +137 -0
  319. package/src/Core/components/TextOperatorsOfMath.js +21 -0
  320. package/src/Core/components/Triangle.js +280 -0
  321. package/src/Core/components/TriggerSet.js +189 -0
  322. package/src/Core/components/TupleList.js +43 -0
  323. package/src/Core/components/UpdateValue.js +435 -0
  324. package/src/Core/components/VariantControl.js +36 -0
  325. package/src/Core/components/Vector.js +2478 -0
  326. package/src/Core/components/Verbatim.js +125 -0
  327. package/src/Core/components/Video.js +673 -0
  328. package/src/Core/components/When.js +198 -0
  329. package/src/Core/components/abstract/AngleListComponent.js +140 -0
  330. package/src/Core/components/abstract/BaseComponent.js +1496 -0
  331. package/src/Core/components/abstract/BlockComponent.js +5 -0
  332. package/src/Core/components/abstract/BooleanBaseOperator.js +88 -0
  333. package/src/Core/components/abstract/BooleanBaseOperatorOfMath.js +100 -0
  334. package/src/Core/components/abstract/BooleanBaseOperatorOneInput.js +44 -0
  335. package/src/Core/components/abstract/ComponentSize.js +789 -0
  336. package/src/Core/components/abstract/ComponentWithSelectableType.js +537 -0
  337. package/src/Core/components/abstract/CompositeComponent.js +142 -0
  338. package/src/Core/components/abstract/ConstraintComponent.js +19 -0
  339. package/src/Core/components/abstract/FunctionBaseOperator.js +680 -0
  340. package/src/Core/components/abstract/GraphicalComponent.js +56 -0
  341. package/src/Core/components/abstract/InlineComponent.js +5 -0
  342. package/src/Core/components/abstract/InlineRenderInlineChildren.js +63 -0
  343. package/src/Core/components/abstract/Input.js +192 -0
  344. package/src/Core/components/abstract/IntervalListComponent.js +218 -0
  345. package/src/Core/components/abstract/LineListComponent.js +114 -0
  346. package/src/Core/components/abstract/MathBaseOperator.js +631 -0
  347. package/src/Core/components/abstract/MathBaseOperatorOneInput.js +112 -0
  348. package/src/Core/components/abstract/PointListComponent.js +238 -0
  349. package/src/Core/components/abstract/SectioningComponent.js +1262 -0
  350. package/src/Core/components/abstract/SingleCharacterInline.js +23 -0
  351. package/src/Core/components/abstract/TextBaseOperatorOfMath.js +47 -0
  352. package/src/Core/components/abstract/TextOrInline.js +66 -0
  353. package/src/Core/components/abstract/VariableName.js +31 -0
  354. package/src/Core/components/abstract/VariableNameList.js +83 -0
  355. package/src/Core/components/abstract/VectorListComponent.js +235 -0
  356. package/src/Core/components/chemistry/Atom.js +910 -0
  357. package/src/Core/components/chemistry/ElectronConfiguration.js +36 -0
  358. package/src/Core/components/chemistry/Ion.js +684 -0
  359. package/src/Core/components/chemistry/IonicCompound.js +189 -0
  360. package/src/Core/components/chemistry/OrbitalDiagram.js +175 -0
  361. package/src/Core/components/chemistry/OrbitalDiagramInput.js +753 -0
  362. package/src/Core/components/chemistry/index.js +6 -0
  363. package/src/Core/components/commonsugar/breakstrings.js +627 -0
  364. package/src/Core/components/commonsugar/lists.js +177 -0
  365. package/src/Core/components/dynamicalSystems/CobwebPolyline.js +913 -0
  366. package/src/Core/components/dynamicalSystems/EquilibriumCurve.js +95 -0
  367. package/src/Core/components/dynamicalSystems/EquilibriumLine.js +93 -0
  368. package/src/Core/components/dynamicalSystems/EquilibriumPoint.js +93 -0
  369. package/src/Core/components/dynamicalSystems/ODESystem.js +943 -0
  370. package/src/Core/components/dynamicalSystems/index.js +5 -0
  371. package/src/Core/components/linearAlgebra/EigenDecomposition.js +294 -0
  372. package/src/Core/utils/array.js +30 -0
  373. package/src/Core/utils/booleanLogic.js +965 -0
  374. package/src/Core/utils/checkEquality.js +818 -0
  375. package/src/Core/utils/cid.js +29 -0
  376. package/src/Core/utils/componentInfoObjects.js +100 -0
  377. package/src/Core/utils/constraints.js +23 -0
  378. package/src/Core/utils/copy.js +572 -0
  379. package/src/Core/utils/deepFunctions.js +173 -0
  380. package/src/Core/utils/descendants.js +252 -0
  381. package/src/Core/utils/enumeration.js +234 -0
  382. package/src/Core/utils/feedback.js +84 -0
  383. package/src/Core/utils/function.js +1343 -0
  384. package/src/Core/utils/graphical.js +196 -0
  385. package/src/Core/utils/label.js +396 -0
  386. package/src/Core/utils/math.js +1056 -0
  387. package/src/Core/utils/naming.js +45 -0
  388. package/src/Core/utils/periodicSetEquality.js +403 -0
  389. package/src/Core/utils/randomNumbers.js +70 -0
  390. package/src/Core/utils/retrieveMedia.js +98 -0
  391. package/src/Core/utils/retrieveTextFile.js +140 -0
  392. package/src/Core/utils/returnAllPossibleVariants.js +73 -0
  393. package/src/Core/utils/rounding.js +316 -0
  394. package/src/Core/utils/sequence.js +754 -0
  395. package/src/Core/utils/serializedStateProcessing.js +4049 -0
  396. package/src/Core/utils/size.js +22 -0
  397. package/src/Core/utils/stateVariables.js +138 -0
  398. package/src/Core/utils/style.js +535 -0
  399. package/src/Core/utils/subset-of-reals.js +796 -0
  400. package/src/Core/utils/table.js +41 -0
  401. package/src/Core/utils/text.js +16 -0
  402. package/src/Core/utils/triggering.js +167 -0
  403. package/src/Core/utils/variants.js +477 -0
  404. package/src/DoenetML.css +308 -0
  405. package/src/DoenetML.jsx +201 -0
  406. package/src/Parser/doenet.grammar +90 -0
  407. package/src/Parser/doenet.js +33 -0
  408. package/src/Parser/doenet.terms.js +20 -0
  409. package/src/Parser/parser.js +266 -0
  410. package/src/Parser/tokens.js +129 -0
  411. package/src/Tools/CodeMirror.jsx +440 -0
  412. package/src/Tools/DarkmodeController.jsx +21 -0
  413. package/src/Tools/Footers/MathInputSelector.jsx +34 -0
  414. package/src/Tools/Footers/VirtualKeyboard.jsx +751 -0
  415. package/src/Tools/cypressTest/CypressTest.jsx +341 -0
  416. package/src/Tools/cypressTest/index.html +102 -0
  417. package/src/Tools/cypressTest/index.jsx +40 -0
  418. package/src/Viewer/ActivityViewer.jsx +1461 -0
  419. package/src/Viewer/PageViewer.jsx +1329 -0
  420. package/src/Viewer/renderers/alert.jsx +17 -0
  421. package/src/Viewer/renderers/angle.jsx +209 -0
  422. package/src/Viewer/renderers/answer.jsx +206 -0
  423. package/src/Viewer/renderers/asList.jsx +25 -0
  424. package/src/Viewer/renderers/blockQuote.jsx +41 -0
  425. package/src/Viewer/renderers/boolean.jsx +17 -0
  426. package/src/Viewer/renderers/booleanInput.css +105 -0
  427. package/src/Viewer/renderers/booleanInput.jsx +636 -0
  428. package/src/Viewer/renderers/button.jsx +369 -0
  429. package/src/Viewer/renderers/c.jsx +17 -0
  430. package/src/Viewer/renderers/callAction.jsx +18 -0
  431. package/src/Viewer/renderers/cell.jsx +59 -0
  432. package/src/Viewer/renderers/chart.jsx +83 -0
  433. package/src/Viewer/renderers/choiceInput.css +223 -0
  434. package/src/Viewer/renderers/choiceInput.jsx +535 -0
  435. package/src/Viewer/renderers/circle.jsx +990 -0
  436. package/src/Viewer/renderers/cobwebPolyline.jsx +442 -0
  437. package/src/Viewer/renderers/codeEditor.jsx +248 -0
  438. package/src/Viewer/renderers/codeViewer.jsx +105 -0
  439. package/src/Viewer/renderers/containerBlock.jsx +41 -0
  440. package/src/Viewer/renderers/containerInline.jsx +17 -0
  441. package/src/Viewer/renderers/contentBrowser.jsx +159 -0
  442. package/src/Viewer/renderers/contentPicker.jsx +160 -0
  443. package/src/Viewer/renderers/curve.jsx +1072 -0
  444. package/src/Viewer/renderers/ellipsis.jsx +17 -0
  445. package/src/Viewer/renderers/em.jsx +17 -0
  446. package/src/Viewer/renderers/embed.jsx +110 -0
  447. package/src/Viewer/renderers/feedback.jsx +74 -0
  448. package/src/Viewer/renderers/figure.jsx +131 -0
  449. package/src/Viewer/renderers/footnote.jsx +52 -0
  450. package/src/Viewer/renderers/graph.jsx +925 -0
  451. package/src/Viewer/renderers/hint.jsx +142 -0
  452. package/src/Viewer/renderers/image.jsx +581 -0
  453. package/src/Viewer/renderers/jsxgraph-distrib/jsxgraphcore.mjs +2 -0
  454. package/src/Viewer/renderers/jsxgraph-distrib/jsxgraphcore.mjs.map +1 -0
  455. package/src/Viewer/renderers/label.jsx +470 -0
  456. package/src/Viewer/renderers/legend.jsx +306 -0
  457. package/src/Viewer/renderers/line.jsx +511 -0
  458. package/src/Viewer/renderers/lineSegment.jsx +754 -0
  459. package/src/Viewer/renderers/list.jsx +111 -0
  460. package/src/Viewer/renderers/lq.jsx +12 -0
  461. package/src/Viewer/renderers/lsq.jsx +12 -0
  462. package/src/Viewer/renderers/math.jsx +582 -0
  463. package/src/Viewer/renderers/mathInput.css +10 -0
  464. package/src/Viewer/renderers/mathInput.jsx +425 -0
  465. package/src/Viewer/renderers/mathInputog.jsx +534 -0
  466. package/src/Viewer/renderers/mathList.jsx +39 -0
  467. package/src/Viewer/renderers/matrixInput.jsx +317 -0
  468. package/src/Viewer/renderers/mdash.jsx +12 -0
  469. package/src/Viewer/renderers/nbsp.jsx +12 -0
  470. package/src/Viewer/renderers/ndash.jsx +12 -0
  471. package/src/Viewer/renderers/number.jsx +454 -0
  472. package/src/Viewer/renderers/numberList.jsx +35 -0
  473. package/src/Viewer/renderers/orbitalDiagram.jsx +247 -0
  474. package/src/Viewer/renderers/orbitalDiagramInput.jsx +450 -0
  475. package/src/Viewer/renderers/p.jsx +38 -0
  476. package/src/Viewer/renderers/paginatorControls.jsx +41 -0
  477. package/src/Viewer/renderers/pegboard.jsx +239 -0
  478. package/src/Viewer/renderers/point.jsx +649 -0
  479. package/src/Viewer/renderers/polygon.jsx +612 -0
  480. package/src/Viewer/renderers/polyline.jsx +608 -0
  481. package/src/Viewer/renderers/pre.jsx +34 -0
  482. package/src/Viewer/renderers/q.jsx +17 -0
  483. package/src/Viewer/renderers/ray.jsx +410 -0
  484. package/src/Viewer/renderers/ref.jsx +149 -0
  485. package/src/Viewer/renderers/regionBetweenCurveXAxis.jsx +182 -0
  486. package/src/Viewer/renderers/renderDoenetML.jsx +56 -0
  487. package/src/Viewer/renderers/row.jsx +31 -0
  488. package/src/Viewer/renderers/rq.jsx +12 -0
  489. package/src/Viewer/renderers/rsq.jsx +12 -0
  490. package/src/Viewer/renderers/section.jsx +427 -0
  491. package/src/Viewer/renderers/sideBySide.jsx +80 -0
  492. package/src/Viewer/renderers/slider.jsx +800 -0
  493. package/src/Viewer/renderers/solution.jsx +134 -0
  494. package/src/Viewer/renderers/spreadsheet.jsx +83 -0
  495. package/src/Viewer/renderers/sq.jsx +17 -0
  496. package/src/Viewer/renderers/styles/global.css +14 -0
  497. package/src/Viewer/renderers/subsetOfRealsInput.jsx +392 -0
  498. package/src/Viewer/renderers/summaryStatistics.jsx +83 -0
  499. package/src/Viewer/renderers/table.jsx +78 -0
  500. package/src/Viewer/renderers/tabular.jsx +58 -0
  501. package/src/Viewer/renderers/tag.jsx +26 -0
  502. package/src/Viewer/renderers/text.jsx +439 -0
  503. package/src/Viewer/renderers/textInput.jsx +774 -0
  504. package/src/Viewer/renderers/textList.jsx +30 -0
  505. package/src/Viewer/renderers/triggerSet.jsx +52 -0
  506. package/src/Viewer/renderers/updateValue.jsx +30 -0
  507. package/src/Viewer/renderers/utils/css.js +13 -0
  508. package/src/Viewer/renderers/utils/graph.js +159 -0
  509. package/src/Viewer/renderers/utils/offGraphIndicators.js +91 -0
  510. package/src/Viewer/renderers/vector.jsx +678 -0
  511. package/src/Viewer/renderers/video.jsx +494 -0
  512. package/src/Viewer/useDoenetRenderer.jsx +128 -0
  513. package/src/main.jsx +16 -0
  514. package/src/media/fonts/files/open-sans-v18-latin-700.woff +0 -0
  515. package/src/media/fonts/files/open-sans-v18-latin-700.woff2 +0 -0
  516. package/src/media/fonts/files/open-sans-v18-latin-700italic.woff +0 -0
  517. package/src/media/fonts/files/open-sans-v18-latin-700italic.woff2 +0 -0
  518. package/src/media/fonts/files/open-sans-v18-latin-italic.woff +0 -0
  519. package/src/media/fonts/files/open-sans-v18-latin-italic.woff2 +0 -0
  520. package/src/media/fonts/files/open-sans-v18-latin-light-italic.woff +0 -0
  521. package/src/media/fonts/files/open-sans-v18-latin-light-italic.woff2 +0 -0
  522. package/src/media/fonts/files/open-sans-v18-latin-light.woff +0 -0
  523. package/src/media/fonts/files/open-sans-v18-latin-light.woff2 +0 -0
  524. package/src/media/fonts/files/open-sans-v18-latin-regular.woff +0 -0
  525. package/src/media/fonts/files/open-sans-v18-latin-regular.woff2 +0 -0
  526. package/src/test/testCode.doenet +26 -0
  527. package/src/test/testViewer.jsx +158 -0
  528. package/src/uiComponents/ActionButton.jsx +157 -0
  529. package/src/uiComponents/ActionButtonGroup.jsx +93 -0
  530. package/src/uiComponents/Button.jsx +160 -0
  531. package/src/uiComponents/ButtonGroup.jsx +56 -0
  532. package/src/uiComponents/ToggleButton.jsx +194 -0
  533. package/src/uiComponents/ToggleButtonGroup.jsx +77 -0
  534. package/src/utils/activityUtils.js +713 -0
  535. package/src/utils/array.js +17 -0
  536. package/src/utils/cid.js +34 -0
  537. package/src/utils/componentInfoObjects.js +89 -0
  538. package/src/utils/deepFunctions.js +165 -0
  539. package/src/utils/enumeration.js +226 -0
  540. package/src/utils/math.js +624 -0
  541. package/src/utils/naming.js +44 -0
  542. package/src/utils/retrieveTextFile.js +156 -0
  543. package/src/utils/returnAllPossibleVariants.js +81 -0
  544. package/src/utils/sequence.js +715 -0
  545. package/src/utils/serialize.js +29 -0
  546. package/src/utils/serializedStateProcessing.js +2587 -0
  547. package/src/utils/subset-of-reals.js +783 -0
  548. package/src/utils/url.js +19 -0
  549. package/vite.config.js +14 -0
@@ -0,0 +1,3412 @@
1
+ import CompositeComponent from "./abstract/CompositeComponent";
2
+ import * as serializeFunctions from "../utils/serializedStateProcessing";
3
+ import {
4
+ convertAttributesForComponentType,
5
+ postProcessCopy,
6
+ verifyReplacementsMatchSpecifiedType,
7
+ } from "../utils/copy";
8
+ import { flattenDeep, flattenLevels } from "../utils/array";
9
+ import { getUniqueIdentifierFromBase } from "../utils/naming";
10
+ import { deepClone } from "../utils/deepFunctions";
11
+
12
+ export default class Copy extends CompositeComponent {
13
+ static componentType = "copy";
14
+
15
+ static assignNamesToReplacements = true;
16
+
17
+ static acceptTarget = true;
18
+ static acceptAnyAttribute = true;
19
+
20
+ static includeBlankStringChildren = true;
21
+
22
+ static stateVariableToEvaluateAfterReplacements =
23
+ "needsReplacementsUpdatedWhenStale";
24
+
25
+ static createAttributesObject() {
26
+ let attributes = super.createAttributesObject();
27
+
28
+ // delete off attributes from base component that should apply to replacements instead
29
+ // (using acceptAnyAttribute)
30
+ delete attributes.disabled;
31
+ delete attributes.modifyIndirectly;
32
+ delete attributes.fixed;
33
+ delete attributes.styleNumber;
34
+ delete attributes.isResponse;
35
+ delete attributes.hide;
36
+
37
+ attributes.assignNewNamespaces = {
38
+ createPrimitiveOfType: "boolean",
39
+ };
40
+ attributes.assignNamesSkip = {
41
+ createPrimitiveOfType: "number",
42
+ };
43
+ attributes.prop = {
44
+ createPrimitiveOfType: "string",
45
+ };
46
+ attributes.obtainPropFromComposite = {
47
+ createPrimitiveOfType: "boolean",
48
+ createStateVariable: "obtainPropFromComposite",
49
+ defaultValue: false,
50
+ public: true,
51
+ };
52
+ attributes.createComponentOfType = {
53
+ createPrimitiveOfType: "string",
54
+ };
55
+ attributes.numComponents = {
56
+ createPrimitiveOfType: "number",
57
+ };
58
+ attributes.componentIndex = {
59
+ createComponentOfType: "integer",
60
+ createStateVariable: "componentIndex",
61
+ defaultValue: null,
62
+ public: true,
63
+ };
64
+ attributes.sourceSubnames = {
65
+ createPrimitiveOfType: "stringArray",
66
+ createStateVariable: "targetSubnames",
67
+ defaultValue: null,
68
+ public: true,
69
+ };
70
+ attributes.sourceSubnamesComponentIndex = {
71
+ createComponentOfType: "numberList",
72
+ createStateVariable: "targetSubnamesComponentIndex",
73
+ defaultValue: null,
74
+ public: true,
75
+ };
76
+ attributes.propIndex = {
77
+ createComponentOfType: "numberList",
78
+ createStateVariable: "propIndex",
79
+ defaultValue: null,
80
+ public: true,
81
+ };
82
+ attributes.uri = {
83
+ createPrimitiveOfType: "string",
84
+ createStateVariable: "uri",
85
+ defaultValue: null,
86
+ public: true,
87
+ };
88
+ attributes.sourceAttributesToIgnore = {
89
+ createPrimitiveOfType: "stringArray",
90
+ createStateVariable: "sourceAttributesToIgnore",
91
+ defaultValue: ["isResponse"],
92
+ public: true,
93
+ };
94
+ attributes.link = {
95
+ createPrimitiveOfType: "boolean",
96
+ };
97
+
98
+ // Note: only implemented with no wrapping components
99
+ attributes.removeEmptyArrayEntries = {
100
+ createPrimitiveOfType: "boolean",
101
+ createStateVariable: "removeEmptyArrayEntries",
102
+ defaultValue: false,
103
+ };
104
+ return attributes;
105
+ }
106
+
107
+ static keepChildrenSerialized({ serializedComponent }) {
108
+ if (serializedComponent.children === undefined) {
109
+ return [];
110
+ } else {
111
+ return Object.keys(serializedComponent.children);
112
+ }
113
+ }
114
+
115
+ static returnStateVariableDefinitions() {
116
+ let stateVariableDefinitions = super.returnStateVariableDefinitions();
117
+
118
+ stateVariableDefinitions.target = {
119
+ returnDependencies: () => ({
120
+ target: {
121
+ dependencyType: "doenetAttribute",
122
+ attributeName: "target",
123
+ },
124
+ }),
125
+ definition: ({ dependencyValues }) => ({
126
+ setValue: { target: dependencyValues.target },
127
+ }),
128
+ };
129
+
130
+ stateVariableDefinitions.targetSourcesName = {
131
+ additionalStateVariablesDefined: [
132
+ {
133
+ variableName: "sourcesChildNumber",
134
+ hasEssential: true,
135
+ shadowVariable: true,
136
+ },
137
+ ],
138
+ stateVariablesDeterminingDependencies: ["target"],
139
+ determineDependenciesImmediately: true,
140
+ hasEssential: true,
141
+ shadowVariable: true,
142
+ returnDependencies: function ({ stateValues, sharedParameters }) {
143
+ let sourceNameMappings = sharedParameters.sourceNameMappings;
144
+ if (!sourceNameMappings) {
145
+ return {};
146
+ }
147
+
148
+ let theMapping = sourceNameMappings[stateValues.target];
149
+ if (!theMapping) {
150
+ return {};
151
+ }
152
+ return {
153
+ targetSourcesName: {
154
+ dependencyType: "value",
155
+ value: theMapping.name,
156
+ },
157
+ sourcesChildNumber: {
158
+ dependencyType: "value",
159
+ value: theMapping.childNumber,
160
+ },
161
+ };
162
+ },
163
+ definition: function ({ dependencyValues }) {
164
+ let targetSourcesName = dependencyValues.targetSourcesName;
165
+ let sourcesChildNumber = dependencyValues.sourcesChildNumber;
166
+ if (!targetSourcesName) {
167
+ targetSourcesName = null;
168
+ sourcesChildNumber = null;
169
+ }
170
+ return {
171
+ setValue: { targetSourcesName, sourcesChildNumber },
172
+ setEssentialValue: { targetSourcesName, sourcesChildNumber },
173
+ };
174
+ },
175
+ };
176
+
177
+ stateVariableDefinitions.targetSources = {
178
+ stateVariablesDeterminingDependencies: ["targetSourcesName"],
179
+ determineDependenciesImmediately: true,
180
+ returnDependencies({ stateValues }) {
181
+ if (!stateValues.targetSourcesName) {
182
+ return {};
183
+ }
184
+ return {
185
+ targetSourcesComponent: {
186
+ dependencyType: "componentIdentity",
187
+ componentName: stateValues.targetSourcesName,
188
+ },
189
+ };
190
+ },
191
+ definition: function ({ dependencyValues }) {
192
+ let targetSources = dependencyValues.targetSourcesComponent;
193
+ if (!targetSources) {
194
+ targetSources = null;
195
+ }
196
+ return { setValue: { targetSources } };
197
+ },
198
+ };
199
+
200
+ stateVariableDefinitions.sourceIndex = {
201
+ stateVariablesDeterminingDependencies: ["target"],
202
+ determineDependenciesImmediately: true,
203
+ hasEssential: true,
204
+ shadowVariable: true,
205
+ returnDependencies: function ({ stateValues, sharedParameters }) {
206
+ let sourceIndexMappings = sharedParameters.sourceIndexMappings;
207
+ if (!sourceIndexMappings) {
208
+ return {};
209
+ }
210
+
211
+ let theMapping = sourceIndexMappings[stateValues.target];
212
+ if (theMapping === undefined) {
213
+ return {};
214
+ }
215
+
216
+ return {
217
+ sourceIndex: {
218
+ dependencyType: "value",
219
+ value: theMapping,
220
+ },
221
+ };
222
+ },
223
+ definition: function ({ dependencyValues }) {
224
+ let sourceIndex = dependencyValues.sourceIndex;
225
+ if (sourceIndex === undefined) {
226
+ sourceIndex = null;
227
+ }
228
+ return {
229
+ setValue: { sourceIndex },
230
+ setEssentialValue: { sourceIndex },
231
+ };
232
+ },
233
+ };
234
+
235
+ stateVariableDefinitions.targetComponent = {
236
+ shadowVariable: true,
237
+ stateVariablesDeterminingDependencies: ["targetSources", "sourceIndex"],
238
+ determineDependenciesImmediately: true,
239
+ returnDependencies({ stateValues }) {
240
+ if (stateValues.sourceIndex !== null) {
241
+ return {};
242
+ }
243
+
244
+ if (stateValues.targetSources !== null) {
245
+ return {
246
+ targetSourcesChildren: {
247
+ dependencyType: "stateVariable",
248
+ componentName: stateValues.targetSources.componentName,
249
+ variableName: "childIdentities",
250
+ },
251
+ sourcesChildNumber: {
252
+ dependencyType: "stateVariable",
253
+ variableName: "sourcesChildNumber",
254
+ },
255
+ };
256
+ }
257
+
258
+ return {
259
+ targetComponent: {
260
+ dependencyType: "targetComponent",
261
+ },
262
+ };
263
+ },
264
+ definition: function ({ dependencyValues }) {
265
+ let targetComponent = null;
266
+ if (dependencyValues.targetSourcesChildren) {
267
+ targetComponent =
268
+ dependencyValues.targetSourcesChildren[
269
+ dependencyValues.sourcesChildNumber
270
+ ];
271
+ if (!targetComponent) {
272
+ targetComponent = null;
273
+ }
274
+ } else if (dependencyValues.targetComponent) {
275
+ targetComponent = dependencyValues.targetComponent;
276
+ }
277
+
278
+ return {
279
+ setValue: { targetComponent },
280
+ };
281
+ },
282
+ };
283
+
284
+ stateVariableDefinitions.targetInactive = {
285
+ stateVariablesDeterminingDependencies: ["targetComponent"],
286
+ returnDependencies({ stateValues }) {
287
+ if (stateValues.targetComponent) {
288
+ return {
289
+ targetIsInactiveCompositeReplacement: {
290
+ dependencyType: "stateVariable",
291
+ componentName: stateValues.targetComponent.componentName,
292
+ variableName: "isInactiveCompositeReplacement",
293
+ },
294
+ };
295
+ } else {
296
+ return {};
297
+ }
298
+ },
299
+ definition: function ({ dependencyValues }) {
300
+ return {
301
+ setValue: {
302
+ targetInactive: Boolean(
303
+ dependencyValues.targetIsInactiveCompositeReplacement,
304
+ ),
305
+ },
306
+ };
307
+ },
308
+ };
309
+
310
+ stateVariableDefinitions.cid = {
311
+ additionalStateVariablesDefined: ["doenetId"],
312
+ returnDependencies: () => ({
313
+ uri: {
314
+ dependencyType: "stateVariable",
315
+ variableName: "uri",
316
+ },
317
+ }),
318
+ definition: function ({ dependencyValues }) {
319
+ if (
320
+ !dependencyValues.uri ||
321
+ dependencyValues.uri.substring(0, 7).toLowerCase() !== "doenet:"
322
+ ) {
323
+ return {
324
+ setValue: { cid: null, doenetId: null },
325
+ };
326
+ }
327
+
328
+ let cid = null,
329
+ doenetId = null;
330
+
331
+ let result = dependencyValues.uri.match(/[:&]cid=([^&]+)/i);
332
+ if (result) {
333
+ cid = result[1];
334
+ }
335
+ result = dependencyValues.uri.match(/[:&]doenetid=([^&]+)/i);
336
+ if (result) {
337
+ doenetId = result[1];
338
+ }
339
+
340
+ return { setValue: { cid, doenetId } };
341
+ },
342
+ };
343
+
344
+ stateVariableDefinitions.serializedComponentsForCid = {
345
+ returnDependencies: () => ({
346
+ cid: {
347
+ dependencyType: "stateVariable",
348
+ variableName: "cid",
349
+ },
350
+ serializedChildren: {
351
+ dependencyType: "serializedChildren",
352
+ doNotProxy: true,
353
+ },
354
+ }),
355
+ definition: function ({ dependencyValues }) {
356
+ if (!dependencyValues.cid) {
357
+ return {
358
+ setValue: { serializedComponentsForCid: null },
359
+ };
360
+ }
361
+ if (!(dependencyValues.serializedChildren?.length > 0)) {
362
+ return {
363
+ setValue: { serializedComponentsForCid: null },
364
+ };
365
+ }
366
+
367
+ return {
368
+ setValue: {
369
+ serializedComponentsForCid: dependencyValues.serializedChildren,
370
+ },
371
+ };
372
+ },
373
+ };
374
+
375
+ stateVariableDefinitions.propName = {
376
+ shadowVariable: true,
377
+ returnDependencies: () => ({
378
+ propName: {
379
+ dependencyType: "attributePrimitive",
380
+ attributeName: "prop",
381
+ },
382
+ }),
383
+ definition: function ({ dependencyValues }) {
384
+ return { setValue: { propName: dependencyValues.propName } };
385
+ },
386
+ };
387
+
388
+ stateVariableDefinitions.isPlainMacro = {
389
+ returnDependencies: () => ({
390
+ isPlainMacro: {
391
+ dependencyType: "doenetAttribute",
392
+ attributeName: "isPlainMacro",
393
+ },
394
+ targetComponent: {
395
+ dependencyType: "stateVariable",
396
+ variableName: "targetComponent",
397
+ },
398
+ typeAttr: {
399
+ dependencyType: "attributePrimitive",
400
+ attributeName: "createComponentOfType",
401
+ },
402
+ targetSubnames: {
403
+ dependencyType: "stateVariable",
404
+ variableName: "targetSubnames",
405
+ },
406
+ }),
407
+ definition: function ({ dependencyValues, componentInfoObjects }) {
408
+ let isPlainMacro =
409
+ dependencyValues.isPlainMacro &&
410
+ (!componentInfoObjects.isCompositeComponent({
411
+ componentType: dependencyValues.targetComponent?.componentType,
412
+ }) ||
413
+ dependencyValues.targetSubnames);
414
+
415
+ if (isPlainMacro && dependencyValues.typeAttr) {
416
+ // typically, if specify createComponentOfType (i.e., typeAttr is defined)
417
+ // then we wouldn't have a plain macro
418
+ // However, if we specified a different componentType
419
+ // and the variable for the plain macro is that componentType (or its undefined)
420
+ // then we'll keep it as a plain macro
421
+
422
+ isPlainMacro = false;
423
+
424
+ let componentTypeFromAttr =
425
+ componentInfoObjects.componentTypeLowerCaseMapping[
426
+ dependencyValues.typeAttr.toLowerCase()
427
+ ];
428
+
429
+ let targetClass =
430
+ componentInfoObjects.allComponentClasses[
431
+ dependencyValues.targetComponent?.componentType
432
+ ];
433
+
434
+ if (targetClass) {
435
+ let varInfo =
436
+ componentInfoObjects.publicStateVariableInfo[
437
+ targetClass.componentType
438
+ ].stateVariableDescriptions[targetClass.variableForPlainMacro];
439
+
440
+ if (
441
+ componentTypeFromAttr !== targetClass.componentType &&
442
+ varInfo &&
443
+ (varInfo.createComponentOfType === undefined ||
444
+ varInfo.createComponentOfType === componentTypeFromAttr)
445
+ ) {
446
+ isPlainMacro = true;
447
+ }
448
+ }
449
+ }
450
+
451
+ return { setValue: { isPlainMacro } };
452
+ },
453
+ };
454
+
455
+ stateVariableDefinitions.isPlainCopy = {
456
+ returnDependencies: () => ({
457
+ isPlainCopy: {
458
+ dependencyType: "doenetAttribute",
459
+ attributeName: "isPlainCopy",
460
+ },
461
+ targetComponent: {
462
+ dependencyType: "stateVariable",
463
+ variableName: "targetComponent",
464
+ },
465
+ typeAttr: {
466
+ dependencyType: "attributePrimitive",
467
+ attributeName: "createComponentOfType",
468
+ },
469
+ targetSubnames: {
470
+ dependencyType: "stateVariable",
471
+ variableName: "targetSubnames",
472
+ },
473
+ }),
474
+ definition: function ({ dependencyValues, componentInfoObjects }) {
475
+ let isPlainCopy =
476
+ dependencyValues.isPlainCopy &&
477
+ (!componentInfoObjects.isCompositeComponent({
478
+ componentType: dependencyValues.targetComponent?.componentType,
479
+ }) ||
480
+ dependencyValues.targetSubnames);
481
+
482
+ if (isPlainCopy && dependencyValues.typeAttr) {
483
+ // typically, if specify createComponentOfType (i.e., typeAttr is defined)
484
+ // then we wouldn't have a plain copy
485
+ // However, if we specified a different componentType
486
+ // and the variable for the plain copy is that componentType (or its undefined)
487
+ // then we'll keep it as a plain copy
488
+
489
+ isPlainCopy = false;
490
+
491
+ let componentTypeFromAttr =
492
+ componentInfoObjects.componentTypeLowerCaseMapping[
493
+ dependencyValues.typeAttr.toLowerCase()
494
+ ];
495
+
496
+ let targetClass =
497
+ componentInfoObjects.allComponentClasses[
498
+ dependencyValues.targetComponent?.componentType
499
+ ];
500
+
501
+ if (targetClass) {
502
+ let varInfo =
503
+ componentInfoObjects.publicStateVariableInfo[
504
+ targetClass.componentType
505
+ ].stateVariableDescriptions[targetClass.variableForPlainCopy];
506
+
507
+ if (
508
+ componentTypeFromAttr !== targetClass.componentType &&
509
+ varInfo &&
510
+ (varInfo.createComponentOfType === undefined ||
511
+ varInfo.createComponentOfType === componentTypeFromAttr)
512
+ ) {
513
+ isPlainCopy = true;
514
+ }
515
+ }
516
+ }
517
+
518
+ return { setValue: { isPlainCopy } };
519
+ },
520
+ };
521
+
522
+ stateVariableDefinitions.linkAttrForDetermineDeps = {
523
+ returnDependencies: () => ({
524
+ linkAttr: {
525
+ dependencyType: "attributePrimitive",
526
+ attributeName: "link",
527
+ },
528
+ }),
529
+ definition({ dependencyValues }) {
530
+ let linkAttrForDetermineDeps;
531
+ if (dependencyValues.linkAttr === null) {
532
+ linkAttrForDetermineDeps = true;
533
+ } else {
534
+ linkAttrForDetermineDeps = dependencyValues.linkAttr;
535
+ }
536
+
537
+ return { setValue: { linkAttrForDetermineDeps } };
538
+ },
539
+ };
540
+
541
+ stateVariableDefinitions.replacementSourceIdentities = {
542
+ stateVariablesDeterminingDependencies: [
543
+ "targetComponent",
544
+ "componentIndex",
545
+ "propName",
546
+ "targetSubnames",
547
+ "targetSubnamesComponentIndex",
548
+ "obtainPropFromComposite",
549
+ "linkAttrForDetermineDeps",
550
+ ],
551
+ additionalStateVariablesDefined: ["addLevelToAssignNames"],
552
+ returnDependencies: function ({ stateValues, componentInfoObjects }) {
553
+ let dependencies = {};
554
+
555
+ let addLevelToAssignNames = false;
556
+ let useReplacements = false;
557
+
558
+ if (stateValues.targetComponent !== null) {
559
+ if (
560
+ componentInfoObjects.isCompositeComponent({
561
+ componentType: stateValues.targetComponent.componentType,
562
+ includeNonStandard: false,
563
+ }) &&
564
+ !(stateValues.propName && stateValues.obtainPropFromComposite)
565
+ ) {
566
+ if (stateValues.linkAttrForDetermineDeps) {
567
+ useReplacements = true;
568
+
569
+ let targetSubnamesComponentIndex =
570
+ stateValues.targetSubnamesComponentIndex;
571
+ if (targetSubnamesComponentIndex) {
572
+ targetSubnamesComponentIndex = [
573
+ ...targetSubnamesComponentIndex,
574
+ ];
575
+ }
576
+ dependencies.targets = {
577
+ dependencyType: "replacement",
578
+ compositeName: stateValues.targetComponent.componentName,
579
+ recursive: true,
580
+ componentIndex: stateValues.componentIndex,
581
+ targetSubnames: stateValues.targetSubnames,
582
+ targetSubnamesComponentIndex,
583
+ };
584
+ } else {
585
+ addLevelToAssignNames = true;
586
+ }
587
+ }
588
+
589
+ if (
590
+ !useReplacements &&
591
+ (stateValues.componentIndex === null ||
592
+ stateValues.componentIndex === 1)
593
+ ) {
594
+ // if we don't have a composite, componentIndex can only match if it is 1
595
+ dependencies.targets = {
596
+ dependencyType: "stateVariable",
597
+ variableName: "targetComponent",
598
+ };
599
+ }
600
+ }
601
+
602
+ dependencies.addLevelToAssignNames = {
603
+ dependencyType: "value",
604
+ value: addLevelToAssignNames,
605
+ };
606
+
607
+ return dependencies;
608
+ },
609
+ definition({ dependencyValues }) {
610
+ let replacementSourceIdentities = null;
611
+ if (dependencyValues.targets) {
612
+ replacementSourceIdentities = dependencyValues.targets;
613
+ if (!Array.isArray(replacementSourceIdentities)) {
614
+ replacementSourceIdentities = [replacementSourceIdentities];
615
+ }
616
+ }
617
+ return {
618
+ setValue: {
619
+ replacementSourceIdentities,
620
+ addLevelToAssignNames: dependencyValues.addLevelToAssignNames,
621
+ },
622
+ };
623
+ },
624
+ };
625
+
626
+ // only reason for replacementSources state variable
627
+ // is to create any array entry state variables from prop
628
+ // when resolve determineDependencies
629
+ stateVariableDefinitions.replacementSources = {
630
+ stateVariablesDeterminingDependencies: [
631
+ "replacementSourceIdentities",
632
+ "propName",
633
+ "propIndex",
634
+ "isPlainMacro",
635
+ "isPlainCopy",
636
+ ],
637
+ additionalStateVariablesDefined: ["effectivePropNameBySource"],
638
+ returnDependencies: function ({ stateValues, componentInfoObjects }) {
639
+ let dependencies = {
640
+ replacementSourceIdentities: {
641
+ dependencyType: "stateVariable",
642
+ variableName: "replacementSourceIdentities",
643
+ },
644
+ propIndex: {
645
+ dependencyType: "stateVariable",
646
+ variableName: "propIndex",
647
+ },
648
+ };
649
+
650
+ if (!stateValues.propName && stateValues.propIndex !== null) {
651
+ throw Error(
652
+ `You cannot specify a propIndex without specifying a prop.`,
653
+ );
654
+ }
655
+
656
+ if (stateValues.replacementSourceIdentities !== null) {
657
+ for (let [
658
+ ind,
659
+ source,
660
+ ] of stateValues.replacementSourceIdentities.entries()) {
661
+ let thisPropName = stateValues.propName;
662
+
663
+ if (stateValues.isPlainMacro) {
664
+ thisPropName =
665
+ componentInfoObjects.allComponentClasses[source.componentType]
666
+ .variableForPlainMacro;
667
+ } else if (stateValues.isPlainCopy) {
668
+ thisPropName =
669
+ componentInfoObjects.allComponentClasses[source.componentType]
670
+ .variableForPlainCopy;
671
+ }
672
+
673
+ let thisTarget;
674
+
675
+ if (thisPropName) {
676
+ dependencies["propName" + ind] = {
677
+ dependencyType: "value",
678
+ value: thisPropName,
679
+ };
680
+
681
+ let propIndex = stateValues.propIndex;
682
+ if (propIndex) {
683
+ // make propIndex be a shallow copy
684
+ // so that can detect if it changed
685
+ // when update dependencies
686
+ propIndex = [...propIndex];
687
+ }
688
+ thisTarget = {
689
+ dependencyType: "stateVariable",
690
+ componentName: source.componentName,
691
+ variableName: thisPropName,
692
+ returnAsComponentObject: true,
693
+ variablesOptional: true,
694
+ propIndex,
695
+ caseInsensitiveVariableMatch: true,
696
+ publicStateVariablesOnly: true,
697
+ useMappedVariableNames: true,
698
+ };
699
+ } else {
700
+ thisTarget = {
701
+ dependencyType: "componentIdentity",
702
+ componentName: source.componentName,
703
+ };
704
+ }
705
+
706
+ dependencies["target" + ind] = thisTarget;
707
+ }
708
+ }
709
+
710
+ return dependencies;
711
+ },
712
+ definition({ dependencyValues }) {
713
+ let replacementSources = null;
714
+ let effectivePropNameBySource = null;
715
+
716
+ if (dependencyValues.replacementSourceIdentities !== null) {
717
+ replacementSources = [];
718
+ effectivePropNameBySource = [];
719
+
720
+ for (let ind in dependencyValues.replacementSourceIdentities) {
721
+ let targetDep = dependencyValues["target" + ind];
722
+ if (targetDep) {
723
+ replacementSources.push(targetDep);
724
+
725
+ let propName;
726
+ if (targetDep.stateValues) {
727
+ propName = Object.keys(targetDep.stateValues)[0];
728
+ }
729
+ if (!propName && dependencyValues["propName" + ind]) {
730
+ // a propName was specified, but it just wasn't found
731
+ propName = "__prop_name_not_found";
732
+ }
733
+ effectivePropNameBySource.push(propName);
734
+ }
735
+ }
736
+ }
737
+
738
+ return { setValue: { replacementSources, effectivePropNameBySource } };
739
+ },
740
+ };
741
+
742
+ stateVariableDefinitions.numComponentsSpecified = {
743
+ returnDependencies: () => ({
744
+ numComponentsAttr: {
745
+ dependencyType: "attributePrimitive",
746
+ attributeName: "numComponents",
747
+ },
748
+ typeAttr: {
749
+ dependencyType: "attributePrimitive",
750
+ attributeName: "createComponentOfType",
751
+ },
752
+ }),
753
+ definition({ dependencyValues, componentInfoObjects }) {
754
+ let numComponentsSpecified;
755
+
756
+ if (dependencyValues.typeAttr) {
757
+ let componentType =
758
+ componentInfoObjects.componentTypeLowerCaseMapping[
759
+ dependencyValues.typeAttr.toLowerCase()
760
+ ];
761
+
762
+ if (!(componentType in componentInfoObjects.allComponentClasses)) {
763
+ throw Error(
764
+ `Invalid componentType ${dependencyValues.typeAttr} of copy.`,
765
+ );
766
+ }
767
+ if (dependencyValues.numComponentsAttr !== null) {
768
+ numComponentsSpecified = dependencyValues.numComponentsAttr;
769
+ } else {
770
+ numComponentsSpecified = 1;
771
+ }
772
+ } else if (dependencyValues.numComponentsAttr !== null) {
773
+ throw Error(
774
+ `You must specify createComponentOfType when specifying numComponents for a copy.`,
775
+ );
776
+ } else {
777
+ numComponentsSpecified = null;
778
+ }
779
+
780
+ return { setValue: { numComponentsSpecified } };
781
+ },
782
+ };
783
+
784
+ stateVariableDefinitions.link = {
785
+ returnDependencies: () => ({
786
+ linkAttr: {
787
+ dependencyType: "attributePrimitive",
788
+ attributeName: "link",
789
+ },
790
+ serializedComponentsForCid: {
791
+ dependencyType: "stateVariable",
792
+ variableName: "serializedComponentsForCid",
793
+ },
794
+ replacementSourceIdentities: {
795
+ dependencyType: "stateVariable",
796
+ variableName: "replacementSourceIdentities",
797
+ },
798
+ }),
799
+ definition({ dependencyValues, componentInfoObjects }) {
800
+ let link;
801
+ if (dependencyValues.linkAttr === null) {
802
+ if (
803
+ dependencyValues.serializedComponentsForCid ||
804
+ (dependencyValues.replacementSourceIdentities &&
805
+ dependencyValues.replacementSourceIdentities.some((x) =>
806
+ componentInfoObjects.isInheritedComponentType({
807
+ inheritedComponentType: x.componentType,
808
+ baseComponentType: "module",
809
+ }),
810
+ ))
811
+ ) {
812
+ link = false;
813
+ } else {
814
+ link = true;
815
+ }
816
+ } else {
817
+ link = dependencyValues.linkAttr !== false;
818
+ }
819
+
820
+ return { setValue: { link } };
821
+ },
822
+ };
823
+
824
+ stateVariableDefinitions.readyToExpandWhenResolved = {
825
+ stateVariablesDeterminingDependencies: [
826
+ "targetComponent",
827
+ "propName",
828
+ "obtainPropFromComposite",
829
+ "link",
830
+ ],
831
+ returnDependencies({ stateValues, componentInfoObjects }) {
832
+ let dependencies = {
833
+ targetComponent: {
834
+ dependencyType: "stateVariable",
835
+ variableName: "targetComponent",
836
+ },
837
+ needsReplacementsUpdatedWhenStale: {
838
+ dependencyType: "stateVariable",
839
+ variableName: "needsReplacementsUpdatedWhenStale",
840
+ },
841
+ // replacementSources: {
842
+ // dependencyType: "stateVariable",
843
+ // variableName: "replacementSources",
844
+ // },
845
+ serializedComponentsForCid: {
846
+ dependencyType: "stateVariable",
847
+ variableName: "serializedComponentsForCid",
848
+ },
849
+ link: {
850
+ dependencyType: "stateVariable",
851
+ variableName: "link",
852
+ },
853
+ // propName: {
854
+ // dependencyType: "stateVariable",
855
+ // variableName: "propName",
856
+ // },
857
+ };
858
+ if (
859
+ stateValues.targetComponent &&
860
+ componentInfoObjects.isCompositeComponent({
861
+ componentType: stateValues.targetComponent.componentType,
862
+ includeNonStandard: false,
863
+ }) &&
864
+ !(stateValues.propName && stateValues.obtainPropFromComposite)
865
+ ) {
866
+ dependencies.targetReadyToExpandWhenResolved = {
867
+ dependencyType: "stateVariable",
868
+ componentName: stateValues.targetComponent.componentName,
869
+ variableName: "readyToExpandWhenResolved",
870
+ };
871
+ }
872
+
873
+ // since will be creating complete replacement when expand,
874
+ // make sure all replacement sources are resolved
875
+ if (!stateValues.link) {
876
+ dependencies.replacementSources = {
877
+ dependencyType: "stateVariable",
878
+ variableName: "replacementSources",
879
+ };
880
+ }
881
+
882
+ return dependencies;
883
+ },
884
+ definition() {
885
+ return { setValue: { readyToExpandWhenResolved: true } };
886
+ },
887
+ };
888
+
889
+ stateVariableDefinitions.needsReplacementsUpdatedWhenStale = {
890
+ stateVariablesDeterminingDependencies: [
891
+ "targetComponent",
892
+ "replacementSourceIdentities",
893
+ "effectivePropNameBySource",
894
+ "propName",
895
+ "obtainPropFromComposite",
896
+ "link",
897
+ "removeEmptyArrayEntries",
898
+ ],
899
+ returnDependencies: function ({ stateValues, componentInfoObjects }) {
900
+ // if don't link, never update replacements
901
+ if (!stateValues.link) {
902
+ return {};
903
+ }
904
+
905
+ let dependencies = {
906
+ targetComponent: {
907
+ dependencyType: "stateVariable",
908
+ variableName: "targetComponent",
909
+ },
910
+ targetInactive: {
911
+ dependencyType: "stateVariable",
912
+ variableName: "targetInactive",
913
+ },
914
+ replacementSourceIdentities: {
915
+ dependencyType: "stateVariable",
916
+ variableName: "replacementSourceIdentities",
917
+ },
918
+ propIndex: {
919
+ dependencyType: "stateVariable",
920
+ variableName: "propIndex",
921
+ },
922
+ };
923
+
924
+ if (stateValues.effectivePropNameBySource !== null) {
925
+ for (let [
926
+ ind,
927
+ propName,
928
+ ] of stateValues.effectivePropNameBySource.entries()) {
929
+ if (propName) {
930
+ // if we have a propName, then we just need the array size state variable,
931
+ // as we need to update only if a component changes
932
+ // or the size of the corresponding array changes.
933
+ // (The actual values of the prop state variables will
934
+ // be updated directly through dependencies)
935
+
936
+ let source = stateValues.replacementSourceIdentities[ind];
937
+
938
+ dependencies["sourceArraySize" + ind] = {
939
+ dependencyType: "stateVariableArraySize",
940
+ componentName: source.componentName,
941
+ variableName: propName,
942
+ variablesOptional: true,
943
+ caseInsensitiveVariableMatch: true,
944
+ };
945
+
946
+ dependencies["sourceComponentType" + ind] = {
947
+ dependencyType: "stateVariableComponentType",
948
+ componentName: source.componentName,
949
+ variableName: propName,
950
+ variablesOptional: true,
951
+ caseInsensitiveVariableMatch: true,
952
+ };
953
+ }
954
+ }
955
+ }
956
+
957
+ if (
958
+ stateValues.targetComponent !== null &&
959
+ componentInfoObjects.isCompositeComponent({
960
+ componentType: stateValues.targetComponent.componentType,
961
+ includeNonStandard: false,
962
+ }) &&
963
+ !(stateValues.propName && stateValues.obtainPropFromComposite)
964
+ ) {
965
+ // Include identities of all replacements (and inactive target variable)
966
+ // without filtering by componentIndex,
967
+ // as components other than the one at that index could change
968
+ // the identity of the component at the relevant index
969
+
970
+ dependencies.allReplacementIdentities = {
971
+ dependencyType: "replacement",
972
+ compositeName: stateValues.targetComponent.componentName,
973
+ recursive: true,
974
+ variableNames: ["isInactiveCompositeReplacement"],
975
+ };
976
+ }
977
+
978
+ if (stateValues.removeEmptyArrayEntries) {
979
+ // if we are to remove empty array entries,
980
+ // then we have to recalculate whenever replacement sources change
981
+ dependencies.replacementSources = {
982
+ dependencyType: "stateVariable",
983
+ variableName: "replacementSources",
984
+ };
985
+ }
986
+
987
+ return dependencies;
988
+ },
989
+ // the whole point of this state variable is to return updateReplacements
990
+ // on mark stale
991
+ markStale() {
992
+ return { updateReplacements: true };
993
+ },
994
+ definition: () => ({
995
+ setValue: { needsReplacementsUpdatedWhenStale: true },
996
+ }),
997
+ };
998
+
999
+ stateVariableDefinitions.effectiveAssignNames = {
1000
+ returnDependencies: () => ({
1001
+ assignNames: {
1002
+ dependencyType: "doenetAttribute",
1003
+ attributeName: "assignNames",
1004
+ },
1005
+ addLevelToAssignNames: {
1006
+ dependencyType: "stateVariable",
1007
+ variableName: "addLevelToAssignNames",
1008
+ },
1009
+ }),
1010
+ definition({ dependencyValues }) {
1011
+ let effectiveAssignNames = dependencyValues.assignNames;
1012
+
1013
+ if (effectiveAssignNames && dependencyValues.addLevelToAssignNames) {
1014
+ effectiveAssignNames = [effectiveAssignNames];
1015
+ }
1016
+
1017
+ return { setValue: { effectiveAssignNames } };
1018
+ },
1019
+ };
1020
+
1021
+ return stateVariableDefinitions;
1022
+ }
1023
+
1024
+ static async createSerializedReplacements({
1025
+ component,
1026
+ components,
1027
+ workspace,
1028
+ componentInfoObjects,
1029
+ flags,
1030
+ resolveItem,
1031
+ publicCaseInsensitiveAliasSubstitutions,
1032
+ }) {
1033
+ // console.log(`create serialized replacements of ${component.componentName}`)
1034
+
1035
+ // console.log(await component.stateValues.targetComponent);
1036
+ // console.log(await component.stateValues.effectivePropNameBySource);
1037
+ // console.log(await component.stateValues.replacementSources)
1038
+
1039
+ // evaluate numComponentsSpecified so get error if specify numComponents without createComponentOfType
1040
+ await component.stateValues.numComponentsSpecified;
1041
+
1042
+ workspace.numReplacementsBySource = [];
1043
+ workspace.numNonStringReplacementsBySource = [];
1044
+ workspace.propVariablesCopiedBySource = [];
1045
+ workspace.sourceNames = [];
1046
+ workspace.uniqueIdentifiersUsedBySource = {};
1047
+
1048
+ let newNamespace = component.attributes.newNamespace?.primitive;
1049
+
1050
+ let compositeAttributesObj = this.createAttributesObject();
1051
+
1052
+ let assignNames = await component.stateValues.effectiveAssignNames;
1053
+
1054
+ let serializedComponentsForCid = await component.stateValues
1055
+ .serializedComponentsForCid;
1056
+
1057
+ if (serializedComponentsForCid) {
1058
+ let replacements = deepClone([serializedComponentsForCid[0]]);
1059
+
1060
+ let additionalChildren = deepClone(serializedComponentsForCid.slice(1));
1061
+
1062
+ if (replacements[0].children) {
1063
+ let namespace;
1064
+ if (replacements[0].componentName) {
1065
+ namespace = replacements[0].componentName + "/";
1066
+ } else {
1067
+ namespace = replacements[0].originalName + "/";
1068
+ }
1069
+
1070
+ if (component.doenetAttributes.keptNewNamespaceOfLastChild) {
1071
+ namespace = namespace.slice(0, namespace.length - 1);
1072
+ let lastSlash = namespace.lastIndexOf("/");
1073
+ namespace = namespace.slice(0, lastSlash + 1);
1074
+ }
1075
+
1076
+ serializeFunctions.restrictTNamesToNamespace({
1077
+ components: replacements[0].children,
1078
+ namespace,
1079
+ invalidateReferencesToBaseNamespace:
1080
+ component.doenetAttributes.keptNewNamespaceOfLastChild,
1081
+ });
1082
+ }
1083
+
1084
+ if (replacements[0].componentType === "externalContent") {
1085
+ // replacements[0] is externalContent
1086
+ // add any specified attributes to its children
1087
+ for (let repl of replacements[0].children) {
1088
+ if (typeof repl !== "object") {
1089
+ continue;
1090
+ }
1091
+
1092
+ // add attributes
1093
+ if (!repl.attributes) {
1094
+ repl.attributes = {};
1095
+ }
1096
+ let attributesFromComposite = convertAttributesForComponentType({
1097
+ attributes: component.attributes,
1098
+ componentType: repl.componentType,
1099
+ componentInfoObjects,
1100
+ compositeAttributesObj,
1101
+ compositeCreatesNewNamespace: newNamespace,
1102
+ flags,
1103
+ });
1104
+
1105
+ for (let attrName in attributesFromComposite) {
1106
+ let attribute = attributesFromComposite[attrName];
1107
+ if (attribute.component) {
1108
+ serializeFunctions.setTNamesToAbsolute([attribute.component]);
1109
+ } else if (attribute.childrenForComponent) {
1110
+ serializeFunctions.setTNamesToAbsolute(
1111
+ attribute.childrenForComponent,
1112
+ );
1113
+ }
1114
+ }
1115
+
1116
+ Object.assign(repl.attributes, attributesFromComposite);
1117
+ }
1118
+ } else {
1119
+ // if replacements[0] is not an externalContent, add attributes to replacements[0] itself
1120
+ if (!replacements[0].attributes) {
1121
+ replacements[0].attributes = {};
1122
+ }
1123
+ let attributesFromComposite = convertAttributesForComponentType({
1124
+ attributes: component.attributes,
1125
+ componentType: replacements[0].componentType,
1126
+ componentInfoObjects,
1127
+ compositeAttributesObj,
1128
+ compositeCreatesNewNamespace: newNamespace,
1129
+ flags,
1130
+ });
1131
+
1132
+ for (let attrName in attributesFromComposite) {
1133
+ let attribute = attributesFromComposite[attrName];
1134
+ if (attribute.component) {
1135
+ serializeFunctions.setTNamesToAbsolute([attribute.component]);
1136
+ } else if (attribute.childrenForComponent) {
1137
+ serializeFunctions.setTNamesToAbsolute(
1138
+ attribute.childrenForComponent,
1139
+ );
1140
+ }
1141
+ }
1142
+
1143
+ Object.assign(replacements[0].attributes, attributesFromComposite);
1144
+ }
1145
+
1146
+ let processResult = serializeFunctions.processAssignNames({
1147
+ assignNames,
1148
+ assignNewNamespaces:
1149
+ component.attributes.assignNewNamespaces?.primitive,
1150
+ serializedComponents: replacements,
1151
+ parentName: component.componentName,
1152
+ parentCreatesNewNamespace: newNamespace,
1153
+ componentInfoObjects,
1154
+ });
1155
+
1156
+ replacements = processResult.serializedComponents;
1157
+
1158
+ // if have copyFromURI, then add additional children from the composite itself
1159
+ if (
1160
+ component.doenetAttributes.fromCopyFromURI &&
1161
+ additionalChildren.length > 0
1162
+ ) {
1163
+ this.addChildrenFromComposite({
1164
+ replacements,
1165
+ children: additionalChildren,
1166
+ assignNewNamespaces:
1167
+ component.attributes.assignNewNamespaces?.primitive,
1168
+ componentInfoObjects,
1169
+ });
1170
+ }
1171
+
1172
+ let verificationResult = await verifyReplacementsMatchSpecifiedType({
1173
+ component,
1174
+ replacements,
1175
+ assignNames,
1176
+ workspace,
1177
+ componentInfoObjects,
1178
+ compositeAttributesObj,
1179
+ flags,
1180
+ });
1181
+
1182
+ return { replacements: verificationResult.replacements };
1183
+ }
1184
+
1185
+ // if have a sourceIndex, it means we are copying the indexAlias from a source
1186
+ // so we just return a number that is the index
1187
+ let sourceIndex = await component.stateValues.sourceIndex;
1188
+ if (sourceIndex !== null) {
1189
+ let attributesFromComposite = convertAttributesForComponentType({
1190
+ attributes: component.attributes,
1191
+ componentType: "number",
1192
+ componentInfoObjects,
1193
+ compositeAttributesObj,
1194
+ compositeCreatesNewNamespace: newNamespace,
1195
+ flags,
1196
+ });
1197
+
1198
+ let replacements = [
1199
+ {
1200
+ componentType: "number",
1201
+ attributes: attributesFromComposite,
1202
+ state: { value: sourceIndex, fixed: true },
1203
+ },
1204
+ ];
1205
+
1206
+ let processResult = serializeFunctions.processAssignNames({
1207
+ assignNames,
1208
+ serializedComponents: replacements,
1209
+ parentName: component.componentName,
1210
+ parentCreatesNewNamespace: newNamespace,
1211
+ componentInfoObjects,
1212
+ });
1213
+
1214
+ let verificationResult = await verifyReplacementsMatchSpecifiedType({
1215
+ component,
1216
+ replacements: processResult.serializedComponents,
1217
+ assignNames,
1218
+ workspace,
1219
+ componentInfoObjects,
1220
+ compositeAttributesObj,
1221
+ flags,
1222
+ });
1223
+
1224
+ return { replacements: verificationResult.replacements };
1225
+ }
1226
+
1227
+ let replacementSourceIdentities = await component.stateValues
1228
+ .replacementSourceIdentities;
1229
+ if (
1230
+ !(await component.stateValues.targetComponent) ||
1231
+ !replacementSourceIdentities
1232
+ ) {
1233
+ // no valid target, so no replacements
1234
+ let replacements = [];
1235
+
1236
+ if (component.doenetAttributes.fromCopyTarget) {
1237
+ // even though don't have valid target,
1238
+ // if have copyTarget, then include children added directly to component
1239
+
1240
+ let componentType =
1241
+ componentInfoObjects.componentTypeLowerCaseMapping[
1242
+ component.attributes.createComponentOfType.primitive.toLowerCase()
1243
+ ];
1244
+
1245
+ let componentClass =
1246
+ componentInfoObjects.allComponentClasses[componentType];
1247
+
1248
+ let attributesFromComposite = convertAttributesForComponentType({
1249
+ attributes: component.attributes,
1250
+ componentType,
1251
+ componentInfoObjects,
1252
+ compositeAttributesObj,
1253
+ compositeCreatesNewNamespace: newNamespace,
1254
+ flags,
1255
+ });
1256
+
1257
+ workspace.uniqueIdentifiersUsedBySource[0] = [];
1258
+ let uniqueIdentifierBase = componentType + "|empty";
1259
+ let uniqueIdentifier = getUniqueIdentifierFromBase(
1260
+ uniqueIdentifierBase,
1261
+ workspace.uniqueIdentifiersUsedBySource[0],
1262
+ );
1263
+
1264
+ let children = deepClone(component.serializedChildren);
1265
+ if (!componentClass.includeBlankStringChildren) {
1266
+ children = children.filter(
1267
+ (x) => typeof x !== "string" || x.trim() !== "",
1268
+ );
1269
+ }
1270
+
1271
+ let attributes = attributesFromComposite;
1272
+ if (component.attributes.assignNewNamespaces?.primitive) {
1273
+ attributes.newNamespace = { primitive: true };
1274
+ }
1275
+
1276
+ replacements = [
1277
+ {
1278
+ componentType,
1279
+ attributes,
1280
+ children,
1281
+ uniqueIdentifier,
1282
+ },
1283
+ ];
1284
+
1285
+ let processResult = serializeFunctions.processAssignNames({
1286
+ assignNames,
1287
+ serializedComponents: replacements,
1288
+ parentName: component.componentName,
1289
+ componentInfoObjects,
1290
+ originalNamesAreConsistent: true,
1291
+ });
1292
+
1293
+ replacements = processResult.serializedComponents;
1294
+
1295
+ workspace.numReplacementsBySource.push(replacements.length);
1296
+ workspace.numNonStringReplacementsBySource.push(
1297
+ replacements.filter((x) => typeof x !== "string").length,
1298
+ );
1299
+ }
1300
+
1301
+ let verificationResult = await verifyReplacementsMatchSpecifiedType({
1302
+ component,
1303
+ replacements,
1304
+ assignNames,
1305
+ workspace,
1306
+ componentInfoObjects,
1307
+ compositeAttributesObj,
1308
+ });
1309
+
1310
+ return { replacements: verificationResult.replacements };
1311
+ }
1312
+
1313
+ // resolve determine dependencies of replacementSources
1314
+ // and resolve recalculateDownstreamComponents of its target dependencies
1315
+ // so any array entry prop is created
1316
+ let resolveResult = await resolveItem({
1317
+ componentName: component.componentName,
1318
+ type: "determineDependencies",
1319
+ stateVariable: "replacementSources",
1320
+ dependency: "__determine_dependencies",
1321
+ expandComposites: false,
1322
+ });
1323
+
1324
+ if (!resolveResult.success) {
1325
+ throw Error(
1326
+ `Couldn't resolve determineDependencies of replacementSources of ${component.componentName}`,
1327
+ );
1328
+ }
1329
+
1330
+ let effectivePropNameBySource = await component.stateValues
1331
+ .effectivePropNameBySource;
1332
+ for (let ind in replacementSourceIdentities) {
1333
+ let thisPropName = effectivePropNameBySource[ind];
1334
+
1335
+ if (thisPropName) {
1336
+ resolveResult = await resolveItem({
1337
+ componentName: component.componentName,
1338
+ type: "recalculateDownstreamComponents",
1339
+ stateVariable: "replacementSources",
1340
+ dependency: "target" + ind,
1341
+ expandComposites: false,
1342
+ });
1343
+
1344
+ if (!resolveResult.success) {
1345
+ throw Error(
1346
+ `Couldn't resolve recalculateDownstreamComponents for target${ind} of replacementSources of ${component.componentName}`,
1347
+ );
1348
+ }
1349
+ }
1350
+ }
1351
+
1352
+ let replacements = [];
1353
+
1354
+ let numReplacementsBySource = [];
1355
+ let numNonStringReplacementsBySource = [];
1356
+ let numReplacementsSoFar = 0;
1357
+ let numNonStringReplacementsSoFar = 0;
1358
+
1359
+ for (let sourceNum in replacementSourceIdentities) {
1360
+ let uniqueIdentifiersUsed = (workspace.uniqueIdentifiersUsedBySource[
1361
+ sourceNum
1362
+ ] = []);
1363
+
1364
+ let numComponentsForSource;
1365
+
1366
+ if (component.attributes.createComponentOfType?.primitive) {
1367
+ let numComponentsTotal = await component.stateValues
1368
+ .numComponentsSpecified;
1369
+ let numSources = replacementSourceIdentities.length;
1370
+
1371
+ // arbitrarily divide these components among the sources
1372
+ numComponentsForSource = Math.floor(numComponentsTotal / numSources);
1373
+ let nExtras = numComponentsTotal % numSources;
1374
+ if (sourceNum < nExtras) {
1375
+ numComponentsForSource++;
1376
+ }
1377
+ }
1378
+
1379
+ let results = await this.createReplacementForSource({
1380
+ component,
1381
+ sourceNum,
1382
+ components,
1383
+ numReplacementsSoFar,
1384
+ numNonStringReplacementsSoFar,
1385
+ uniqueIdentifiersUsed,
1386
+ compositeAttributesObj,
1387
+ componentInfoObjects,
1388
+ numComponentsForSource,
1389
+ publicCaseInsensitiveAliasSubstitutions,
1390
+ flags,
1391
+ fromCopyTarget:
1392
+ Number(sourceNum) === 0 && component.doenetAttributes.fromCopyTarget,
1393
+ });
1394
+
1395
+ workspace.propVariablesCopiedBySource[sourceNum] =
1396
+ results.propVariablesCopiedByReplacement;
1397
+
1398
+ let sourceReplacements = results.serializedReplacements;
1399
+ numReplacementsBySource[sourceNum] = sourceReplacements.length;
1400
+ numNonStringReplacementsBySource[sourceNum] = sourceReplacements.filter(
1401
+ (x) => typeof x !== "string",
1402
+ ).length;
1403
+ numReplacementsSoFar += numReplacementsBySource[sourceNum];
1404
+ numNonStringReplacementsSoFar +=
1405
+ numNonStringReplacementsBySource[sourceNum];
1406
+ replacements.push(...sourceReplacements);
1407
+ }
1408
+
1409
+ workspace.numReplacementsBySource = numReplacementsBySource;
1410
+ workspace.numNonStringReplacementsBySource =
1411
+ numNonStringReplacementsBySource;
1412
+ workspace.sourceNames = replacementSourceIdentities.map(
1413
+ (x) => x.componentName,
1414
+ );
1415
+
1416
+ let verificationResult = await verifyReplacementsMatchSpecifiedType({
1417
+ component,
1418
+ replacements,
1419
+ assignNames,
1420
+ workspace,
1421
+ componentInfoObjects,
1422
+ compositeAttributesObj,
1423
+ flags,
1424
+ });
1425
+
1426
+ // console.log(`serialized replacements for ${component.componentName}`)
1427
+ // console.log(JSON.parse(JSON.stringify(verificationResult.replacements)))
1428
+
1429
+ return { replacements: verificationResult.replacements };
1430
+ }
1431
+
1432
+ static async createReplacementForSource({
1433
+ component,
1434
+ sourceNum,
1435
+ components,
1436
+ numReplacementsSoFar,
1437
+ numNonStringReplacementsSoFar,
1438
+ uniqueIdentifiersUsed,
1439
+ compositeAttributesObj,
1440
+ componentInfoObjects,
1441
+ numComponentsForSource,
1442
+ publicCaseInsensitiveAliasSubstitutions,
1443
+ flags,
1444
+ fromCopyTarget,
1445
+ }) {
1446
+ // console.log(`create replacement for sourceNum ${sourceNum}`)
1447
+ // console.log(`propName: ${component.stateValues.effectivePropNameBySource[sourceNum]}`)
1448
+
1449
+ let replacementSource = (
1450
+ await component.stateValues.replacementSourceIdentities
1451
+ )[sourceNum];
1452
+ if (typeof replacementSource !== "object") {
1453
+ return { serializedReplacements: [replacementSource] };
1454
+ }
1455
+ let replacementSourceComponent =
1456
+ components[replacementSource.componentName];
1457
+
1458
+ // if not linking or removing empty array entries,
1459
+ // then replacementSources is resolved,
1460
+ // which we need for state variable value
1461
+ let link = await component.stateValues.link;
1462
+ if (!link || (await component.stateValues.removeEmptyArrayEntries)) {
1463
+ replacementSource = (await component.stateValues.replacementSources)[
1464
+ sourceNum
1465
+ ];
1466
+ }
1467
+
1468
+ let newNamespace = component.attributes.newNamespace?.primitive;
1469
+
1470
+ let assignNames = await component.stateValues.effectiveAssignNames;
1471
+
1472
+ // if creating copy from a prop
1473
+ // manually create the serialized component
1474
+ let propName = (await component.stateValues.effectivePropNameBySource)[
1475
+ sourceNum
1476
+ ];
1477
+ if (propName) {
1478
+ let results = await replacementFromProp({
1479
+ component,
1480
+ components,
1481
+ replacementSource,
1482
+ propName,
1483
+ numReplacementsSoFar,
1484
+ numNonStringReplacementsSoFar,
1485
+ uniqueIdentifiersUsed,
1486
+ compositeAttributesObj,
1487
+ componentInfoObjects,
1488
+ numComponentsForSource,
1489
+ publicCaseInsensitiveAliasSubstitutions,
1490
+ flags,
1491
+ });
1492
+
1493
+ let processResult = serializeFunctions.processAssignNames({
1494
+ assignNames,
1495
+ serializedComponents: results.serializedReplacements,
1496
+ parentName: component.componentName,
1497
+ parentCreatesNewNamespace: newNamespace,
1498
+ indOffset: numNonStringReplacementsSoFar,
1499
+ componentInfoObjects,
1500
+ });
1501
+
1502
+ return {
1503
+ serializedReplacements: processResult.serializedComponents,
1504
+ propVariablesCopiedByReplacement:
1505
+ results.propVariablesCopiedByReplacement,
1506
+ };
1507
+ }
1508
+
1509
+ // if creating copy directly from the target component,
1510
+ // create a serialized copy of the entire component
1511
+
1512
+ let sourceAttributesToIgnore = await component.stateValues
1513
+ .sourceAttributesToIgnore;
1514
+
1515
+ let serializedReplacements = [
1516
+ await replacementSourceComponent.serialize({
1517
+ copyAll: !link,
1518
+ copyVariants: !link,
1519
+ sourceAttributesToIgnore,
1520
+ }),
1521
+ ];
1522
+
1523
+ // when copying with link=false, ignore fixed if from essential state
1524
+ // so that, for example, a copy from a sequence with link=false is not fixed
1525
+ if (!link && serializedReplacements[0].state?.fixed !== undefined) {
1526
+ delete serializedReplacements[0].state.fixed;
1527
+ }
1528
+
1529
+ // console.log(`serializedReplacements for ${component.componentName}`);
1530
+ // console.log(JSON.parse(JSON.stringify(serializedReplacements)));
1531
+
1532
+ serializedReplacements = postProcessCopy({
1533
+ serializedComponents: serializedReplacements,
1534
+ componentName: component.componentName,
1535
+ uniqueIdentifiersUsed,
1536
+ addShadowDependencies: link,
1537
+ unlinkExternalCopies: !link,
1538
+ });
1539
+
1540
+ if (serializedReplacements.length > 0) {
1541
+ delete serializedReplacements[0].doenetAttributes
1542
+ .haveNewNamespaceOnlyFromShadow;
1543
+ }
1544
+
1545
+ for (let repl of serializedReplacements) {
1546
+ if (typeof repl !== "object") {
1547
+ continue;
1548
+ }
1549
+
1550
+ // add attributes
1551
+ if (!repl.attributes) {
1552
+ repl.attributes = {};
1553
+ }
1554
+ let attributesFromComposite = convertAttributesForComponentType({
1555
+ attributes: component.attributes,
1556
+ componentType: repl.componentType,
1557
+ componentInfoObjects,
1558
+ compositeAttributesObj,
1559
+ compositeCreatesNewNamespace: newNamespace,
1560
+ flags,
1561
+ });
1562
+ Object.assign(repl.attributes, attributesFromComposite);
1563
+ }
1564
+
1565
+ if (
1566
+ serializedReplacements[0].attributes.newNamespace?.primitive &&
1567
+ !component.attributes.assignNewNamespaces?.primitive
1568
+ ) {
1569
+ serializedReplacements[0].doenetAttributes.haveNewNamespaceOnlyFromShadow = true;
1570
+ }
1571
+
1572
+ let processResult = serializeFunctions.processAssignNames({
1573
+ assignNames,
1574
+ assignNewNamespaces: component.attributes.assignNewNamespaces?.primitive,
1575
+ serializedComponents: serializedReplacements,
1576
+ parentName: component.componentName,
1577
+ parentCreatesNewNamespace: newNamespace,
1578
+ indOffset: numNonStringReplacementsSoFar,
1579
+ componentInfoObjects,
1580
+ originalNamesAreConsistent: newNamespace && !assignNames,
1581
+ });
1582
+
1583
+ serializedReplacements = processResult.serializedComponents;
1584
+
1585
+ // if have copy target, then add additional children from the composite itself
1586
+ if (
1587
+ fromCopyTarget &&
1588
+ serializedReplacements.length === 1 &&
1589
+ component.serializedChildren.length > 0
1590
+ ) {
1591
+ this.addChildrenFromComposite({
1592
+ replacements: serializedReplacements,
1593
+ children: component.serializedChildren,
1594
+ assignNewNamespaces:
1595
+ component.attributes.assignNewNamespaces?.primitive,
1596
+ componentInfoObjects,
1597
+ });
1598
+ }
1599
+
1600
+ // console.log(`ending serializedReplacements for ${component.componentName}`);
1601
+ // console.log(JSON.parse(JSON.stringify(serializedReplacements)));
1602
+
1603
+ return { serializedReplacements };
1604
+ }
1605
+
1606
+ static addChildrenFromComposite({
1607
+ replacements,
1608
+ children,
1609
+ assignNewNamespaces,
1610
+ componentInfoObjects,
1611
+ }) {
1612
+ let repl = replacements[0];
1613
+ if (!repl.children) {
1614
+ repl.children = [];
1615
+ }
1616
+ let newChildren = deepClone(children);
1617
+ let componentClass =
1618
+ componentInfoObjects.allComponentClasses[repl.componentType];
1619
+
1620
+ if (!componentClass.includeBlankStringChildren) {
1621
+ newChildren = newChildren.filter(
1622
+ (x) => typeof x !== "string" || x.trim() !== "",
1623
+ );
1624
+ }
1625
+
1626
+ if (
1627
+ replacements[0].attributes.newNamespace?.primitive &&
1628
+ assignNewNamespaces
1629
+ ) {
1630
+ // if the new components were added with a new namespace
1631
+ // and their parent had a new namespace
1632
+ // make the auto numbered component names include the names
1633
+ // from the original children so that don't have a name collision
1634
+ // from the autonumbering
1635
+ let componentCounts =
1636
+ serializeFunctions.countRegularComponentTypesInNamespace(repl.children);
1637
+
1638
+ serializeFunctions.renameAutonameBasedOnNewCounts(
1639
+ newChildren,
1640
+ componentCounts,
1641
+ );
1642
+ }
1643
+
1644
+ let processResult = serializeFunctions.processAssignNames({
1645
+ serializedComponents: newChildren,
1646
+ parentName: replacements[0].componentName,
1647
+ parentCreatesNewNamespace: assignNewNamespaces,
1648
+ componentInfoObjects,
1649
+ originalNamesAreConsistent: true,
1650
+ });
1651
+
1652
+ if (
1653
+ replacements[0].attributes.newNamespace?.primitive &&
1654
+ !assignNewNamespaces
1655
+ ) {
1656
+ // the new components were added without a new namespace
1657
+ // even though their parent had a new namespace
1658
+ // The parent has already been marked as having a new namespace only because it is shadowing.
1659
+ // Mark them to ignore their parent's new namespace.
1660
+ // Then if the parent is copied directly,
1661
+ // the children won't be given a new namespace
1662
+ for (let comp of processResult.serializedComponents) {
1663
+ if (typeof comp === "object") {
1664
+ comp.doenetAttributes.ignoreParentNewNamespace = true;
1665
+ }
1666
+ }
1667
+ }
1668
+
1669
+ repl.children.push(...processResult.serializedComponents);
1670
+ }
1671
+
1672
+ static async calculateReplacementChanges({
1673
+ component,
1674
+ componentChanges,
1675
+ components,
1676
+ workspace,
1677
+ componentInfoObjects,
1678
+ flags,
1679
+ resolveItem,
1680
+ publicCaseInsensitiveAliasSubstitutions,
1681
+ }) {
1682
+ // console.log("Calculating replacement changes for " + component.componentName);
1683
+
1684
+ // if copying a cid, no changes
1685
+ if (await component.stateValues.serializedComponentsForCid) {
1686
+ return [];
1687
+ }
1688
+
1689
+ // for indexAlias from a source, the replacements never change
1690
+ if ((await component.stateValues.sourceIndex) !== null) {
1691
+ return [];
1692
+ }
1693
+
1694
+ let compositeAttributesObj = this.createAttributesObject();
1695
+
1696
+ let assignNames = await component.stateValues.effectiveAssignNames;
1697
+
1698
+ let replacementSourceIdentities = await component.stateValues
1699
+ .replacementSourceIdentities;
1700
+ if (
1701
+ !(await component.stateValues.targetComponent) ||
1702
+ !replacementSourceIdentities
1703
+ ) {
1704
+ if (await component.stateValues.targetSources) {
1705
+ // if have targetSources, then we're in a template instance
1706
+ // that will be withheld
1707
+ // Don't change replacements so that maintain replacement
1708
+ // if the template instance is later no longer withheld
1709
+ return [];
1710
+ } else {
1711
+ let replacementChanges = [];
1712
+
1713
+ if (component.replacements.length > 0) {
1714
+ let replacementInstruction = {
1715
+ changeType: "delete",
1716
+ changeTopLevelReplacements: true,
1717
+ firstReplacementInd: 0,
1718
+ numberReplacementsToDelete: component.replacements.length,
1719
+ };
1720
+ replacementChanges.push(replacementInstruction);
1721
+ }
1722
+
1723
+ let previousZeroSourceNames = workspace.sourceNames.length === 0;
1724
+
1725
+ workspace.sourceNames = [];
1726
+ workspace.numReplacementsBySource = [];
1727
+ workspace.numNonStringReplacementsBySource = [];
1728
+ workspace.propVariablesCopiedBySource = [];
1729
+
1730
+ let verificationResult = await verifyReplacementsMatchSpecifiedType({
1731
+ component,
1732
+ replacementChanges,
1733
+ assignNames,
1734
+ workspace,
1735
+ componentInfoObjects,
1736
+ compositeAttributesObj,
1737
+ flags,
1738
+ });
1739
+
1740
+ // Note: this has to run after verify,
1741
+ // as verify has side effects of setting workspace variables,
1742
+ // such as numReplacementsBySource
1743
+ if (previousZeroSourceNames) {
1744
+ // didn't have sources before and still don't have sources.
1745
+ // we're just getting filler components being recreated.
1746
+ // Don't actually make those changes
1747
+ return [];
1748
+ }
1749
+
1750
+ return verificationResult.replacementChanges;
1751
+ }
1752
+ }
1753
+
1754
+ if (await component.stateValues.targetInactive) {
1755
+ let replacementChanges = [];
1756
+
1757
+ let nReplacements = component.replacements.length;
1758
+ if (nReplacements > 0) {
1759
+ if (component.replacementsToWithhold !== nReplacements) {
1760
+ let replacementInstruction = {
1761
+ changeType: "changeReplacementsToWithhold",
1762
+ replacementsToWithhold: nReplacements,
1763
+ };
1764
+ replacementChanges.push(replacementInstruction);
1765
+ }
1766
+
1767
+ let verificationResult = await verifyReplacementsMatchSpecifiedType({
1768
+ component,
1769
+ replacementChanges,
1770
+ assignNames,
1771
+ workspace,
1772
+ componentInfoObjects,
1773
+ compositeAttributesObj,
1774
+ flags,
1775
+ });
1776
+
1777
+ replacementChanges = verificationResult.replacementChanges;
1778
+ }
1779
+
1780
+ return replacementChanges;
1781
+ }
1782
+
1783
+ // resolve determine dependencies of replacementSources
1784
+ // and resolve recalculateDownstreamComponents of its target dependencies
1785
+ // so any array entry prop is created
1786
+ let resolveResult = await resolveItem({
1787
+ componentName: component.componentName,
1788
+ type: "determineDependencies",
1789
+ stateVariable: "replacementSources",
1790
+ dependency: "__determine_dependencies",
1791
+ expandComposites: false,
1792
+ });
1793
+
1794
+ if (!resolveResult.success) {
1795
+ throw Error(
1796
+ `Couldn't resolve determineDependencies of replacementSources of ${component.componentName}`,
1797
+ );
1798
+ }
1799
+
1800
+ let effectivePropNameBySource = await component.stateValues
1801
+ .effectivePropNameBySource;
1802
+
1803
+ for (let ind in replacementSourceIdentities) {
1804
+ let thisPropName = effectivePropNameBySource[ind];
1805
+
1806
+ if (thisPropName) {
1807
+ resolveResult = await resolveItem({
1808
+ componentName: component.componentName,
1809
+ type: "recalculateDownstreamComponents",
1810
+ stateVariable: "replacementSources",
1811
+ dependency: "target" + ind,
1812
+ expandComposites: false,
1813
+ });
1814
+
1815
+ if (!resolveResult.success) {
1816
+ throw Error(
1817
+ `Couldn't resolve recalculateDownstreamComponents for target${ind} of replacementSources of ${component.componentName}`,
1818
+ );
1819
+ }
1820
+ }
1821
+ }
1822
+
1823
+ let replacementChanges = [];
1824
+
1825
+ if (component.replacementsToWithhold > 0) {
1826
+ let replacementInstruction = {
1827
+ changeType: "changeReplacementsToWithhold",
1828
+ replacementsToWithhold: 0,
1829
+ };
1830
+ replacementChanges.push(replacementInstruction);
1831
+ }
1832
+
1833
+ let numReplacementsSoFar = 0;
1834
+ let numNonStringReplacementsSoFar = 0;
1835
+
1836
+ let numReplacementsBySource = [];
1837
+ let numNonStringReplacementsBySource = [];
1838
+ let propVariablesCopiedBySource = [];
1839
+
1840
+ let maxSourceLength = Math.max(
1841
+ replacementSourceIdentities.length,
1842
+ workspace.numReplacementsBySource.length,
1843
+ );
1844
+
1845
+ let recreateRemaining = false;
1846
+
1847
+ for (let sourceNum = 0; sourceNum < maxSourceLength; sourceNum++) {
1848
+ let numComponentsForSource;
1849
+
1850
+ if (component.attributes.createComponentOfType?.primitive) {
1851
+ let numComponentsTotal = await component.stateValues
1852
+ .numComponentsSpecified;
1853
+ let numSources = replacementSourceIdentities.length;
1854
+
1855
+ // arbitrarily divide these components among the sources
1856
+ numComponentsForSource = Math.floor(numComponentsTotal / numSources);
1857
+ let nExtras = numComponentsTotal % numSources;
1858
+ if (sourceNum < nExtras) {
1859
+ numComponentsForSource++;
1860
+ }
1861
+ }
1862
+
1863
+ let replacementSource = replacementSourceIdentities[sourceNum];
1864
+ if (replacementSource === undefined) {
1865
+ if (workspace.numReplacementsBySource[sourceNum] > 0) {
1866
+ if (!recreateRemaining) {
1867
+ // since deleting replacement will shift the remaining replacements
1868
+ // and change resulting names,
1869
+ // delete all remaining and mark to be recreated
1870
+
1871
+ let numberReplacementsLeft = workspace.numReplacementsBySource
1872
+ .slice(sourceNum)
1873
+ .reduce((a, c) => a + c, 0);
1874
+
1875
+ if (numberReplacementsLeft > 0) {
1876
+ let replacementInstruction = {
1877
+ changeType: "delete",
1878
+ changeTopLevelReplacements: true,
1879
+ firstReplacementInd: numReplacementsSoFar,
1880
+ numberReplacementsToDelete: numberReplacementsLeft,
1881
+ };
1882
+
1883
+ replacementChanges.push(replacementInstruction);
1884
+ }
1885
+
1886
+ recreateRemaining = true;
1887
+
1888
+ // since deleted remaining, change in workspace
1889
+ // so that don't attempt to delete again
1890
+ workspace.numReplacementsBySource
1891
+ .slice(sourceNum)
1892
+ .forEach((v, i) => (workspace.numReplacementsBySource[i] = 0));
1893
+ workspace.numNonStringReplacementsBySource
1894
+ .slice(sourceNum)
1895
+ .forEach(
1896
+ (v, i) => (workspace.numNonStringReplacementsBySource[i] = 0),
1897
+ );
1898
+ }
1899
+
1900
+ workspace.uniqueIdentifiersUsedBySource[sourceNum] = [];
1901
+ }
1902
+
1903
+ numReplacementsBySource[sourceNum] = 0;
1904
+ numNonStringReplacementsBySource[sourceNum] = 0;
1905
+ propVariablesCopiedBySource.push([]);
1906
+
1907
+ continue;
1908
+ }
1909
+
1910
+ let prevSourceName = workspace.sourceNames[sourceNum];
1911
+
1912
+ // check if replacementSource has changed
1913
+ let needToRecreate =
1914
+ prevSourceName === undefined ||
1915
+ replacementSource.componentName !== prevSourceName ||
1916
+ recreateRemaining;
1917
+
1918
+ if (!needToRecreate) {
1919
+ // make sure the current replacements still shadow the replacement source
1920
+ for (
1921
+ let ind = 0;
1922
+ ind < workspace.numReplacementsBySource[sourceNum];
1923
+ ind++
1924
+ ) {
1925
+ let currentReplacement =
1926
+ component.replacements[numReplacementsSoFar + ind];
1927
+ if (!currentReplacement) {
1928
+ needToRecreate = true;
1929
+ break;
1930
+ } else if (
1931
+ !effectivePropNameBySource[sourceNum] &&
1932
+ currentReplacement.shadows &&
1933
+ currentReplacement.shadows.componentName !==
1934
+ replacementSourceIdentities[sourceNum].componentName
1935
+ ) {
1936
+ needToRecreate = true;
1937
+ break;
1938
+ }
1939
+ }
1940
+ }
1941
+
1942
+ if (needToRecreate) {
1943
+ let prevNumReplacements = 0;
1944
+ if (sourceNum in workspace.numReplacementsBySource) {
1945
+ prevNumReplacements = workspace.numReplacementsBySource[sourceNum];
1946
+ }
1947
+
1948
+ let numReplacementsToDelete = prevNumReplacements;
1949
+ if (recreateRemaining) {
1950
+ // already deleted old replacements
1951
+ numReplacementsToDelete = 0;
1952
+ }
1953
+
1954
+ let uniqueIdentifiersUsed = (workspace.uniqueIdentifiersUsedBySource[
1955
+ sourceNum
1956
+ ] = []);
1957
+ let results = await this.recreateReplacements({
1958
+ component,
1959
+ sourceNum,
1960
+ numReplacementsSoFar,
1961
+ numNonStringReplacementsSoFar,
1962
+ numReplacementsToDelete,
1963
+ components,
1964
+ uniqueIdentifiersUsed,
1965
+ compositeAttributesObj,
1966
+ componentInfoObjects,
1967
+ numComponentsForSource,
1968
+ publicCaseInsensitiveAliasSubstitutions,
1969
+ flags,
1970
+ });
1971
+
1972
+ numReplacementsSoFar += results.numReplacements;
1973
+ numNonStringReplacementsSoFar += results.numNonStringReplacements;
1974
+
1975
+ numReplacementsBySource[sourceNum] = results.numReplacements;
1976
+ numNonStringReplacementsBySource[sourceNum] =
1977
+ results.numNonStringReplacements;
1978
+
1979
+ propVariablesCopiedBySource[sourceNum] =
1980
+ results.propVariablesCopiedByReplacement;
1981
+
1982
+ let replacementInstruction = results.replacementInstruction;
1983
+
1984
+ if (!recreateRemaining) {
1985
+ if (results.numReplacements !== prevNumReplacements) {
1986
+ // we changed the number of replacements which shifts remaining ones
1987
+ // since names won't match, we need to delete
1988
+ // all the remaining replacements and recreate them
1989
+
1990
+ let numberReplacementsLeft = workspace.numReplacementsBySource
1991
+ .slice(sourceNum)
1992
+ .reduce((a, c) => a + c, 0);
1993
+
1994
+ replacementInstruction.numberReplacementsToReplace =
1995
+ numberReplacementsLeft;
1996
+
1997
+ recreateRemaining = true;
1998
+
1999
+ // since deleted remaining, change in workspace
2000
+ // so that don't attempt to delete again
2001
+ workspace.numReplacementsBySource
2002
+ .slice(sourceNum)
2003
+ .forEach((v, i) => (workspace.numReplacementsBySource[i] = 0));
2004
+ workspace.numNonStringReplacementsBySource
2005
+ .slice(sourceNum)
2006
+ .forEach(
2007
+ (v, i) => (workspace.numNonStringReplacementsBySource[i] = 0),
2008
+ );
2009
+ }
2010
+ }
2011
+
2012
+ replacementChanges.push(replacementInstruction);
2013
+
2014
+ continue;
2015
+ }
2016
+
2017
+ if (
2018
+ !effectivePropNameBySource[sourceNum] &&
2019
+ workspace.numReplacementsBySource[sourceNum] > 0
2020
+ ) {
2021
+ // if previously had replacements and target still isn't inactive
2022
+ // then don't check for changes if don't have a propName
2023
+ numReplacementsSoFar += workspace.numReplacementsBySource[sourceNum];
2024
+ numNonStringReplacementsSoFar +=
2025
+ workspace.numNonStringReplacementsBySource[sourceNum];
2026
+ numReplacementsBySource[sourceNum] =
2027
+ workspace.numReplacementsBySource[sourceNum];
2028
+ numNonStringReplacementsBySource[sourceNum] =
2029
+ workspace.numNonStringReplacementsBySource[sourceNum];
2030
+ continue;
2031
+ }
2032
+
2033
+ // use new uniqueIdentifiersUsed
2034
+ // so will get the same names for pieces that match
2035
+ let uniqueIdentifiersUsed = (workspace.uniqueIdentifiersUsedBySource[
2036
+ sourceNum
2037
+ ] = []);
2038
+
2039
+ let results = await this.createReplacementForSource({
2040
+ component,
2041
+ sourceNum,
2042
+ components,
2043
+ numReplacementsSoFar,
2044
+ numNonStringReplacementsSoFar,
2045
+ uniqueIdentifiersUsed,
2046
+ compositeAttributesObj,
2047
+ componentInfoObjects,
2048
+ numComponentsForSource,
2049
+ publicCaseInsensitiveAliasSubstitutions,
2050
+ flags,
2051
+ });
2052
+
2053
+ let propVariablesCopiedByReplacement =
2054
+ results.propVariablesCopiedByReplacement;
2055
+
2056
+ let newSerializedReplacements = results.serializedReplacements;
2057
+
2058
+ let nNewReplacements = newSerializedReplacements.length;
2059
+ let nOldReplacements = workspace.numReplacementsBySource[sourceNum];
2060
+
2061
+ if (nNewReplacements !== nOldReplacements) {
2062
+ // changing the number of replacements will shift the remaining replacements
2063
+ // and change resulting names,
2064
+ // delete all remaining and mark to be recreated
2065
+
2066
+ let numberReplacementsLeft = workspace.numReplacementsBySource
2067
+ .slice(sourceNum)
2068
+ .reduce((a, c) => a + c, 0);
2069
+
2070
+ let replacementInstruction = {
2071
+ changeType: "add",
2072
+ changeTopLevelReplacements: true,
2073
+ firstReplacementInd: numReplacementsSoFar,
2074
+ numberReplacementsToReplace: numberReplacementsLeft,
2075
+ serializedReplacements: newSerializedReplacements,
2076
+ assignNamesOffset: numNonStringReplacementsSoFar,
2077
+ };
2078
+
2079
+ replacementChanges.push(replacementInstruction);
2080
+
2081
+ recreateRemaining = true;
2082
+
2083
+ // since deleted remaining, change in workspace
2084
+ // so that don't attempt to delete again
2085
+ workspace.numReplacementsBySource
2086
+ .slice(sourceNum)
2087
+ .forEach((v, i) => (workspace.numReplacementsBySource[i] = 0));
2088
+ workspace.numNonStringReplacementsBySource
2089
+ .slice(sourceNum)
2090
+ .forEach(
2091
+ (v, i) => (workspace.numNonStringReplacementsBySource[i] = 0),
2092
+ );
2093
+ } else {
2094
+ let nonStringInd = 0;
2095
+ for (let ind = 0; ind < nNewReplacements; ind++) {
2096
+ let foundDifference =
2097
+ propVariablesCopiedByReplacement[ind].length !==
2098
+ workspace.propVariablesCopiedBySource[sourceNum][ind].length;
2099
+ let onlyDifferenceIsType = !foundDifference;
2100
+ if (!foundDifference) {
2101
+ if (
2102
+ workspace.propVariablesCopiedBySource[sourceNum][ind].some(
2103
+ (v, i) => v !== propVariablesCopiedByReplacement[ind][i],
2104
+ )
2105
+ ) {
2106
+ onlyDifferenceIsType = false;
2107
+ foundDifference = true;
2108
+ } else {
2109
+ if (
2110
+ component.replacements[numReplacementsSoFar + ind]
2111
+ .componentType !==
2112
+ newSerializedReplacements[ind].componentType
2113
+ ) {
2114
+ foundDifference = true;
2115
+ }
2116
+ }
2117
+ }
2118
+
2119
+ if (ind == 0 && foundDifference && onlyDifferenceIsType) {
2120
+ let requiredLength = await component.stateValues
2121
+ .numComponentsSpecified;
2122
+
2123
+ let wrapExistingReplacements =
2124
+ requiredLength === 1 &&
2125
+ nNewReplacements === 1 &&
2126
+ !(component.replacementsToWithhold > 0) &&
2127
+ workspace.sourceNames.length === 1;
2128
+
2129
+ if (wrapExistingReplacements) {
2130
+ foundDifference = false;
2131
+ }
2132
+ }
2133
+
2134
+ if (foundDifference) {
2135
+ let replacementInstruction = {
2136
+ changeType: "add",
2137
+ changeTopLevelReplacements: true,
2138
+ firstReplacementInd: numReplacementsSoFar + ind,
2139
+ numberReplacementsToReplace: 1,
2140
+ serializedReplacements: [newSerializedReplacements[ind]],
2141
+ assignNamesOffset: numNonStringReplacementsSoFar + nonStringInd,
2142
+ };
2143
+ replacementChanges.push(replacementInstruction);
2144
+ }
2145
+
2146
+ if (typeof newSerializedReplacements[ind] !== "string") {
2147
+ nonStringInd++;
2148
+ }
2149
+ }
2150
+ }
2151
+
2152
+ let nNewNonStrings = newSerializedReplacements.filter(
2153
+ (x) => typeof x !== "string",
2154
+ ).length;
2155
+
2156
+ numReplacementsSoFar += nNewReplacements;
2157
+ numNonStringReplacementsSoFar += nNewNonStrings;
2158
+
2159
+ numReplacementsBySource[sourceNum] = nNewReplacements;
2160
+ numNonStringReplacementsBySource[sourceNum] = nNewNonStrings;
2161
+
2162
+ propVariablesCopiedBySource[sourceNum] = propVariablesCopiedByReplacement;
2163
+ }
2164
+
2165
+ let previousZeroSourceNames = workspace.sourceNames.length === 0;
2166
+
2167
+ workspace.numReplacementsBySource = numReplacementsBySource;
2168
+ workspace.numNonStringReplacementsBySource =
2169
+ numNonStringReplacementsBySource;
2170
+ workspace.sourceNames = replacementSourceIdentities.map(
2171
+ (x) => x.componentName,
2172
+ );
2173
+ workspace.propVariablesCopiedBySource = propVariablesCopiedBySource;
2174
+
2175
+ let verificationResult = await verifyReplacementsMatchSpecifiedType({
2176
+ component,
2177
+ replacementChanges,
2178
+ assignNames,
2179
+ workspace,
2180
+ componentInfoObjects,
2181
+ compositeAttributesObj,
2182
+ flags,
2183
+ });
2184
+
2185
+ // Note: this has to run after verify,
2186
+ // as verify has side effects of setting workspace variables,
2187
+ // such as numReplacementsBySource
2188
+ if (previousZeroSourceNames && workspace.sourceNames.length === 0) {
2189
+ // didn't have sources before and still don't have sources.
2190
+ // we're just getting filler components being recreated.
2191
+ // Don't actually make those changes
2192
+ return [];
2193
+ }
2194
+
2195
+ // console.log("replacementChanges");
2196
+ // console.log(verificationResult.replacementChanges);
2197
+
2198
+ return verificationResult.replacementChanges;
2199
+ }
2200
+
2201
+ static async recreateReplacements({
2202
+ component,
2203
+ sourceNum,
2204
+ numReplacementsSoFar,
2205
+ numNonStringReplacementsSoFar,
2206
+ numReplacementsToDelete,
2207
+ uniqueIdentifiersUsed,
2208
+ components,
2209
+ compositeAttributesObj,
2210
+ componentInfoObjects,
2211
+ numComponentsForSource,
2212
+ publicCaseInsensitiveAliasSubstitutions,
2213
+ flags,
2214
+ }) {
2215
+ let results = await this.createReplacementForSource({
2216
+ component,
2217
+ sourceNum,
2218
+ numReplacementsSoFar,
2219
+ numNonStringReplacementsSoFar,
2220
+ components,
2221
+ uniqueIdentifiersUsed,
2222
+ compositeAttributesObj,
2223
+ componentInfoObjects,
2224
+ numComponentsForSource,
2225
+ publicCaseInsensitiveAliasSubstitutions,
2226
+ flags,
2227
+ });
2228
+
2229
+ let propVariablesCopiedByReplacement =
2230
+ results.propVariablesCopiedByReplacement;
2231
+
2232
+ let newSerializedChildren = results.serializedReplacements;
2233
+
2234
+ let replacementInstruction = {
2235
+ changeType: "add",
2236
+ changeTopLevelReplacements: true,
2237
+ firstReplacementInd: numReplacementsSoFar,
2238
+ numberReplacementsToReplace: numReplacementsToDelete,
2239
+ serializedReplacements: newSerializedChildren,
2240
+ assignNamesOffset: numNonStringReplacementsSoFar,
2241
+ };
2242
+
2243
+ return {
2244
+ numReplacements: newSerializedChildren.length,
2245
+ numNonStringReplacements: newSerializedChildren.filter(
2246
+ (x) => typeof x !== "string",
2247
+ ).length,
2248
+ propVariablesCopiedByReplacement,
2249
+ replacementInstruction,
2250
+ };
2251
+ }
2252
+ }
2253
+
2254
+ export async function replacementFromProp({
2255
+ component,
2256
+ components,
2257
+ replacementSource,
2258
+ propName,
2259
+ // numReplacementsSoFar,
2260
+ uniqueIdentifiersUsed,
2261
+ compositeAttributesObj,
2262
+ componentInfoObjects,
2263
+ numComponentsForSource,
2264
+ publicCaseInsensitiveAliasSubstitutions,
2265
+ flags,
2266
+ }) {
2267
+ // console.log(`replacement from prop for ${component.componentName}`)
2268
+ // console.log(replacementSource)
2269
+
2270
+ let serializedReplacements = [];
2271
+ let propVariablesCopiedByReplacement = [];
2272
+ let newNamespace = component.attributes.newNamespace?.primitive;
2273
+
2274
+ // if (replacementSource === null) {
2275
+ // return { serializedReplacements, propVariablesCopiedByReplacement };
2276
+ // }
2277
+
2278
+ let replacementInd = -1; //numReplacementsSoFar - 1;
2279
+
2280
+ let target = components[replacementSource.componentName];
2281
+
2282
+ let varName = publicCaseInsensitiveAliasSubstitutions({
2283
+ stateVariables: [propName],
2284
+ componentClass: target.constructor,
2285
+ })[0];
2286
+
2287
+ if (varName === undefined || varName.slice(0, 12) === "__not_public") {
2288
+ if (propName !== "__prop_name_not_found") {
2289
+ console.warn(
2290
+ `Could not find prop ${propName} on a component of type ${replacementSource.componentType}`,
2291
+ );
2292
+ }
2293
+ return {
2294
+ serializedReplacements: [],
2295
+ propVariablesCopiedByReplacement: [],
2296
+ };
2297
+ }
2298
+
2299
+ let stateVarObj = target.state[varName];
2300
+ let stateVarValue = await stateVarObj.value;
2301
+
2302
+ let link = await component.stateValues.link;
2303
+
2304
+ if (stateVarObj.isArray || stateVarObj.isArrayEntry) {
2305
+ let arrayStateVarObj, unflattenedArrayKeys, arraySize, arrayKeys;
2306
+ if (stateVarObj.isArray) {
2307
+ arrayStateVarObj = stateVarObj;
2308
+ arraySize = await stateVarObj.arraySize;
2309
+ unflattenedArrayKeys = stateVarObj.getAllArrayKeys(arraySize, false);
2310
+ } else {
2311
+ arrayStateVarObj = target.state[stateVarObj.arrayStateVariable];
2312
+ unflattenedArrayKeys = await stateVarObj.unflattenedArrayKeys;
2313
+ arrayKeys = await stateVarObj.arrayKeys;
2314
+ }
2315
+
2316
+ if (arrayStateVarObj.shadowingInstructions?.hasVariableComponentType) {
2317
+ await component.stateValues.replacementSources;
2318
+ if (!arrayStateVarObj.shadowingInstructions.createComponentOfType) {
2319
+ return {
2320
+ serializedReplacements: [],
2321
+ propVariablesCopiedByReplacement: [],
2322
+ };
2323
+ }
2324
+ }
2325
+
2326
+ let wrappingComponents = stateVarObj.wrappingComponents;
2327
+ let numWrappingComponents = wrappingComponents.length;
2328
+
2329
+ let numReplacementsForSource = numComponentsForSource;
2330
+
2331
+ if (stateVarObj.isArray) {
2332
+ numReplacementsForSource = arraySize
2333
+ .slice(0, arraySize.length - numWrappingComponents)
2334
+ .reduce((a, c) => a * c, 1);
2335
+ } else {
2336
+ if (arrayKeys.length === 0) {
2337
+ // have an undefined array entry
2338
+ numReplacementsForSource = 0;
2339
+ } else if (numWrappingComponents === 0) {
2340
+ // with no wrapping components, will just output
2341
+ // one component for each component of the array
2342
+ numReplacementsForSource = arrayKeys.length;
2343
+ } else if (numWrappingComponents >= stateVarObj.numDimensions) {
2344
+ // if had an outer wrapping component, would just have a single component
2345
+ numReplacementsForSource = 1;
2346
+ } else if (numWrappingComponents === stateVarObj.numDimensions - 1) {
2347
+ // if the second from outer dimension is wrapped
2348
+ // then just count the number of entries in the original array
2349
+ numReplacementsForSource = unflattenedArrayKeys.length;
2350
+ } else {
2351
+ // if have at least two unwrapped dimensions,
2352
+ // flatten the array so that the entries counted are the outermost wrapped
2353
+ // Note: we need to create a 3D array entry to access this,
2354
+ // so this code is so far untested
2355
+ let nLevelsToFlatten =
2356
+ stateVarObj.numDimensions - numWrappingComponents - 1;
2357
+ numReplacementsForSource = flattenLevels(
2358
+ unflattenedArrayKeys,
2359
+ nLevelsToFlatten,
2360
+ ).length;
2361
+ }
2362
+ }
2363
+
2364
+ if (numWrappingComponents === 0) {
2365
+ // return flattened entries
2366
+
2367
+ let flattenedArrayKeys = flattenDeep(unflattenedArrayKeys);
2368
+
2369
+ for (let ind = 0; ind < numReplacementsForSource; ind++) {
2370
+ let arrayKey = flattenedArrayKeys[ind];
2371
+
2372
+ if (await component.stateValues.removeEmptyArrayEntries) {
2373
+ // check if value of replacmentSource is undefined or null
2374
+ // if so, skip
2375
+
2376
+ if (!arrayKey) {
2377
+ // skip because didn't match array key
2378
+ continue;
2379
+ }
2380
+
2381
+ let arrayIndex = arrayStateVarObj.keyToIndex(arrayKey);
2382
+ if (!Array.isArray(arrayIndex)) {
2383
+ arrayIndex = [arrayIndex];
2384
+ }
2385
+ let propStateValue = await arrayStateVarObj.value;
2386
+ for (let ind2 of arrayIndex) {
2387
+ propStateValue = propStateValue[ind2];
2388
+ }
2389
+
2390
+ if (propStateValue === undefined || propStateValue === null) {
2391
+ continue;
2392
+ }
2393
+ }
2394
+
2395
+ replacementInd++;
2396
+ let propVariablesCopied = (propVariablesCopiedByReplacement[
2397
+ replacementInd
2398
+ ] = []);
2399
+
2400
+ let createComponentOfType =
2401
+ arrayStateVarObj.shadowingInstructions.createComponentOfType;
2402
+ if (Array.isArray(createComponentOfType)) {
2403
+ // TODO: multidimensional arrays?
2404
+
2405
+ if (createComponentOfType[arrayStateVarObj.keyToIndex(arrayKey)]) {
2406
+ createComponentOfType =
2407
+ createComponentOfType[arrayStateVarObj.keyToIndex(arrayKey)];
2408
+ } else {
2409
+ // TODO: better way to handle no match?
2410
+ createComponentOfType = createComponentOfType[0];
2411
+ }
2412
+ // if (stateVarObj.isArrayEntry) {
2413
+ // createComponentOfType = createComponentOfType[arrayStateVarObj.keyToIndex(arrayKey)];
2414
+ // } else {
2415
+ // createComponentOfType = createComponentOfType[ind];
2416
+ // }
2417
+ }
2418
+
2419
+ if (arrayKey) {
2420
+ let propVariable =
2421
+ arrayStateVarObj.arrayVarNameFromArrayKey(arrayKey);
2422
+
2423
+ propVariablesCopied.push(propVariable);
2424
+
2425
+ let uniqueIdentifierBase =
2426
+ replacementSource.componentName + "|shadow|" + propVariable;
2427
+ let uniqueIdentifier = getUniqueIdentifierFromBase(
2428
+ uniqueIdentifierBase,
2429
+ uniqueIdentifiersUsed,
2430
+ );
2431
+
2432
+ let attributesFromComposite = convertAttributesForComponentType({
2433
+ attributes: component.attributes,
2434
+ componentType: createComponentOfType,
2435
+ componentInfoObjects,
2436
+ compositeAttributesObj,
2437
+ compositeCreatesNewNamespace: newNamespace,
2438
+ flags,
2439
+ });
2440
+
2441
+ let attributeComponentsShadowingStateVariables;
2442
+ if (
2443
+ arrayStateVarObj.shadowingInstructions
2444
+ .addAttributeComponentsShadowingStateVariables
2445
+ ) {
2446
+ attributeComponentsShadowingStateVariables = {};
2447
+
2448
+ for (let attrName in arrayStateVarObj.shadowingInstructions
2449
+ .addAttributeComponentsShadowingStateVariables) {
2450
+ let stateVariableToShadow =
2451
+ arrayStateVarObj.shadowingInstructions
2452
+ .addAttributeComponentsShadowingStateVariables[attrName]
2453
+ .stateVariableToShadow;
2454
+
2455
+ let sObj = target.state[stateVariableToShadow];
2456
+ if (sObj.isArray) {
2457
+ stateVariableToShadow = sObj.arrayVarNameFromArrayKey(arrayKey);
2458
+ }
2459
+
2460
+ attributeComponentsShadowingStateVariables[attrName] = {
2461
+ stateVariableToShadow,
2462
+ };
2463
+ }
2464
+ }
2465
+
2466
+ let stateVariablesShadowingStateVariables;
2467
+ if (
2468
+ arrayStateVarObj.shadowingInstructions
2469
+ .addStateVariablesShadowingStateVariables
2470
+ ) {
2471
+ stateVariablesShadowingStateVariables = {};
2472
+
2473
+ for (let attrName in arrayStateVarObj.shadowingInstructions
2474
+ .addStateVariablesShadowingStateVariables) {
2475
+ let stateVariableToShadow =
2476
+ arrayStateVarObj.shadowingInstructions
2477
+ .addStateVariablesShadowingStateVariables[attrName]
2478
+ .stateVariableToShadow;
2479
+
2480
+ let sObj = target.state[stateVariableToShadow];
2481
+ if (sObj.isArray) {
2482
+ stateVariableToShadow = sObj.arrayVarNameFromArrayKey(arrayKey);
2483
+ }
2484
+
2485
+ stateVariablesShadowingStateVariables[attrName] = {
2486
+ stateVariableToShadow,
2487
+ };
2488
+ }
2489
+ }
2490
+
2491
+ if (link) {
2492
+ let attributesForReplacement = {};
2493
+
2494
+ if (attributeComponentsShadowingStateVariables) {
2495
+ let classOfComponentToCreate =
2496
+ componentInfoObjects.allComponentClasses[createComponentOfType];
2497
+ let attrObj = classOfComponentToCreate.createAttributesObject();
2498
+
2499
+ for (let attrName in attributeComponentsShadowingStateVariables) {
2500
+ let stateVariableToShadow =
2501
+ attributeComponentsShadowingStateVariables[attrName]
2502
+ .stateVariableToShadow;
2503
+ let attributeComponentType =
2504
+ attrObj[attrName]?.createComponentOfType;
2505
+
2506
+ if (attributeComponentType) {
2507
+ let shadowComponent = {
2508
+ componentType: attributeComponentType,
2509
+ downstreamDependencies: {
2510
+ [target.componentName]: [
2511
+ {
2512
+ compositeName: component.componentName,
2513
+ dependencyType: "referenceShadow",
2514
+ propVariable: stateVariableToShadow,
2515
+ },
2516
+ ],
2517
+ },
2518
+ };
2519
+
2520
+ attributesForReplacement[attrName] = {
2521
+ component: shadowComponent,
2522
+ };
2523
+ }
2524
+ }
2525
+ }
2526
+
2527
+ Object.assign(attributesForReplacement, attributesFromComposite);
2528
+
2529
+ serializedReplacements.push({
2530
+ componentType: createComponentOfType,
2531
+ attributes: attributesForReplacement,
2532
+ downstreamDependencies: {
2533
+ [replacementSource.componentName]: [
2534
+ {
2535
+ dependencyType: "referenceShadow",
2536
+ compositeName: component.componentName,
2537
+ propVariable,
2538
+ additionalStateVariableShadowing:
2539
+ stateVariablesShadowingStateVariables,
2540
+ },
2541
+ ],
2542
+ },
2543
+ uniqueIdentifier,
2544
+ });
2545
+ } else {
2546
+ // no link
2547
+
2548
+ let attributesForReplacement = {};
2549
+
2550
+ if (attributeComponentsShadowingStateVariables) {
2551
+ let classOfComponentToCreate =
2552
+ componentInfoObjects.allComponentClasses[createComponentOfType];
2553
+ let attrObj = classOfComponentToCreate.createAttributesObject();
2554
+
2555
+ let additionalAttributes = {};
2556
+ for (let attrName in attributeComponentsShadowingStateVariables) {
2557
+ if (attrObj[attrName]?.createComponentOfType) {
2558
+ let vName =
2559
+ attributeComponentsShadowingStateVariables[attrName]
2560
+ .stateVariableToShadow;
2561
+ let attributeStateVarObj = target.state[vName];
2562
+ let attributeValue = await attributeStateVarObj.value;
2563
+ if (attributeStateVarObj.isArray) {
2564
+ // Assume attribute has same dimensions as original
2565
+ // TODO: multidimensional arrays?
2566
+ attributeValue =
2567
+ attributeValue[attributeStateVarObj.keyToIndex[arrayKey]];
2568
+ }
2569
+ if (!target.state[vName].usedDefault) {
2570
+ additionalAttributes[attrName] = attributeValue;
2571
+ }
2572
+ }
2573
+ }
2574
+
2575
+ let attributesFromComponent = convertAttributesForComponentType({
2576
+ attributes: additionalAttributes,
2577
+ componentType: createComponentOfType,
2578
+ componentInfoObjects,
2579
+ flags,
2580
+ });
2581
+
2582
+ if (stateVarObj.shadowingInstructions.attributesToShadow) {
2583
+ for (let attrName of stateVarObj.shadowingInstructions
2584
+ .attributesToShadow) {
2585
+ if (target.attributes[attrName]?.component) {
2586
+ attributesFromComponent[attrName] = {
2587
+ component: await target.attributes[
2588
+ attrName
2589
+ ]?.component.serialize({
2590
+ copyAll: true,
2591
+ copyVariants: true,
2592
+ }),
2593
+ };
2594
+ } else if (
2595
+ target.attributes[attrName]?.primitive !== undefined
2596
+ ) {
2597
+ attributesFromComponent[attrName] = {
2598
+ primitive: JSON.parse(
2599
+ JSON.stringify(target.attributes[attrName].primitive),
2600
+ ),
2601
+ };
2602
+ }
2603
+ }
2604
+ }
2605
+
2606
+ Object.assign(attributesForReplacement, attributesFromComponent);
2607
+ }
2608
+
2609
+ Object.assign(attributesForReplacement, attributesFromComposite);
2610
+
2611
+ let primaryEssentialStateVariable = "value";
2612
+ let componentClass =
2613
+ componentInfoObjects.allComponentClasses[createComponentOfType];
2614
+ if (componentClass.primaryEssentialStateVariable) {
2615
+ primaryEssentialStateVariable =
2616
+ componentClass.primaryEssentialStateVariable;
2617
+ } else if (componentClass.primaryStateVariableForDefinition) {
2618
+ primaryEssentialStateVariable =
2619
+ componentClass.primaryStateVariableForDefinition;
2620
+ }
2621
+
2622
+ let arrayIndex = arrayStateVarObj.keyToIndex(arrayKey);
2623
+ if (!Array.isArray(arrayIndex)) {
2624
+ arrayIndex = [arrayIndex];
2625
+ }
2626
+ let propStateValue = await arrayStateVarObj.value;
2627
+ for (let ind2 of arrayIndex) {
2628
+ propStateValue = propStateValue[ind2];
2629
+ }
2630
+
2631
+ let serializedComponent = {
2632
+ componentType: createComponentOfType,
2633
+ attributes: attributesForReplacement,
2634
+ state: {
2635
+ [primaryEssentialStateVariable]: propStateValue,
2636
+ },
2637
+ uniqueIdentifier,
2638
+ };
2639
+
2640
+ serializedReplacements.push(serializedComponent);
2641
+ }
2642
+ } else {
2643
+ // didn't match an array key, so just add an empty component of createComponentOfType
2644
+ let uniqueIdentifierBase = createComponentOfType + "|empty";
2645
+ let uniqueIdentifier = getUniqueIdentifierFromBase(
2646
+ uniqueIdentifierBase,
2647
+ uniqueIdentifiersUsed,
2648
+ );
2649
+
2650
+ serializedReplacements.push({
2651
+ componentType: createComponentOfType,
2652
+ uniqueIdentifier,
2653
+ });
2654
+ }
2655
+ }
2656
+ } else {
2657
+ // have wrapping components
2658
+
2659
+ let createReplacementPiece = async function (
2660
+ subArrayKeys,
2661
+ numDimensionsLeft,
2662
+ init = false,
2663
+ ) {
2664
+ let pieces = [];
2665
+ let propVariablesCopiedByPiece = [];
2666
+
2667
+ if (numDimensionsLeft > 1) {
2668
+ // since numDimensionsLeft > 1, each component of subArray should be an array
2669
+ for (let subSubArrayKeys of subArrayKeys) {
2670
+ // recurse down to previous dimension
2671
+ let result = await createReplacementPiece(
2672
+ subSubArrayKeys,
2673
+ numDimensionsLeft - 1,
2674
+ );
2675
+ pieces.push(...result.pieces);
2676
+ propVariablesCopiedByPiece.push(
2677
+ ...result.propVariablesCopiedByPiece,
2678
+ );
2679
+ }
2680
+ } else {
2681
+ // down to last piece
2682
+ for (let arrayKey of subArrayKeys) {
2683
+ let propVariable =
2684
+ arrayStateVarObj.arrayVarNameFromArrayKey(arrayKey);
2685
+ let propVariablesCopiedForThisPiece = [propVariable];
2686
+
2687
+ let uniqueIdentifierBase =
2688
+ replacementSource.componentName + "|shadow|" + propVariable;
2689
+ let uniqueIdentifier = getUniqueIdentifierFromBase(
2690
+ uniqueIdentifierBase,
2691
+ uniqueIdentifiersUsed,
2692
+ );
2693
+
2694
+ let createComponentOfType =
2695
+ arrayStateVarObj.shadowingInstructions.createComponentOfType;
2696
+ if (Array.isArray(createComponentOfType)) {
2697
+ // TODO: multidimensional arrays?
2698
+ createComponentOfType =
2699
+ createComponentOfType[arrayStateVarObj.keyToIndex(arrayKey)];
2700
+ }
2701
+
2702
+ let attributeComponentsShadowingStateVariables;
2703
+ if (
2704
+ arrayStateVarObj.shadowingInstructions
2705
+ .addAttributeComponentsShadowingStateVariables
2706
+ ) {
2707
+ attributeComponentsShadowingStateVariables = {};
2708
+
2709
+ let attributeShadowingInfo =
2710
+ arrayStateVarObj.shadowingInstructions
2711
+ .addAttributeComponentsShadowingStateVariables;
2712
+
2713
+ for (let attrName in attributeShadowingInfo) {
2714
+ if (
2715
+ !attributeShadowingInfo[attrName].addToOuterIfWrappedArray
2716
+ ) {
2717
+ let stateVariableToShadow =
2718
+ attributeShadowingInfo[attrName].stateVariableToShadow;
2719
+
2720
+ let sObj = target.state[stateVariableToShadow];
2721
+ if (sObj.isArray) {
2722
+ stateVariableToShadow =
2723
+ sObj.arrayVarNameFromArrayKey(arrayKey);
2724
+ }
2725
+
2726
+ attributeComponentsShadowingStateVariables[attrName] = {
2727
+ stateVariableToShadow,
2728
+ };
2729
+ }
2730
+ }
2731
+ }
2732
+
2733
+ let stateVariablesShadowingStateVariables;
2734
+ if (
2735
+ arrayStateVarObj.shadowingInstructions
2736
+ .addStateVariablesShadowingStateVariables
2737
+ ) {
2738
+ stateVariablesShadowingStateVariables = {};
2739
+
2740
+ for (let attrName in arrayStateVarObj.shadowingInstructions
2741
+ .addStateVariablesShadowingStateVariables) {
2742
+ let stateVariableToShadow =
2743
+ arrayStateVarObj.shadowingInstructions
2744
+ .addStateVariablesShadowingStateVariables[attrName]
2745
+ .stateVariableToShadow;
2746
+
2747
+ let sObj = target.state[stateVariableToShadow];
2748
+ if (sObj.isArray) {
2749
+ stateVariableToShadow =
2750
+ sObj.arrayVarNameFromArrayKey(arrayKey);
2751
+ }
2752
+
2753
+ stateVariablesShadowingStateVariables[attrName] = {
2754
+ stateVariableToShadow,
2755
+ };
2756
+ }
2757
+ }
2758
+
2759
+ if (link) {
2760
+ let attributesForReplacement = {};
2761
+
2762
+ if (attributeComponentsShadowingStateVariables) {
2763
+ let classOfComponentToCreate =
2764
+ componentInfoObjects.allComponentClasses[
2765
+ createComponentOfType
2766
+ ];
2767
+ let attrObj = classOfComponentToCreate.createAttributesObject();
2768
+
2769
+ for (let attrName in attributeComponentsShadowingStateVariables) {
2770
+ let stateVariableToShadow =
2771
+ attributeComponentsShadowingStateVariables[attrName]
2772
+ .stateVariableToShadow;
2773
+ let attributeComponentType =
2774
+ attrObj[attrName]?.createComponentOfType;
2775
+
2776
+ if (attributeComponentType) {
2777
+ let shadowComponent = {
2778
+ componentType: attributeComponentType,
2779
+ downstreamDependencies: {
2780
+ [target.componentName]: [
2781
+ {
2782
+ compositeName: component.componentName,
2783
+ dependencyType: "referenceShadow",
2784
+ propVariable: stateVariableToShadow,
2785
+ },
2786
+ ],
2787
+ },
2788
+ };
2789
+
2790
+ attributesForReplacement[attrName] = {
2791
+ component: shadowComponent,
2792
+ };
2793
+ }
2794
+ }
2795
+ }
2796
+
2797
+ pieces.push({
2798
+ componentType: createComponentOfType,
2799
+ attributes: attributesForReplacement,
2800
+ downstreamDependencies: {
2801
+ [replacementSource.componentName]: [
2802
+ {
2803
+ dependencyType: "referenceShadow",
2804
+ compositeName: component.componentName,
2805
+ propVariable,
2806
+ additionalStateVariableShadowing:
2807
+ stateVariablesShadowingStateVariables,
2808
+ },
2809
+ ],
2810
+ },
2811
+ uniqueIdentifier,
2812
+ });
2813
+ } else {
2814
+ let attributesForReplacement = {};
2815
+
2816
+ if (attributeComponentsShadowingStateVariables) {
2817
+ let classOfComponentToCreate =
2818
+ componentInfoObjects.allComponentClasses[
2819
+ createComponentOfType
2820
+ ];
2821
+ let attrObj = classOfComponentToCreate.createAttributesObject();
2822
+ let additionalAttributes = {};
2823
+ for (let attrName in attributeComponentsShadowingStateVariables) {
2824
+ if (attrObj[attrName]?.createComponentOfType) {
2825
+ let vName =
2826
+ attributeComponentsShadowingStateVariables[attrName]
2827
+ .stateVariableToShadow;
2828
+ let attributeStateVarObj = target.state[vName];
2829
+ let attributeValue = await attributeStateVarObj.value;
2830
+ if (attributeStateVarObj.isArray) {
2831
+ // Assume attribute has same dimensions as original
2832
+ // TODO: multidimensional arrays?
2833
+ attributeValue =
2834
+ attributeValue[
2835
+ attributeStateVarObj.keyToIndex[arrayKey]
2836
+ ];
2837
+ }
2838
+ if (!target.state[vName].usedDefault) {
2839
+ additionalAttributes[attrName] = attributeValue;
2840
+ }
2841
+ }
2842
+ }
2843
+
2844
+ let attributesFromComponent = convertAttributesForComponentType(
2845
+ {
2846
+ attributes: additionalAttributes,
2847
+ componentType: createComponentOfType,
2848
+ componentInfoObjects,
2849
+ flags,
2850
+ },
2851
+ );
2852
+
2853
+ if (stateVarObj.shadowingInstructions.attributesToShadow) {
2854
+ for (let attrName of stateVarObj.shadowingInstructions
2855
+ .attributesToShadow) {
2856
+ if (target.attributes[attrName]?.component) {
2857
+ attributesFromComponent[attrName] = {
2858
+ component: await target.attributes[
2859
+ attrName
2860
+ ]?.component.serialize({
2861
+ copyAll: true,
2862
+ copyVariants: true,
2863
+ }),
2864
+ };
2865
+ } else if (
2866
+ target.attributes[attrName]?.primitive !== undefined
2867
+ ) {
2868
+ attributesFromComponent[attrName] = {
2869
+ primitive: JSON.parse(
2870
+ JSON.stringify(target.attributes[attrName].primitive),
2871
+ ),
2872
+ };
2873
+ }
2874
+ }
2875
+ }
2876
+
2877
+ Object.assign(
2878
+ attributesForReplacement,
2879
+ attributesFromComponent,
2880
+ );
2881
+ }
2882
+
2883
+ let primaryEssentialStateVariable = "value";
2884
+ let componentClass =
2885
+ componentInfoObjects.allComponentClasses[createComponentOfType];
2886
+ if (componentClass.primaryEssentialStateVariable) {
2887
+ primaryEssentialStateVariable =
2888
+ componentClass.primaryEssentialStateVariable;
2889
+ } else if (componentClass.primaryStateVariableForDefinition) {
2890
+ primaryEssentialStateVariable =
2891
+ componentClass.primaryStateVariableForDefinition;
2892
+ }
2893
+
2894
+ let arrayIndex = arrayStateVarObj.keyToIndex(arrayKey);
2895
+ if (!Array.isArray(arrayIndex)) {
2896
+ arrayIndex = [arrayIndex];
2897
+ }
2898
+
2899
+ let propStateValue = await arrayStateVarObj.value;
2900
+ for (let ind of arrayIndex) {
2901
+ propStateValue = propStateValue[ind];
2902
+ }
2903
+
2904
+ let serializedComponent = {
2905
+ componentType: createComponentOfType,
2906
+ attributes: attributesForReplacement,
2907
+ state: {
2908
+ [primaryEssentialStateVariable]: propStateValue,
2909
+ },
2910
+ uniqueIdentifier,
2911
+ };
2912
+
2913
+ pieces.push(serializedComponent);
2914
+ }
2915
+
2916
+ propVariablesCopiedByPiece.push(propVariablesCopiedForThisPiece);
2917
+ }
2918
+ }
2919
+
2920
+ // we wrap this dimension if have corresponding wrapping components
2921
+ let wrapCs = wrappingComponents[numDimensionsLeft - 1];
2922
+ if (pieces.length > 0 && wrapCs && wrapCs.length > 0) {
2923
+ for (let ind = wrapCs.length - 1; ind >= 0; ind--) {
2924
+ let wrapCT =
2925
+ typeof wrapCs[ind] === "object"
2926
+ ? wrapCs[ind].componentType
2927
+ : wrapCs[ind];
2928
+ let uniqueIdentifierBase = wrapCT + "|wrapper";
2929
+ let uniqueIdentifier = getUniqueIdentifierFromBase(
2930
+ uniqueIdentifierBase,
2931
+ uniqueIdentifiersUsed,
2932
+ );
2933
+
2934
+ let children = [];
2935
+ let attributes = {};
2936
+
2937
+ for (let p of pieces) {
2938
+ if (p.isAttribute) {
2939
+ let attr = p.isAttribute;
2940
+ delete p.isAttribute;
2941
+ attributes[attr] = { component: p };
2942
+ } else {
2943
+ children.push(p);
2944
+ }
2945
+ }
2946
+
2947
+ pieces = [
2948
+ {
2949
+ componentType: wrapCT,
2950
+ children,
2951
+ attributes,
2952
+ uniqueIdentifier,
2953
+ skipSugar: true,
2954
+ },
2955
+ ];
2956
+ if (typeof wrapCs[ind] === "object") {
2957
+ if (wrapCs[ind].doenetAttributes) {
2958
+ pieces[0].doenetAttributes = Object.assign(
2959
+ {},
2960
+ wrapCs[ind].doenetAttributes,
2961
+ );
2962
+ }
2963
+ if (wrapCs[ind].isAttribute) {
2964
+ pieces[0].isAttribute = wrapCs[ind].isAttribute;
2965
+ }
2966
+ }
2967
+ }
2968
+ propVariablesCopiedByPiece = [
2969
+ flattenDeep(propVariablesCopiedByPiece),
2970
+ ];
2971
+ }
2972
+
2973
+ if (
2974
+ init &&
2975
+ arrayStateVarObj.shadowingInstructions
2976
+ .addAttributeComponentsShadowingStateVariables
2977
+ ) {
2978
+ let attributeComponentsShadowingStateVariables = {};
2979
+
2980
+ let attributeShadowingInfo =
2981
+ arrayStateVarObj.shadowingInstructions
2982
+ .addAttributeComponentsShadowingStateVariables;
2983
+
2984
+ for (let attrName in attributeShadowingInfo) {
2985
+ if (attributeShadowingInfo[attrName].addToOuterIfWrappedArray) {
2986
+ let stateVariableToShadow =
2987
+ attributeShadowingInfo[attrName].stateVariableToShadow;
2988
+
2989
+ attributeComponentsShadowingStateVariables[attrName] = {
2990
+ stateVariableToShadow,
2991
+ };
2992
+ }
2993
+ }
2994
+
2995
+ if (
2996
+ Object.keys(attributeComponentsShadowingStateVariables).length > 0
2997
+ ) {
2998
+ for (let piece of pieces) {
2999
+ let attributesForReplacement = piece.attributes;
3000
+ if (!attributesForReplacement) {
3001
+ attributesForReplacement = piece.attributes = {};
3002
+ }
3003
+
3004
+ let classOfComponentToCreate =
3005
+ componentInfoObjects.allComponentClasses[piece.componentType];
3006
+ let attrObj = classOfComponentToCreate.createAttributesObject();
3007
+
3008
+ if (link) {
3009
+ for (let attrName in attributeComponentsShadowingStateVariables) {
3010
+ let stateVariableToShadow =
3011
+ attributeComponentsShadowingStateVariables[attrName]
3012
+ .stateVariableToShadow;
3013
+ let attributeComponentType =
3014
+ attrObj[attrName]?.createComponentOfType;
3015
+
3016
+ if (attributeComponentType) {
3017
+ let shadowComponent = {
3018
+ componentType: attributeComponentType,
3019
+ downstreamDependencies: {
3020
+ [target.componentName]: [
3021
+ {
3022
+ compositeName: component.componentName,
3023
+ dependencyType: "referenceShadow",
3024
+ propVariable: stateVariableToShadow,
3025
+ },
3026
+ ],
3027
+ },
3028
+ };
3029
+
3030
+ attributesForReplacement[attrName] = {
3031
+ component: shadowComponent,
3032
+ };
3033
+ }
3034
+ }
3035
+ } else {
3036
+ let additionalAttributes = {};
3037
+ for (let attrName in attributeComponentsShadowingStateVariables) {
3038
+ if (attrObj[attrName]?.createComponentOfType) {
3039
+ let vName =
3040
+ attributeComponentsShadowingStateVariables[attrName]
3041
+ .stateVariableToShadow;
3042
+ let attributeStateVarObj = target.state[vName];
3043
+ let attributeValue = await attributeStateVarObj.value;
3044
+
3045
+ if (!target.state[vName].usedDefault) {
3046
+ additionalAttributes[attrName] = attributeValue;
3047
+ }
3048
+ }
3049
+ }
3050
+
3051
+ if (Object.keys(additionalAttributes).length > 0) {
3052
+ additionalAttributes = convertAttributesForComponentType({
3053
+ attributes: additionalAttributes,
3054
+ componentType: piece.componentType,
3055
+ componentInfoObjects,
3056
+ flags,
3057
+ });
3058
+
3059
+ Object.assign(attributesForReplacement, additionalAttributes);
3060
+ }
3061
+ }
3062
+ }
3063
+ }
3064
+ }
3065
+
3066
+ return { pieces, propVariablesCopiedByPiece };
3067
+ };
3068
+
3069
+ let result = await createReplacementPiece(
3070
+ unflattenedArrayKeys,
3071
+ stateVarObj.numDimensions,
3072
+ true,
3073
+ );
3074
+
3075
+ let newReplacements = result.pieces;
3076
+ propVariablesCopiedByReplacement = result.propVariablesCopiedByPiece;
3077
+
3078
+ // add downstream dependencies and attributes to top level replacements
3079
+ // (which are wrappers, so didn't get downstream dependencies originally)
3080
+ for (let replacement of newReplacements) {
3081
+ if (typeof replacement !== "object") {
3082
+ continue;
3083
+ }
3084
+
3085
+ if (!replacement.attributes) {
3086
+ replacement.attributes = {};
3087
+ }
3088
+
3089
+ let attributesFromComposite = convertAttributesForComponentType({
3090
+ attributes: component.attributes,
3091
+ componentType: replacement.componentType,
3092
+ componentInfoObjects,
3093
+ compositeAttributesObj,
3094
+ compositeCreatesNewNamespace: newNamespace,
3095
+ flags,
3096
+ });
3097
+
3098
+ Object.assign(replacement.attributes, attributesFromComposite);
3099
+
3100
+ if (link) {
3101
+ replacement.downstreamDependencies = {
3102
+ [replacementSource.componentName]: [
3103
+ {
3104
+ dependencyType: "referenceShadow",
3105
+ compositeName: component.componentName,
3106
+ propVariable: varName,
3107
+ ignorePrimaryStateVariable: true,
3108
+ },
3109
+ ],
3110
+ };
3111
+ }
3112
+ }
3113
+
3114
+ replacementInd += newReplacements.length;
3115
+
3116
+ serializedReplacements.push(...newReplacements);
3117
+
3118
+ if (newReplacements.length < numReplacementsForSource) {
3119
+ // we didn't create enough replacements,
3120
+ // which could happen if we have componentType and numComponentsSpecified set
3121
+
3122
+ // just create additional replacements,
3123
+ // even though they won't yet refer to the right dependencies
3124
+
3125
+ for (
3126
+ let ind = newReplacements.length;
3127
+ ind < numReplacementsForSource;
3128
+ ind++
3129
+ ) {
3130
+ replacementInd++;
3131
+ propVariablesCopiedByReplacement[replacementInd] = [];
3132
+
3133
+ let createComponentOfType;
3134
+ let wrapCs = wrappingComponents[0];
3135
+ let wrapDoenetAttributes;
3136
+ if (wrapCs && wrapCs.length > 0) {
3137
+ if (typeof wrapCs[0] === "object") {
3138
+ createComponentOfType = wrapCs[0].componentType;
3139
+ wrapDoenetAttributes = Object.assign(
3140
+ {},
3141
+ wrapCs[0].doenetAttributes,
3142
+ );
3143
+ } else {
3144
+ createComponentOfType = wrapCs[0];
3145
+ }
3146
+ } else {
3147
+ createComponentOfType =
3148
+ arrayStateVarObj.shadowingInstructions.createComponentOfType;
3149
+ if (Array.isArray(createComponentOfType)) {
3150
+ // TODO: multidimensional arrays?
3151
+ if (stateVarObj.isArrayEntry) {
3152
+ createComponentOfType =
3153
+ createComponentOfType[
3154
+ arrayStateVarObj.keyToIndex(arrayKeys[ind])
3155
+ ];
3156
+ } else {
3157
+ createComponentOfType = createComponentOfType[ind];
3158
+ }
3159
+ }
3160
+ }
3161
+
3162
+ // just add an empty component of createComponentOfType
3163
+
3164
+ let uniqueIdentifierBase = createComponentOfType + "|empty";
3165
+ let uniqueIdentifier = getUniqueIdentifierFromBase(
3166
+ uniqueIdentifierBase,
3167
+ uniqueIdentifiersUsed,
3168
+ );
3169
+
3170
+ let newReplacement = {
3171
+ componentType: createComponentOfType,
3172
+ uniqueIdentifier,
3173
+ };
3174
+ if (wrapDoenetAttributes) {
3175
+ newReplacement.doenetAttributes = wrapDoenetAttributes;
3176
+ }
3177
+ serializedReplacements.push(newReplacement);
3178
+ }
3179
+ } else if (newReplacements > numReplacementsForSource) {
3180
+ throw Error(
3181
+ `Something went wrong when creating replacements for ${component.componentName} as we ended up with too many replacements`,
3182
+ );
3183
+ }
3184
+ }
3185
+ } else {
3186
+ // not an array or array entry
3187
+
3188
+ if (stateVarObj.shadowingInstructions?.hasVariableComponentType) {
3189
+ // evaluate stateVarObj to make sure createComponentOfType is calculated and up-to-date
3190
+ await stateVarObj.value;
3191
+ }
3192
+
3193
+ if (!stateVarObj.shadowingInstructions?.createComponentOfType) {
3194
+ return {
3195
+ serializedReplacements: [],
3196
+ propVariablesCopiedByReplacement: [],
3197
+ };
3198
+ }
3199
+
3200
+ replacementInd++;
3201
+
3202
+ let propVariablesCopied = (propVariablesCopiedByReplacement[
3203
+ replacementInd
3204
+ ] = []);
3205
+
3206
+ propVariablesCopied.push(varName);
3207
+
3208
+ let uniqueIdentifierBase = target.componentName + "|shadow|" + varName;
3209
+ let uniqueIdentifier = getUniqueIdentifierFromBase(
3210
+ uniqueIdentifierBase,
3211
+ uniqueIdentifiersUsed,
3212
+ );
3213
+
3214
+ if (stateVarObj.shadowingInstructions.createComponentOfType === "string") {
3215
+ serializedReplacements.push(await stateVarObj.value);
3216
+ } else {
3217
+ let attributesFromComposite = convertAttributesForComponentType({
3218
+ attributes: component.attributes,
3219
+ componentType: stateVarObj.shadowingInstructions.createComponentOfType,
3220
+ componentInfoObjects,
3221
+ compositeAttributesObj,
3222
+ compositeCreatesNewNamespace: newNamespace,
3223
+ flags,
3224
+ });
3225
+
3226
+ if (link) {
3227
+ let attributesForReplacement = {};
3228
+
3229
+ if (
3230
+ stateVarObj.shadowingInstructions
3231
+ .addAttributeComponentsShadowingStateVariables
3232
+ ) {
3233
+ let classOfComponentToCreate =
3234
+ componentInfoObjects.allComponentClasses[
3235
+ stateVarObj.shadowingInstructions.createComponentOfType
3236
+ ];
3237
+ let attrObj = classOfComponentToCreate.createAttributesObject();
3238
+
3239
+ for (let attrName in stateVarObj.shadowingInstructions
3240
+ .addAttributeComponentsShadowingStateVariables) {
3241
+ let stateVariableToShadow =
3242
+ stateVarObj.shadowingInstructions
3243
+ .addAttributeComponentsShadowingStateVariables[attrName]
3244
+ .stateVariableToShadow;
3245
+ let attributeComponentType =
3246
+ attrObj[attrName]?.createComponentOfType;
3247
+
3248
+ if (attributeComponentType) {
3249
+ let shadowComponent = {
3250
+ componentType: attributeComponentType,
3251
+ downstreamDependencies: {
3252
+ [target.componentName]: [
3253
+ {
3254
+ compositeName: component.componentName,
3255
+ dependencyType: "referenceShadow",
3256
+ propVariable: stateVariableToShadow,
3257
+ },
3258
+ ],
3259
+ },
3260
+ };
3261
+
3262
+ attributesForReplacement[attrName] = {
3263
+ component: shadowComponent,
3264
+ };
3265
+ }
3266
+ }
3267
+ }
3268
+
3269
+ Object.assign(attributesForReplacement, attributesFromComposite);
3270
+
3271
+ serializedReplacements.push({
3272
+ componentType:
3273
+ stateVarObj.shadowingInstructions.createComponentOfType,
3274
+ attributes: attributesForReplacement,
3275
+ downstreamDependencies: {
3276
+ [target.componentName]: [
3277
+ {
3278
+ dependencyType: "referenceShadow",
3279
+ compositeName: component.componentName,
3280
+ propVariable: varName,
3281
+ additionalStateVariableShadowing:
3282
+ stateVarObj.shadowingInstructions
3283
+ .addStateVariablesShadowingStateVariables,
3284
+ },
3285
+ ],
3286
+ },
3287
+ uniqueIdentifier,
3288
+ });
3289
+ } else {
3290
+ let attributesForReplacement = {};
3291
+
3292
+ if (
3293
+ stateVarObj.shadowingInstructions
3294
+ .addAttributeComponentsShadowingStateVariables
3295
+ ) {
3296
+ let classOfComponentToCreate =
3297
+ componentInfoObjects.allComponentClasses[
3298
+ stateVarObj.shadowingInstructions.createComponentOfType
3299
+ ];
3300
+ let attrObj = classOfComponentToCreate.createAttributesObject();
3301
+
3302
+ let additionalAttributes = {};
3303
+ for (let attrName in stateVarObj.shadowingInstructions
3304
+ .addAttributeComponentsShadowingStateVariables) {
3305
+ if (attrObj[attrName]?.createComponentOfType) {
3306
+ // when copying with link=false, don't copy fixed attribute
3307
+ // so that, for example, a copy from a sequence with link=false is not fixed
3308
+ if (attrName !== "fixed") {
3309
+ let vName =
3310
+ stateVarObj.shadowingInstructions
3311
+ .addAttributeComponentsShadowingStateVariables[attrName]
3312
+ .stateVariableToShadow;
3313
+ let attributeValue = await target.state[vName].value;
3314
+ if (!target.state[vName].usedDefault) {
3315
+ additionalAttributes[attrName] = attributeValue;
3316
+ }
3317
+ }
3318
+ }
3319
+ }
3320
+
3321
+ let attributesFromComponent = convertAttributesForComponentType({
3322
+ attributes: additionalAttributes,
3323
+ componentType:
3324
+ stateVarObj.shadowingInstructions.createComponentOfType,
3325
+ componentInfoObjects,
3326
+ flags,
3327
+ });
3328
+
3329
+ if (stateVarObj.shadowingInstructions.attributesToShadow) {
3330
+ for (let attrName of stateVarObj.shadowingInstructions
3331
+ .attributesToShadow) {
3332
+ if (target.attributes[attrName]?.component) {
3333
+ attributesFromComponent[attrName] = {
3334
+ component: await target.attributes[
3335
+ attrName
3336
+ ]?.component.serialize({ copyAll: true, copyVariants: true }),
3337
+ };
3338
+ } else if (target.attributes[attrName]?.primitive !== undefined) {
3339
+ attributesFromComponent[attrName] = {
3340
+ primitive: JSON.parse(
3341
+ JSON.stringify(target.attributes[attrName].primitive),
3342
+ ),
3343
+ };
3344
+ }
3345
+ }
3346
+ }
3347
+
3348
+ Object.assign(attributesForReplacement, attributesFromComponent);
3349
+ }
3350
+
3351
+ Object.assign(attributesForReplacement, attributesFromComposite);
3352
+
3353
+ let primaryEssentialStateVariable = "value";
3354
+ let componentClass =
3355
+ componentInfoObjects.allComponentClasses[
3356
+ stateVarObj.shadowingInstructions.createComponentOfType
3357
+ ];
3358
+ if (componentClass.primaryEssentialStateVariable) {
3359
+ primaryEssentialStateVariable =
3360
+ componentClass.primaryEssentialStateVariable;
3361
+ } else if (componentClass.primaryStateVariableForDefinition) {
3362
+ primaryEssentialStateVariable =
3363
+ componentClass.primaryStateVariableForDefinition;
3364
+ }
3365
+
3366
+ let serializedComponent = {
3367
+ componentType:
3368
+ stateVarObj.shadowingInstructions.createComponentOfType,
3369
+ attributes: attributesForReplacement,
3370
+ state: {
3371
+ [primaryEssentialStateVariable]: stateVarValue,
3372
+ },
3373
+ uniqueIdentifier,
3374
+ };
3375
+
3376
+ serializedReplacements.push(serializedComponent);
3377
+ }
3378
+ }
3379
+ }
3380
+
3381
+ if (await component.stateValues.isPlainMacro) {
3382
+ for (let repl of serializedReplacements) {
3383
+ if (!repl.doenetAttributes) {
3384
+ repl.doenetAttributes = {};
3385
+ }
3386
+ repl.doenetAttributes.fromPlainMacro = true;
3387
+ if (repl.downstreamDependencies?.[target.componentName]?.[0]) {
3388
+ repl.downstreamDependencies[
3389
+ target.componentName
3390
+ ][0].fromPlainMacro = true;
3391
+ }
3392
+ }
3393
+ } else if (await component.stateValues.isPlainCopy) {
3394
+ for (let repl of serializedReplacements) {
3395
+ if (!repl.doenetAttributes) {
3396
+ repl.doenetAttributes = {};
3397
+ }
3398
+ repl.doenetAttributes.fromPlainCopy = true;
3399
+ if (repl.downstreamDependencies?.[target.componentName]?.[0]) {
3400
+ repl.downstreamDependencies[
3401
+ target.componentName
3402
+ ][0].fromPlainCopy = true;
3403
+ }
3404
+ }
3405
+ }
3406
+
3407
+ // console.log(`serializedReplacements for ${component.componentName}`)
3408
+ // console.log(JSON.parse(JSON.stringify(serializedReplacements)))
3409
+ // console.log(serializedReplacements)
3410
+
3411
+ return { serializedReplacements, propVariablesCopiedByReplacement };
3412
+ }