iobroker.javascript 10.2.5 → 10.3.0

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 (114) hide show
  1. package/README.md +6 -14
  2. package/admin/assets/AiChatPanel-CpY4Bun-.js +27 -0
  3. package/admin/assets/{AiChatService-BOL3J2Jd.js → AiChatService-QKcpW4jQ.js} +1 -1
  4. package/admin/assets/AiDiffView-DscPfZ38.js +1 -0
  5. package/admin/assets/{AiInlineProvider-BIlcrTkS.js → AiInlineProvider-DTSPKoXG.js} +1 -1
  6. package/admin/assets/BlocklyEditor-BZyoN1JE.js +301 -0
  7. package/admin/assets/Compile-B0uHjrBE.css +1 -0
  8. package/admin/assets/Compile-Oss28m_f.js +165 -0
  9. package/admin/assets/{Debugger-DwHHsh9O.js → Debugger-teJTIU-2.js} +4 -4
  10. package/admin/assets/{Documentation-Bc0RmoEF.js → Documentation-uz4Ut9pT.js} +4 -4
  11. package/admin/assets/ExpandMore-V5Ix1QB1.js +1 -0
  12. package/admin/assets/FbEditor-B8S-mCvc.css +1 -0
  13. package/admin/assets/FbEditor-aOZ-RpPV.js +15 -0
  14. package/admin/assets/Import-BIC5Ee9z.js +1 -0
  15. package/admin/assets/NotificationsActive-BdzH44gp.js +1 -0
  16. package/admin/assets/RulesEditor-CcDVthPa.js +1 -0
  17. package/admin/assets/{ScriptEditor-CEHpEFp7.js → ScriptEditor-CviB6Hif.js} +2 -2
  18. package/admin/assets/ScriptEditorVanillaMonaco-ByuXwybM.js +3 -0
  19. package/admin/assets/Send-Mdo32jMb.js +1 -0
  20. package/admin/assets/{_virtual_mf-localSharedImportMap___mfe_internal__iobroker_javascript__mf_owner__1-CM95r358.js → _virtual_mf-localSharedImportMap___mfe_internal__iobroker_javascript__mf_owner__1-BnL93BgK.js} +1 -1
  21. package/admin/assets/{_virtual_mf___mfe_internal__iobroker_javascript__mf_owner__180366418666083__loadShare___mf_0_iobroker_mf_1_gui_mf_2_components__loadShare__.js-BEpNZh4U.js → _virtual_mf___mfe_internal__iobroker_javascript__mf_owner__180366418666083__loadShare___mf_0_iobroker_mf_1_gui_mf_2_components__loadShare__.js-NI-3Uv4e.js} +75 -75
  22. package/admin/assets/{_virtual_mf___mfe_internal__iobroker_javascript__mf_owner__180366418666083__loadShare__react_mf_2_dom_mf_1_client__loadShare__.js-FeM77flT.js → _virtual_mf___mfe_internal__iobroker_javascript__mf_owner__180366418666083__loadShare__react_mf_2_dom_mf_1_client__loadShare__.js-DVaMIZyC.js} +1 -1
  23. package/admin/assets/aiPromptBuilder-yTB6N2VT.js +1 -0
  24. package/admin/assets/blocklyTheme-CGhU3cEO.js +1 -0
  25. package/admin/assets/blocks_action-BQ4O7NRE.js +1 -0
  26. package/admin/assets/{blocks_convert-BP2RjhQH.js → blocks_convert-0VBjfhqQ.js} +1 -1
  27. package/admin/assets/blocks_logic-DAo99xDr.js +1 -0
  28. package/admin/assets/blocks_number-C--e19NU.js +1 -0
  29. package/admin/assets/blocks_object-D0TPhdzg.js +1 -0
  30. package/admin/assets/blocks_procedures-DgTxgXdB.js +3 -0
  31. package/admin/assets/{blocks_sendto-qIKzOAcV.js → blocks_sendto-CRIrtOUc.js} +1 -1
  32. package/admin/assets/blocks_switch-b_GYfF0n.js +2 -0
  33. package/admin/assets/blocks_system-BdkUdSsc.js +1 -0
  34. package/admin/assets/blocks_text-DSFhEVOf.js +1 -0
  35. package/admin/assets/blocks_time-CqALAiJp.js +1 -0
  36. package/admin/assets/blocks_timeout-yrOD2pZp.js +1 -0
  37. package/admin/assets/{blocks_trigger-CnmXLCUE.js → blocks_trigger-DeAYXpSS.js} +1 -1
  38. package/admin/assets/{cronHoverProvider-CcIFAhVy.js → cronHoverProvider-DoO2_tpG.js} +1 -1
  39. package/admin/assets/{field_cron-Ba46q8Qc.js → field_cron-D3Ts_s9M.js} +1 -1
  40. package/admin/assets/{field_oid-lWCjOzuq.js → field_oid-BRNXredg.js} +1 -1
  41. package/admin/assets/{field_script-BCWZHhnW.js → field_script-3X6ousg7.js} +1 -1
  42. package/admin/assets/helpers-BTGaTdnT.js +1 -0
  43. package/admin/assets/{hostInit-CVybS7BB.js → hostInit-2h2Cbsaw.js} +1 -1
  44. package/admin/assets/index-BHhhebRG.css +1 -0
  45. package/admin/assets/index-CbQlIKB_.js +156 -0
  46. package/admin/assets/{inlineChatWidget-N8xIkvxX.js → inlineChatWidget-BwQVCPkx.js} +2 -2
  47. package/admin/assets/{inlineDiffController-BuqYsKKq.js → inlineDiffController-BsDDsDHn.js} +2 -2
  48. package/admin/assets/loadBlocks-RpqM7PwO.js +117 -0
  49. package/admin/assets/loadMonaco-BVOEahNw.js +1 -0
  50. package/admin/assets/{mf-entry-bootstrap-0-a5a39621.js → mf-entry-bootstrap-0-0deef484.js} +3 -3
  51. package/admin/assets/{pendingShares-DOAkyFMS.js → pendingShares-BaAadIDv.js} +1 -1
  52. package/admin/assets/reactour.esm-DX9ZgYlx.js +137 -0
  53. package/admin/assets/{stateHoverProvider-BYAbe1Ay.js → stateHoverProvider-BEadnSXp.js} +1 -1
  54. package/admin/assets/tileFbd-CWAy7R7m.svg +85 -0
  55. package/admin/mf-manifest.json +1 -1
  56. package/admin/mf-stats.json +1 -1
  57. package/admin/remoteEntry.js +2 -2
  58. package/admin/tab.html +3 -7
  59. package/build/lib/fb/analyze.js +288 -0
  60. package/build/lib/fb/analyze.js.map +1 -0
  61. package/build/lib/fb/blocks.js +605 -0
  62. package/build/lib/fb/blocks.js.map +1 -0
  63. package/build/lib/fb/generate.js +326 -0
  64. package/build/lib/fb/generate.js.map +1 -0
  65. package/build/lib/fb/graph.js +240 -0
  66. package/build/lib/fb/graph.js.map +1 -0
  67. package/build/lib/fb/index.js +57 -0
  68. package/build/lib/fb/index.js.map +1 -0
  69. package/build/lib/fb/js.js +33 -0
  70. package/build/lib/fb/js.js.map +1 -0
  71. package/build/lib/fb/layout.js +205 -0
  72. package/build/lib/fb/layout.js.map +1 -0
  73. package/build/lib/fb/library.js +657 -0
  74. package/build/lib/fb/library.js.map +1 -0
  75. package/build/lib/fb/runtime.js +793 -0
  76. package/build/lib/fb/runtime.js.map +1 -0
  77. package/build/lib/fb/time.js +76 -0
  78. package/build/lib/fb/time.js.map +1 -0
  79. package/build/lib/fb/types.js +19 -0
  80. package/build/lib/fb/types.js.map +1 -0
  81. package/build/lib/fb/user.js +78 -0
  82. package/build/lib/fb/user.js.map +1 -0
  83. package/build/lib/javascript.d.ts +1 -1
  84. package/build/lib/mirror.js +4 -0
  85. package/build/lib/mirror.js.map +1 -1
  86. package/build/lib/sandbox.js +44 -0
  87. package/build/lib/sandbox.js.map +1 -1
  88. package/build/main.js +66 -1
  89. package/build/main.js.map +1 -1
  90. package/build/types.d.ts +9 -1
  91. package/docs/de/fbd.md +274 -0
  92. package/docs/en/fbd.md +260 -0
  93. package/io-package.json +39 -15
  94. package/package.json +1 -1
  95. package/admin/assets/AiChatPanel-oBeXbUFv.js +0 -27
  96. package/admin/assets/AiDiffView-C-KKjnJD.js +0 -1
  97. package/admin/assets/Error-DZ4vCykD.js +0 -1
  98. package/admin/assets/Import-Cu02ceLW.js +0 -1
  99. package/admin/assets/RulesEditor-QCbi1lV_.js +0 -1
  100. package/admin/assets/ScriptEditorVanillaMonaco-ChQmnk0p.js +0 -3
  101. package/admin/assets/aiPromptBuilder-DKler0UK.js +0 -1
  102. package/admin/assets/blocks_action-DywZVfRY.js +0 -1
  103. package/admin/assets/blocks_logic-CdTl5YZw.js +0 -1
  104. package/admin/assets/blocks_number-DXFd9Rva.js +0 -1
  105. package/admin/assets/blocks_object-by1uBDHi.js +0 -1
  106. package/admin/assets/blocks_procedures-BcJ7N70D.js +0 -3
  107. package/admin/assets/blocks_switch-dLF6hSJl.js +0 -2
  108. package/admin/assets/blocks_system-DmX-SBy8.js +0 -1
  109. package/admin/assets/blocks_text-BI4zNU3o.js +0 -1
  110. package/admin/assets/blocks_time-BgYA4Y_4.js +0 -1
  111. package/admin/assets/blocks_timeout-DUzgMyAu.js +0 -1
  112. package/admin/assets/helpers-CnEjYAup.js +0 -1
  113. package/admin/assets/index-B3s0zmWC.js +0 -871
  114. package/admin/assets/index-CXaeqPRy.css +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graph.js","sourceRoot":"","sources":["../../../src/lib/fb/graph.ts"],"names":[],"mappings":";;;AAqCA,kCASC;AAGD,wCAMC;AAGD,sCASC;AAED,8BAYC;AAGD,wCAOC;AAED,gCAYC;AAQD,oCAEC;AAGD,4BAYC;AAMD,kCA4BC;AAGD,wCAmEC;AAMD,gCAiBC;AAGD,kCAQC;AAED,wCAEC;AAhRD,uCAAwC;AACxC,mCAYiB;AAEjB,yEAAyE;AAC5D,QAAA,eAAe,GAAG,SAAS,CAAC;AAE5B,QAAA,mBAAmB,GAAG,GAAG,CAAC;AAC1B,QAAA,eAAe,GAAG,EAAE,CAAC;AACrB,QAAA,eAAe,GAAG,KAAK,CAAC;AAErC,oGAAoG;AACvF,QAAA,aAAa,GAAG,0BAA0B,CAAC;AAExD,MAAM,YAAY,GAAmB,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;AAY/E,SAAgB,WAAW;IACvB,OAAO;QACH,MAAM,EAAE,iBAAS;QACjB,OAAO,EAAE,0BAAkB;QAC3B,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,2BAAmB,EAAE;QAChD,MAAM,EAAE,EAAE;QACV,KAAK,EAAE,EAAE;QACT,QAAQ,EAAE,EAAE;KACf,CAAC;AACN,CAAC;AAED,8CAA8C;AAC9C,SAAgB,cAAc,CAAC,KAAc,EAAE,IAAe,EAAE,GAAgB;IAC5E,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC3B,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,IAAI,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;QACzG,OAAO,YAAY,CAAC,QAAQ,CAAC,KAAqB,CAAC,CAAC,CAAC,CAAE,KAAsB,CAAC,CAAC,CAAC,MAAM,CAAC;IAC3F,CAAC;IACD,OAAO,IAAI,CAAC;AAChB,CAAC;AAED,8CAA8C;AAC9C,SAAgB,aAAa,CAAC,KAAc,EAAE,GAAe;IACzD,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC;QAClB,OAAO,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC;IAC7B,CAAC;IACD,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC3C,OAAO,IAAI,CAAC,GAAG,CACX,GAAG,CAAC,UAAU,CAAC,GAAG,EAClB,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAChG,CAAC;AACN,CAAC;AAED,SAAgB,SAAS,CAAC,KAAc,EAAE,GAAG,GAAG,IAAA,qBAAW,EAAC,KAAK,CAAC,IAAI,CAAC;IACnE,IAAI,CAAC,GAAG,EAAE,CAAC;QACP,OAAO,EAAE,CAAC;IACd,CAAC;IACD,MAAM,MAAM,GAAY,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,EAAE,GAAG,GAAG,EAAE,IAAI,EAAE,cAAc,CAAC,KAAK,EAAE,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IACxG,IAAI,GAAG,CAAC,UAAU,EAAE,CAAC;QACjB,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,YAAY,EAAE,GAAG,GAAG,CAAC,UAAU,CAAC;QAC/D,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,aAAa,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAClD,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,GAAG,MAAM,GAAG,CAAC,EAAE,EAAE,IAAI,EAAE,cAAc,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,CAAC,EAAE,OAAO,EAAE,YAAY,EAAE,CAAC,CAAC;QACxG,CAAC;IACL,CAAC;IACD,OAAO,MAAM,CAAC;AAClB,CAAC;AAED,kEAAkE;AAClE,SAAgB,cAAc,CAAC,KAAc,EAAE,GAAe;IAC1D,IAAI,CAAC,GAAG,CAAC,iBAAiB,EAAE,CAAC;QACzB,OAAO,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC;IAC9B,CAAC;IACD,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,GAAG,CAAC,iBAAiB,CAAC;IAC3C,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC5C,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AAC1F,CAAC;AAED,SAAgB,UAAU,CAAC,KAAc,EAAE,GAAG,GAAG,IAAA,qBAAW,EAAC,KAAK,CAAC,IAAI,CAAC;IACpE,IAAI,CAAC,GAAG,EAAE,CAAC;QACP,OAAO,EAAE,CAAC;IACd,CAAC;IACD,MAAM,OAAO,GAAY,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,EAAE,GAAG,GAAG,EAAE,IAAI,EAAE,cAAc,CAAC,KAAK,EAAE,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IAC1G,IAAI,GAAG,CAAC,iBAAiB,EAAE,CAAC;QACxB,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,GAAG,CAAC,iBAAiB,CAAC;QAC/C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,cAAc,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YACnD,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,GAAG,MAAM,GAAG,CAAC,EAAE,EAAE,IAAI,EAAE,cAAc,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;QAClF,CAAC;IACL,CAAC;IACD,OAAO,OAAO,CAAC;AACnB,CAAC;AAED;;;;;GAKG;AACH,SAAgB,YAAY,CAAC,IAA0B,EAAE,EAAwB;IAC7E,OAAO,EAAE,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,EAAE,IAAI,CAAC,IAAI,KAAK,KAAK,IAAI,EAAE,KAAK,MAAM,CAAC,CAAC;AAC9F,CAAC;AAED,oDAAoD;AACpD,SAAgB,QAAQ,CAAC,MAAc,EAAE,IAAsB;IAC3D,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC;IAC5B,IAAI,GAAG,GAAG,CAAC,CAAC;IACZ,KAAK,MAAM,EAAE,IAAI,KAAK,EAAE,CAAC;QACrB,IAAI,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;YACxB,MAAM,CAAC,GAAG,MAAM,CAAC,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;YAC9C,IAAI,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,GAAG,EAAE,CAAC;gBACjC,GAAG,GAAG,CAAC,CAAC;YACZ,CAAC;QACL,CAAC;IACL,CAAC;IACD,OAAO,GAAG,MAAM,GAAG,GAAG,GAAG,CAAC,EAAE,CAAC;AACjC,CAAC;AAED;;;GAGG;AACH,SAAgB,WAAW,CAAC,IAAY,EAAE,GAAqB,EAAE,KAAc;IAC3E,MAAM,GAAG,GAAG,IAAA,qBAAW,EAAC,IAAI,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC;IAChD,MAAM,EAAE,GAAG,QAAQ,CACf,GAAG,EACH,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CACtC,CAAC;IACF,gEAAgE;IAChE,MAAM,IAAI,GAAG,QAAQ,CACjB,GAAG,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,EAClE,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CACxC,CAAC;IACF,MAAM,KAAK,GAAY,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC;IAC/C,MAAM,MAAM,GAA4B,EAAE,CAAC;IAC3C,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,KAAK,CAAC,EAAE;QACzB,IAAI,KAAK,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;YAC9B,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,OAAO,CAAC;QACrC,CAAC;IACL,CAAC,CAAC,CAAC;IACH,IAAI,GAAG,EAAE,UAAU,EAAE,CAAC;QAClB,MAAM,CAAC,MAAM,GAAG,GAAG,CAAC,UAAU,CAAC,KAAK,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC;IAC/D,CAAC;IACD,IAAI,GAAG,EAAE,iBAAiB,EAAE,CAAC;QACzB,MAAM,CAAC,OAAO,GAAG,GAAG,CAAC,iBAAiB,CAAC,KAAK,IAAI,GAAG,CAAC,iBAAiB,CAAC,GAAG,CAAC;IAC9E,CAAC;IACD,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,CAAC;QAC7B,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC;IAC1B,CAAC;IACD,OAAO,KAAK,CAAC;AACjB,CAAC;AAED,yEAAyE;AACzE,SAAgB,cAAc,CAAC,IAAyC;IACpE,MAAM,KAAK,GAAG,WAAW,EAAE,CAAC;IAC5B,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;QACpC,OAAO,KAAK,CAAC;IACjB,CAAC;IACD,KAAK,CAAC,MAAM,GAAG,OAAO,IAAI,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,iBAAS,CAAC;IACzE,KAAK,CAAC,OAAO,GAAG,OAAO,IAAI,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,0BAAkB,CAAC;IACrF,IAAI,IAAI,CAAC,KAAK,IAAI,OAAO,IAAI,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC/C,KAAK,CAAC,KAAK,GAAG;YACV,IAAI,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM;YACtF,EAAE,EAAE,OAAO,IAAI,CAAC,KAAK,CAAC,EAAE,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,2BAAmB;SAC9E,CAAC;IACN,CAAC;IACD,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACjH,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;QACzB,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACtD,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACvB,CAAC;QACD,IAAI,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACjC,KAAK,CAAC,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAClC,CAAC;IACL,CAAC,CAAC,CAAC;IACH,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC;QACnC,CAAC,CAAC,IAAI,CAAC,KAAK;aACL,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;aAC1E,GAAG,CAAC,IAAI,CAAC,EAAE;YACR,MAAM,KAAK,GAAW,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC;YACpE,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;gBACrB,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC;YACtB,CAAC;YACD,IAAI,OAAO,IAAI,CAAC,KAAK,KAAK,QAAQ,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;gBACtD,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;YACpC,CAAC;YACD,OAAO,KAAK,CAAC;QACjB,CAAC,CAAC;QACR,CAAC,CAAC,EAAE,CAAC;IACT,KAAK,CAAC,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAElG,MAAM,IAAI,GAAG,CAAC,KAAuC,EAAsB,EAAE,CACzE,KAAK,IAAI,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ;QACrE,CAAC,CAAC;YACI,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,OAAO,EAAE,OAAO,KAAK,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;YAC9D,GAAG,CAAC,OAAO,KAAK,CAAC,WAAW,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACvF;QACH,CAAC,CAAC,IAAI,CAAC;IAEf,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC/B,IAAI,KAAK,EAAE,CAAC;QACR,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC;IACxB,CAAC;IACD,IAAI,IAAI,CAAC,UAAU,IAAI,OAAO,IAAI,CAAC,UAAU,KAAK,QAAQ,EAAE,CAAC;QACzD,MAAM,UAAU,GAAgC,EAAE,CAAC;QACnD,KAAK,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;YACzD,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC;YAC5B,IAAI,QAAQ,IAAI,QAAQ,CAAC,IAAI,KAAK,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;gBACnD,gEAAgE;gBAChE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,KAAK,EAAE,GAAG,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBACnF,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;YACrD,CAAC;QACL,CAAC;QACD,IAAI,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,MAAM,EAAE,CAAC;YACjC,KAAK,CAAC,UAAU,GAAG,UAAU,CAAC;QAClC,CAAC;IACL,CAAC;IACD,OAAO,KAAK,CAAC;AACjB,CAAC;AAED;;;GAGG;AACH,SAAgB,UAAU,CAAC,MAAiC;IACxD,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE,CAAC;QAClB,OAAO,WAAW,EAAE,CAAC;IACzB,CAAC;IACD,MAAM,GAAG,GAAG,MAAM,CAAC,WAAW,CAAC,uBAAe,CAAC,CAAC;IAChD,IAAI,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,IAAI,MAAM,CAAC,GAAG,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,EAAE,CAAC;QACtD,OAAO,IAAI,CAAC;IAChB,CAAC;IACD,MAAM,IAAI,GAAG,MAAM;SACd,SAAS,CAAC,GAAG,GAAG,uBAAe,CAAC,MAAM,CAAC;SACvC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;SACd,IAAI,EAAE,CAAC;IACZ,IAAI,CAAC;QACD,OAAO,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAqB,CAAC,CAAC;IAChE,CAAC;IAAC,MAAM,CAAC;QACL,OAAO,IAAI,CAAC;IAChB,CAAC;AACL,CAAC;AAED,0EAA0E;AAC1E,SAAgB,WAAW,CAAC,MAAiC;IACzD,IAAI,CAAC,MAAM,EAAE,CAAC;QACV,OAAO,KAAK,CAAC;IACjB,CAAC;IACD,gEAAgE;IAChE,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAC3C,MAAM,GAAG,GAAG,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;IACtC,OAAO,OAAO,CAAC,SAAS,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,uBAAe,CAAC,CAAC;AAClE,CAAC;AAED,SAAgB,cAAc,CAAC,KAAc;IACzC,OAAO,GAAG,uBAAe,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC;AACxD,CAAC","sourcesContent":["import { getBlockDef } from './library';\nimport {\n FB_FORMAT,\n FB_RUNTIME_VERSION,\n type FbBlock,\n type FbBlockDef,\n type FbBlockInfo,\n type FbGraph,\n type FbLink,\n type FbUserBlock,\n type FbPinType,\n type FbSignalType,\n type FbValue,\n} from './types';\n\n/** The last line of the script source holds the graph: `//#fbd:{...}` */\nexport const FB_GRAPH_MARKER = '//#fbd:';\n\nexport const FB_CYCLE_DEFAULT_MS = 200;\nexport const FB_CYCLE_MIN_MS = 50;\nexport const FB_CYCLE_MAX_MS = 10000;\n\n/** IDs end up in the generated code (`I.b7`, `S['b7.Q']`), so they are restricted to identifiers */\nexport const FB_ID_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;\n\nconst SIGNAL_TYPES: FbSignalType[] = ['BOOL', 'INT', 'REAL', 'TIME', 'STRING'];\n\n/** A pin of a concrete block: extensible inputs are expanded and parameter types resolved */\nexport interface FbPin {\n id: string;\n /** `ANY` only for inputs that take every type */\n type: FbSignalType | 'ANY';\n param?: boolean;\n default?: FbValue;\n clock?: boolean;\n}\n\nexport function createGraph(): FbGraph {\n return {\n format: FB_FORMAT,\n runtime: FB_RUNTIME_VERSION,\n cycle: { mode: 'auto', ms: FB_CYCLE_DEFAULT_MS },\n blocks: [],\n links: [],\n comments: [],\n };\n}\n\n/** The signal type a pin has in this block */\nexport function resolvePinType(block: FbBlock, type: FbPinType, def?: FbBlockDef): FbSignalType | 'ANY' {\n if (typeof type === 'object') {\n const value = block.params?.[type.param] ?? def?.params?.find(param => param.id === type.param)?.default;\n return SIGNAL_TYPES.includes(value as FbSignalType) ? (value as FbSignalType) : 'REAL';\n }\n return type;\n}\n\n/** Number of inputs of an extensible block */\nexport function getInputCount(block: FbBlock, def: FbBlockDef): number {\n if (!def.extensible) {\n return def.inputs.length;\n }\n const count = Number(block.params?.inputs);\n return Math.max(\n def.extensible.min,\n Math.min(def.extensible.max, Math.round(Number.isFinite(count) ? count : def.extensible.min)),\n );\n}\n\nexport function getInputs(block: FbBlock, def = getBlockDef(block.type)): FbPin[] {\n if (!def) {\n return [];\n }\n const inputs: FbPin[] = def.inputs.map(pin => ({ ...pin, type: resolvePinType(block, pin.type, def) }));\n if (def.extensible) {\n const { prefix, type, default: defaultValue } = def.extensible;\n for (let i = 1; i <= getInputCount(block, def); i++) {\n inputs.push({ id: `${prefix}${i}`, type: resolvePinType(block, type, def), default: defaultValue });\n }\n }\n return inputs;\n}\n\n/** Number of outputs of a block with a variable number of them */\nexport function getOutputCount(block: FbBlock, def: FbBlockDef): number {\n if (!def.extensibleOutputs) {\n return def.outputs.length;\n }\n const { min, max } = def.extensibleOutputs;\n const count = Number(block.params?.outputs);\n return Math.max(min, Math.min(max, Math.round(Number.isFinite(count) ? count : min)));\n}\n\nexport function getOutputs(block: FbBlock, def = getBlockDef(block.type)): FbPin[] {\n if (!def) {\n return [];\n }\n const outputs: FbPin[] = def.outputs.map(pin => ({ ...pin, type: resolvePinType(block, pin.type, def) }));\n if (def.extensibleOutputs) {\n const { prefix, type } = def.extensibleOutputs;\n for (let i = 1; i <= getOutputCount(block, def); i++) {\n outputs.push({ id: `${prefix}${i}`, type: resolvePinType(block, type, def) });\n }\n }\n return outputs;\n}\n\n/**\n * Whether an output of type `from` may drive an input of type `to`.\n *\n * Only widening happens by itself (INT to REAL); everything else needs a block that converts. An\n * output of the type ANY - of a JS block, whose code decides - goes anywhere.\n */\nexport function isCompatible(from: FbSignalType | 'ANY', to: FbSignalType | 'ANY'): boolean {\n return to === 'ANY' || from === 'ANY' || from === to || (from === 'INT' && to === 'REAL');\n}\n\n/** A new ID that is not in `used`: `<prefix><n>` */\nexport function createId(prefix: string, used: Iterable<string>): string {\n const taken = new Set(used);\n let max = 0;\n for (const id of taken) {\n if (id.startsWith(prefix)) {\n const n = Number(id.substring(prefix.length));\n if (Number.isInteger(n) && n > max) {\n max = n;\n }\n }\n }\n return `${prefix}${max + 1}`;\n}\n\n/**\n * A new block of a type, with the parameters at their defaults. A user block must be in\n * `graph.userBlocks` already.\n */\nexport function createBlock(type: string, pos: [number, number], graph: FbGraph): FbBlock {\n const def = getBlockDef(type, graph.userBlocks);\n const id = createId(\n 'b',\n graph.blocks.map(block => block.id),\n );\n // a user block is named after its name, not after `@userFb/...`\n const name = createId(\n `${def?.user ? def.user.name.trim().replace(/\\s+/g, '_') : type}_`,\n graph.blocks.map(block => block.name),\n );\n const block: FbBlock = { id, type, name, pos };\n const params: Record<string, FbValue> = {};\n def?.params?.forEach(param => {\n if (param.default !== undefined) {\n params[param.id] = param.default;\n }\n });\n if (def?.extensible) {\n params.inputs = def.extensible.count ?? def.extensible.min;\n }\n if (def?.extensibleOutputs) {\n params.outputs = def.extensibleOutputs.count ?? def.extensibleOutputs.min;\n }\n if (Object.keys(params).length) {\n block.params = params;\n }\n return block;\n}\n\n/** Brings a parsed graph into shape: missing parts get their defaults */\nexport function normalizeGraph(data: Partial<FbGraph> | null | undefined): FbGraph {\n const graph = createGraph();\n if (!data || typeof data !== 'object') {\n return graph;\n }\n graph.format = typeof data.format === 'number' ? data.format : FB_FORMAT;\n graph.runtime = typeof data.runtime === 'string' ? data.runtime : FB_RUNTIME_VERSION;\n if (data.cycle && typeof data.cycle === 'object') {\n graph.cycle = {\n mode: ['auto', 'cyclic', 'event'].includes(data.cycle.mode) ? data.cycle.mode : 'auto',\n ms: typeof data.cycle.ms === 'number' ? data.cycle.ms : FB_CYCLE_DEFAULT_MS,\n };\n }\n graph.blocks = Array.isArray(data.blocks) ? data.blocks.filter(block => block && typeof block === 'object') : [];\n graph.blocks.forEach(block => {\n if (!Array.isArray(block.pos) || block.pos.length !== 2) {\n block.pos = [0, 0];\n }\n if (typeof block.name !== 'string') {\n block.name = String(block.id);\n }\n });\n graph.links = Array.isArray(data.links)\n ? data.links\n .filter(link => link && Array.isArray(link.from) && Array.isArray(link.to))\n .map(link => {\n const clean: FbLink = { id: link.id, from: link.from, to: link.to };\n if (link.mark === true) {\n clean.mark = true;\n }\n if (typeof link.label === 'string' && link.label.trim()) {\n clean.label = link.label.trim();\n }\n return clean;\n })\n : [];\n graph.comments = Array.isArray(data.comments) ? data.comments.filter(comment => comment?.id) : [];\n\n const info = (value: Partial<FbBlockInfo> | undefined): FbBlockInfo | null =>\n value && typeof value.type === 'string' && typeof value.name === 'string'\n ? {\n type: value.type,\n name: value.name,\n version: typeof value.version === 'number' ? value.version : 1,\n ...(typeof value.description === 'string' ? { description: value.description } : {}),\n }\n : null;\n\n const block = info(data.block);\n if (block) {\n graph.block = block;\n }\n if (data.userBlocks && typeof data.userBlocks === 'object') {\n const userBlocks: Record<string, FbUserBlock> = {};\n for (const [type, user] of Object.entries(data.userBlocks)) {\n const userInfo = info(user);\n if (userInfo && userInfo.type === type && user.graph) {\n // the copies carry neither a block info nor copies of their own\n const { block: _block, userBlocks: _inner, ...inner } = normalizeGraph(user.graph);\n userBlocks[type] = { ...userInfo, graph: inner };\n }\n }\n if (Object.keys(userBlocks).length) {\n graph.userBlocks = userBlocks;\n }\n }\n return graph;\n}\n\n/**\n * Reads the graph out of a script source. Returns `null` when the source holds no graph; an empty\n * source gives an empty graph, which is what a new script starts with.\n */\nexport function parseGraph(source: string | null | undefined): FbGraph | null {\n if (!source?.trim()) {\n return createGraph();\n }\n const pos = source.lastIndexOf(FB_GRAPH_MARKER);\n if (pos === -1 || (pos > 0 && source[pos - 1] !== '\\n')) {\n return null;\n }\n const line = source\n .substring(pos + FB_GRAPH_MARKER.length)\n .split('\\n')[0]\n .trim();\n try {\n return normalizeGraph(JSON.parse(line) as Partial<FbGraph>);\n } catch {\n return null;\n }\n}\n\n/** Whether a script source was generated from a function block diagram */\nexport function isFbdSource(source: string | null | undefined): boolean {\n if (!source) {\n return false;\n }\n // no trimEnd(): the editor compiles this with an ES2018 library\n const trimmed = source.replace(/\\s+$/, '');\n const pos = trimmed.lastIndexOf('\\n');\n return trimmed.substring(pos + 1).startsWith(FB_GRAPH_MARKER);\n}\n\nexport function serializeGraph(graph: FbGraph): string {\n return `${FB_GRAPH_MARKER}${JSON.stringify(graph)}`;\n}\n"]}
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
36
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.fbBlocks = void 0;
40
+ /**
41
+ * fb-core: the model, the block library, the checks and the code generator of function block
42
+ * diagrams. No React, no DOM, no Node - the editor and the adapter both use it.
43
+ *
44
+ * The runtime the generated code calls is `./runtime`, which is Node only and not exported here. Its
45
+ * blocks are, as `fbBlocks` - the editor runs them for the preview of a block.
46
+ */
47
+ exports.fbBlocks = __importStar(require("./blocks"));
48
+ __exportStar(require("./types"), exports);
49
+ __exportStar(require("./library"), exports);
50
+ __exportStar(require("./graph"), exports);
51
+ __exportStar(require("./analyze"), exports);
52
+ __exportStar(require("./generate"), exports);
53
+ __exportStar(require("./time"), exports);
54
+ __exportStar(require("./js"), exports);
55
+ __exportStar(require("./user"), exports);
56
+ __exportStar(require("./layout"), exports);
57
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/lib/fb/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;;;;;;GAMG;AACH,qDAAqC;AACrC,0CAAwB;AACxB,4CAA0B;AAC1B,0CAAwB;AACxB,4CAA0B;AAC1B,6CAA2B;AAC3B,yCAAuB;AACvB,uCAAqB;AACrB,yCAAuB;AACvB,2CAAyB","sourcesContent":["/**\n * fb-core: the model, the block library, the checks and the code generator of function block\n * diagrams. No React, no DOM, no Node - the editor and the adapter both use it.\n *\n * The runtime the generated code calls is `./runtime`, which is Node only and not exported here. Its\n * blocks are, as `fbBlocks` - the editor runs them for the preview of a block.\n */\nexport * as fbBlocks from './blocks';\nexport * from './types';\nexport * from './library';\nexport * from './graph';\nexport * from './analyze';\nexport * from './generate';\nexport * from './time';\nexport * from './js';\nexport * from './user';\nexport * from './layout';\n"]}
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.jsParameters = jsParameters;
4
+ exports.jsCode = jsCode;
5
+ exports.checkJsCode = checkJsCode;
6
+ /**
7
+ * The JS block: code of the user that becomes a function of the generated script. Its parameters are
8
+ * the inputs of the block, then `dt`, `firstScan` and `state`.
9
+ */
10
+ const graph_1 = require("./graph");
11
+ /** The names the code of a JS block sees, in the order the function gets them */
12
+ function jsParameters(block, def) {
13
+ return [...(0, graph_1.getInputs)(block, def).map(pin => pin.id), 'dt', 'firstScan', 'state'];
14
+ }
15
+ /** The code of a JS block */
16
+ function jsCode(block, def) {
17
+ const code = block.params?.code ?? def.params?.find(param => param.id === 'code')?.default;
18
+ return typeof code === 'string' ? code : '';
19
+ }
20
+ /**
21
+ * The syntax error of the code of a JS block, or `null`. The body is parsed on its own, so code that
22
+ * closes the function early is an error too and cannot break the script around it.
23
+ */
24
+ function checkJsCode(code, parameters) {
25
+ try {
26
+ new Function(...parameters, code);
27
+ return null;
28
+ }
29
+ catch (error) {
30
+ return error?.message || String(error);
31
+ }
32
+ }
33
+ //# sourceMappingURL=js.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"js.js","sourceRoot":"","sources":["../../../src/lib/fb/js.ts"],"names":[],"mappings":";;AAQA,oCAEC;AAGD,wBAGC;AAMD,kCAOC;AA7BD;;;GAGG;AACH,mCAAoC;AAGpC,iFAAiF;AACjF,SAAgB,YAAY,CAAC,KAAc,EAAE,GAAe;IACxD,OAAO,CAAC,GAAG,IAAA,iBAAS,EAAC,KAAK,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,CAAC,CAAC;AACrF,CAAC;AAED,6BAA6B;AAC7B,SAAgB,MAAM,CAAC,KAAc,EAAE,GAAe;IAClD,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,EAAE,IAAI,IAAI,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,MAAM,CAAC,EAAE,OAAO,CAAC;IAC3F,OAAO,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;AAChD,CAAC;AAED;;;GAGG;AACH,SAAgB,WAAW,CAAC,IAAY,EAAE,UAAoB;IAC1D,IAAI,CAAC;QACD,IAAI,QAAQ,CAAC,GAAG,UAAU,EAAE,IAAI,CAAC,CAAC;QAClC,OAAO,IAAI,CAAC;IAChB,CAAC;IAAC,OAAO,KAAc,EAAE,CAAC;QACtB,OAAQ,KAAe,EAAE,OAAO,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC;IACtD,CAAC;AACL,CAAC","sourcesContent":["/**\n * The JS block: code of the user that becomes a function of the generated script. Its parameters are\n * the inputs of the block, then `dt`, `firstScan` and `state`.\n */\nimport { getInputs } from './graph';\nimport type { FbBlock, FbBlockDef } from './types';\n\n/** The names the code of a JS block sees, in the order the function gets them */\nexport function jsParameters(block: FbBlock, def: FbBlockDef): string[] {\n return [...getInputs(block, def).map(pin => pin.id), 'dt', 'firstScan', 'state'];\n}\n\n/** The code of a JS block */\nexport function jsCode(block: FbBlock, def: FbBlockDef): string {\n const code = block.params?.code ?? def.params?.find(param => param.id === 'code')?.default;\n return typeof code === 'string' ? code : '';\n}\n\n/**\n * The syntax error of the code of a JS block, or `null`. The body is parsed on its own, so code that\n * closes the function early is an error too and cannot break the script around it.\n */\nexport function checkJsCode(code: string, parameters: string[]): string | null {\n try {\n new Function(...parameters, code);\n return null;\n } catch (error: unknown) {\n return (error as Error)?.message || String(error);\n }\n}\n"]}
@@ -0,0 +1,205 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.layoutGraph = layoutGraph;
4
+ /**
5
+ * Arranges the blocks of a diagram automatically: in columns along the data flow, inputs on the
6
+ * left, outputs on the right, and each block as level as it can be with the blocks it is linked to,
7
+ * so the links run straight where possible.
8
+ *
9
+ * A layered layout in the manner of Sugiyama, kept small: columns by the longest path, the order in a
10
+ * column by the positions of the neighbours, and the positions by the mean of what the blocks of a
11
+ * column want, without overlaps. Links that lead back (feedback) do not count.
12
+ */
13
+ const analyze_1 = require("./analyze");
14
+ const graph_1 = require("./graph");
15
+ const library_1 = require("./library");
16
+ const DEFAULT_METRICS = { header: 22, detail: 18, pin: 20, frame: 6 };
17
+ const DEFAULT_WIDTH = 160;
18
+ /** Room between the columns - for the links, and the values of open inputs left of a block */
19
+ const GAP_X = 100;
20
+ const GAP_Y = 30;
21
+ const GRID = 10;
22
+ /** Rounds from one side to the other and back */
23
+ const PASSES = 4;
24
+ /** Blocks with a line under the type (state, value, pin, version) are that much higher */
25
+ function pinTop(def, metrics) {
26
+ return metrics.header + (def?.user || def?.params?.length ? metrics.detail : 0);
27
+ }
28
+ /** The top of a group of blocks that touch: the mean of what each of them wants */
29
+ function settle(cluster) {
30
+ let offset = 0;
31
+ let sum = 0;
32
+ cluster.ids.forEach((_id, i) => {
33
+ sum += cluster.wants[i] - offset;
34
+ offset += cluster.heights[i] + GAP_Y;
35
+ });
36
+ cluster.top = sum / cluster.ids.length;
37
+ }
38
+ function clusterHeight(cluster) {
39
+ return cluster.heights.reduce((sum, height) => sum + height + GAP_Y, 0) - GAP_Y;
40
+ }
41
+ /**
42
+ * New positions for the blocks of a diagram, by ID. The comments stay where they are; the top left
43
+ * corner of the blocks stays where it was.
44
+ */
45
+ function layoutGraph(graph, options = {}) {
46
+ if (!graph.blocks.length) {
47
+ return {};
48
+ }
49
+ const analysis = (0, analyze_1.analyzeGraph)(graph);
50
+ const feedback = new Set(analysis.feedback);
51
+ const links = analysis.links.filter(link => !feedback.has(link.id) && link.from[0] !== link.to[0]);
52
+ const metrics = options.metrics || DEFAULT_METRICS;
53
+ const PIN_HEIGHT = metrics.pin;
54
+ const items = new Map();
55
+ for (const block of graph.blocks) {
56
+ const def = (0, library_1.getBlockDef)(block.type, graph.userBlocks);
57
+ const rows = Math.max((0, graph_1.getInputs)(block, def).length, (0, graph_1.getOutputs)(block, def).length, 1);
58
+ const top = pinTop(def, metrics);
59
+ const size = options.sizes?.[block.id];
60
+ items.set(block.id, {
61
+ id: block.id,
62
+ block,
63
+ def,
64
+ width: size?.width || DEFAULT_WIDTH,
65
+ height: size?.height || top + rows * PIN_HEIGHT + metrics.frame,
66
+ pinTop: top,
67
+ });
68
+ }
69
+ const incoming = new Map();
70
+ const outgoing = new Map();
71
+ for (const link of links) {
72
+ incoming.set(link.to[0], [...(incoming.get(link.to[0]) || []), link]);
73
+ outgoing.set(link.from[0], [...(outgoing.get(link.from[0]) || []), link]);
74
+ }
75
+ // the pins, from the top of their block
76
+ const outputY = (link) => {
77
+ const item = items.get(link.from[0]);
78
+ const index = (0, graph_1.getOutputs)(item.block, item.def).findIndex(pin => pin.id === link.from[1]);
79
+ return item.pinTop + Math.max(index, 0) * PIN_HEIGHT + PIN_HEIGHT / 2;
80
+ };
81
+ const inputY = (link) => {
82
+ const item = items.get(link.to[0]);
83
+ const index = (0, graph_1.getInputs)(item.block, item.def).findIndex(pin => pin.id === link.to[1]);
84
+ return item.pinTop + Math.max(index, 0) * PIN_HEIGHT + PIN_HEIGHT / 2;
85
+ };
86
+ // Columns by the longest path. The execution order is a topological order of the links that do
87
+ // not lead back; blocks that cannot run (an unknown type) come last.
88
+ const sequence = graph.blocks
89
+ .map(block => block.id)
90
+ .sort((a, b) => (analysis.order[a] ?? Infinity) - (analysis.order[b] ?? Infinity));
91
+ const column = new Map();
92
+ for (const id of sequence) {
93
+ let index = 0;
94
+ for (const link of incoming.get(id) || []) {
95
+ index = Math.max(index, (column.get(link.from[0]) ?? 0) + 1);
96
+ }
97
+ column.set(id, index);
98
+ }
99
+ // a block that only gives a value, like CONST, goes next to where it is used
100
+ for (const id of [...sequence].reverse()) {
101
+ const type = items.get(id).block.type;
102
+ const next = outgoing.get(id) || [];
103
+ if (!incoming.get(id)?.length && next.length && type !== 'STATE_IN' && type !== 'FB_IN') {
104
+ column.set(id, Math.max(0, Math.min(...next.map(link => column.get(link.to[0]))) - 1));
105
+ }
106
+ }
107
+ // the outputs of the diagram in the last column
108
+ const last = Math.max(...column.values());
109
+ for (const id of sequence) {
110
+ const type = items.get(id).block.type;
111
+ if ((type === 'STATE_OUT' || type === 'FB_OUT') && !outgoing.get(id)?.length) {
112
+ column.set(id, last);
113
+ }
114
+ }
115
+ // the columns, at first in the order the blocks have from top to bottom
116
+ const columns = Array.from({ length: last + 1 }, () => []);
117
+ graph.blocks
118
+ .slice()
119
+ .sort((a, b) => a.pos[1] - b.pos[1] || a.pos[0] - b.pos[0])
120
+ .forEach(block => columns[column.get(block.id)].push(block.id));
121
+ const y = new Map();
122
+ for (const ids of columns) {
123
+ let top = 0;
124
+ for (const id of ids) {
125
+ y.set(id, top);
126
+ top += items.get(id).height + GAP_Y;
127
+ }
128
+ }
129
+ /**
130
+ * Places the blocks of a column where they want to be, without overlaps: blocks that would
131
+ * overlap form a group, which sits at the mean of what its blocks want.
132
+ */
133
+ const place = (ids, want) => {
134
+ const wishes = ids
135
+ .map((id, i) => ({ id, i, want: want(id) ?? y.get(id) }))
136
+ .sort((a, b) => a.want - b.want || a.i - b.i);
137
+ const clusters = [];
138
+ for (const wish of wishes) {
139
+ const cluster = {
140
+ ids: [wish.id],
141
+ wants: [wish.want],
142
+ heights: [items.get(wish.id).height],
143
+ top: wish.want,
144
+ };
145
+ clusters.push(cluster);
146
+ // merge with the groups above as long as they overlap
147
+ while (clusters.length > 1) {
148
+ const current = clusters[clusters.length - 1];
149
+ const above = clusters[clusters.length - 2];
150
+ if (above.top + clusterHeight(above) + GAP_Y <= current.top) {
151
+ break;
152
+ }
153
+ above.ids.push(...current.ids);
154
+ above.wants.push(...current.wants);
155
+ above.heights.push(...current.heights);
156
+ settle(above);
157
+ clusters.pop();
158
+ }
159
+ }
160
+ ids.length = 0;
161
+ for (const cluster of clusters) {
162
+ let top = cluster.top;
163
+ cluster.ids.forEach((id, i) => {
164
+ y.set(id, top);
165
+ top += cluster.heights[i] + GAP_Y;
166
+ ids.push(id);
167
+ });
168
+ }
169
+ };
170
+ const mean = (values) => values.length ? values.reduce((sum, value) => sum + value, 0) / values.length : null;
171
+ // level with the outputs that feed it
172
+ const fromLeft = (id) => mean((incoming.get(id) || []).map(link => y.get(link.from[0]) + outputY(link) - inputY(link)));
173
+ // level with the inputs it feeds
174
+ const fromRight = (id) => mean((outgoing.get(id) || []).map(link => y.get(link.to[0]) + inputY(link) - outputY(link)));
175
+ for (let pass = 0; pass < PASSES; pass++) {
176
+ for (let i = 1; i < columns.length; i++) {
177
+ place(columns[i], fromLeft);
178
+ }
179
+ for (let i = columns.length - 2; i >= 0; i--) {
180
+ place(columns[i], fromRight);
181
+ }
182
+ }
183
+ // the last round from left to right: the links of a chain run straight
184
+ for (let i = 1; i < columns.length; i++) {
185
+ place(columns[i], fromLeft);
186
+ }
187
+ // the columns side by side, each as wide as its widest block
188
+ const left = Math.min(...graph.blocks.map(block => block.pos[0]));
189
+ const top = Math.min(...graph.blocks.map(block => block.pos[1]));
190
+ const minY = Math.min(...y.values());
191
+ const positions = {};
192
+ let x = Math.round(left / GRID) * GRID;
193
+ for (const ids of columns) {
194
+ if (!ids.length) {
195
+ continue;
196
+ }
197
+ for (const id of ids) {
198
+ // not on the grid vertically: a link between pins at different heights would get a kink
199
+ positions[id] = [x, Math.round(top + y.get(id) - minY)];
200
+ }
201
+ x += Math.round((Math.max(...ids.map(id => items.get(id).width)) + GAP_X) / GRID) * GRID;
202
+ }
203
+ return positions;
204
+ }
205
+ //# sourceMappingURL=layout.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layout.js","sourceRoot":"","sources":["../../../src/lib/fb/layout.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Arranges the blocks of a diagram automatically: in columns along the data flow, inputs on the\n * left, outputs on the right, and each block as level as it can be with the blocks it is linked to,\n * so the links run straight where possible.\n *\n * A layered layout in the manner of Sugiyama, kept small: columns by the longest path, the order in a\n * column by the positions of the neighbours, and the positions by the mean of what the blocks of a\n * column want, without overlaps. Links that lead back (feedback) do not count.\n */\nimport { analyzeGraph } from './analyze';\nimport { getInputs, getOutputs } from './graph';\nimport { getBlockDef } from './library';\nimport type { FbBlock, FbBlockDef, FbGraph, FbLink } from './types';\n\n/** How the editor draws a block, in pixels */\nexport interface FbBlockMetrics {\n /** From the top of the block to the line under the type */\n header: number;\n /** The line under the type: the state, the value, the pin, the version */\n detail: number;\n /** One row of pins */\n pin: number;\n /** Below the last row */\n frame: number;\n}\n\nexport interface FbLayoutOptions {\n /** The sizes of the blocks as they are drawn, by ID; estimated where missing */\n sizes?: Record<string, { width: number; height: number }>;\n /** Where the pins are - by default as the first editor drew them */\n metrics?: FbBlockMetrics;\n}\n\nconst DEFAULT_METRICS: FbBlockMetrics = { header: 22, detail: 18, pin: 20, frame: 6 };\nconst DEFAULT_WIDTH = 160;\n\n/** Room between the columns - for the links, and the values of open inputs left of a block */\nconst GAP_X = 100;\nconst GAP_Y = 30;\nconst GRID = 10;\n/** Rounds from one side to the other and back */\nconst PASSES = 4;\n\ninterface Item {\n id: string;\n block: FbBlock;\n def: FbBlockDef | undefined;\n width: number;\n height: number;\n /** From the top of the block to the first pin */\n pinTop: number;\n}\n\n/** Blocks with a line under the type (state, value, pin, version) are that much higher */\nfunction pinTop(def: FbBlockDef | undefined, metrics: FbBlockMetrics): number {\n return metrics.header + (def?.user || def?.params?.length ? metrics.detail : 0);\n}\n\ninterface Cluster {\n ids: string[];\n wants: number[];\n heights: number[];\n top: number;\n}\n\n/** The top of a group of blocks that touch: the mean of what each of them wants */\nfunction settle(cluster: Cluster): void {\n let offset = 0;\n let sum = 0;\n cluster.ids.forEach((_id, i) => {\n sum += cluster.wants[i] - offset;\n offset += cluster.heights[i] + GAP_Y;\n });\n cluster.top = sum / cluster.ids.length;\n}\n\nfunction clusterHeight(cluster: Cluster): number {\n return cluster.heights.reduce((sum, height) => sum + height + GAP_Y, 0) - GAP_Y;\n}\n\n/**\n * New positions for the blocks of a diagram, by ID. The comments stay where they are; the top left\n * corner of the blocks stays where it was.\n */\nexport function layoutGraph(graph: FbGraph, options: FbLayoutOptions = {}): Record<string, [number, number]> {\n if (!graph.blocks.length) {\n return {};\n }\n const analysis = analyzeGraph(graph);\n const feedback = new Set(analysis.feedback);\n const links = analysis.links.filter(link => !feedback.has(link.id) && link.from[0] !== link.to[0]);\n\n const metrics = options.metrics || DEFAULT_METRICS;\n const PIN_HEIGHT = metrics.pin;\n const items = new Map<string, Item>();\n for (const block of graph.blocks) {\n const def = getBlockDef(block.type, graph.userBlocks);\n const rows = Math.max(getInputs(block, def).length, getOutputs(block, def).length, 1);\n const top = pinTop(def, metrics);\n const size = options.sizes?.[block.id];\n items.set(block.id, {\n id: block.id,\n block,\n def,\n width: size?.width || DEFAULT_WIDTH,\n height: size?.height || top + rows * PIN_HEIGHT + metrics.frame,\n pinTop: top,\n });\n }\n\n const incoming = new Map<string, FbLink[]>();\n const outgoing = new Map<string, FbLink[]>();\n for (const link of links) {\n incoming.set(link.to[0], [...(incoming.get(link.to[0]) || []), link]);\n outgoing.set(link.from[0], [...(outgoing.get(link.from[0]) || []), link]);\n }\n\n // the pins, from the top of their block\n const outputY = (link: FbLink): number => {\n const item = items.get(link.from[0])!;\n const index = getOutputs(item.block, item.def).findIndex(pin => pin.id === link.from[1]);\n return item.pinTop + Math.max(index, 0) * PIN_HEIGHT + PIN_HEIGHT / 2;\n };\n const inputY = (link: FbLink): number => {\n const item = items.get(link.to[0])!;\n const index = getInputs(item.block, item.def).findIndex(pin => pin.id === link.to[1]);\n return item.pinTop + Math.max(index, 0) * PIN_HEIGHT + PIN_HEIGHT / 2;\n };\n\n // Columns by the longest path. The execution order is a topological order of the links that do\n // not lead back; blocks that cannot run (an unknown type) come last.\n const sequence = graph.blocks\n .map(block => block.id)\n .sort((a, b) => (analysis.order[a] ?? Infinity) - (analysis.order[b] ?? Infinity));\n const column = new Map<string, number>();\n for (const id of sequence) {\n let index = 0;\n for (const link of incoming.get(id) || []) {\n index = Math.max(index, (column.get(link.from[0]) ?? 0) + 1);\n }\n column.set(id, index);\n }\n // a block that only gives a value, like CONST, goes next to where it is used\n for (const id of [...sequence].reverse()) {\n const type = items.get(id)!.block.type;\n const next = outgoing.get(id) || [];\n if (!incoming.get(id)?.length && next.length && type !== 'STATE_IN' && type !== 'FB_IN') {\n column.set(id, Math.max(0, Math.min(...next.map(link => column.get(link.to[0])!)) - 1));\n }\n }\n // the outputs of the diagram in the last column\n const last = Math.max(...column.values());\n for (const id of sequence) {\n const type = items.get(id)!.block.type;\n if ((type === 'STATE_OUT' || type === 'FB_OUT') && !outgoing.get(id)?.length) {\n column.set(id, last);\n }\n }\n\n // the columns, at first in the order the blocks have from top to bottom\n const columns: string[][] = Array.from({ length: last + 1 }, () => []);\n graph.blocks\n .slice()\n .sort((a, b) => a.pos[1] - b.pos[1] || a.pos[0] - b.pos[0])\n .forEach(block => columns[column.get(block.id)!].push(block.id));\n\n const y = new Map<string, number>();\n for (const ids of columns) {\n let top = 0;\n for (const id of ids) {\n y.set(id, top);\n top += items.get(id)!.height + GAP_Y;\n }\n }\n\n /**\n * Places the blocks of a column where they want to be, without overlaps: blocks that would\n * overlap form a group, which sits at the mean of what its blocks want.\n */\n const place = (ids: string[], want: (id: string) => number | null): void => {\n const wishes = ids\n .map((id, i) => ({ id, i, want: want(id) ?? y.get(id)! }))\n .sort((a, b) => a.want - b.want || a.i - b.i);\n const clusters: Cluster[] = [];\n for (const wish of wishes) {\n const cluster: Cluster = {\n ids: [wish.id],\n wants: [wish.want],\n heights: [items.get(wish.id)!.height],\n top: wish.want,\n };\n clusters.push(cluster);\n // merge with the groups above as long as they overlap\n while (clusters.length > 1) {\n const current = clusters[clusters.length - 1];\n const above = clusters[clusters.length - 2];\n if (above.top + clusterHeight(above) + GAP_Y <= current.top) {\n break;\n }\n above.ids.push(...current.ids);\n above.wants.push(...current.wants);\n above.heights.push(...current.heights);\n settle(above);\n clusters.pop();\n }\n }\n ids.length = 0;\n for (const cluster of clusters) {\n let top = cluster.top;\n cluster.ids.forEach((id, i) => {\n y.set(id, top);\n top += cluster.heights[i] + GAP_Y;\n ids.push(id);\n });\n }\n };\n\n const mean = (values: number[]): number | null =>\n values.length ? values.reduce((sum, value) => sum + value, 0) / values.length : null;\n // level with the outputs that feed it\n const fromLeft = (id: string): number | null =>\n mean((incoming.get(id) || []).map(link => y.get(link.from[0])! + outputY(link) - inputY(link)));\n // level with the inputs it feeds\n const fromRight = (id: string): number | null =>\n mean((outgoing.get(id) || []).map(link => y.get(link.to[0])! + inputY(link) - outputY(link)));\n\n for (let pass = 0; pass < PASSES; pass++) {\n for (let i = 1; i < columns.length; i++) {\n place(columns[i], fromLeft);\n }\n for (let i = columns.length - 2; i >= 0; i--) {\n place(columns[i], fromRight);\n }\n }\n // the last round from left to right: the links of a chain run straight\n for (let i = 1; i < columns.length; i++) {\n place(columns[i], fromLeft);\n }\n\n // the columns side by side, each as wide as its widest block\n const left = Math.min(...graph.blocks.map(block => block.pos[0]));\n const top = Math.min(...graph.blocks.map(block => block.pos[1]));\n const minY = Math.min(...y.values());\n const positions: Record<string, [number, number]> = {};\n let x = Math.round(left / GRID) * GRID;\n for (const ids of columns) {\n if (!ids.length) {\n continue;\n }\n for (const id of ids) {\n // not on the grid vertically: a link between pins at different heights would get a kink\n positions[id] = [x, Math.round(top + y.get(id)! - minY)];\n }\n x += Math.round((Math.max(...ids.map(id => items.get(id)!.width)) + GAP_X) / GRID) * GRID;\n }\n return positions;\n}\n"]}