jsgui3-server 0.0.121 → 0.0.123

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 (282) hide show
  1. package/.vscode/settings.json +6 -0
  2. package/README.md +10 -10
  3. package/controls/Active_HTML_Document.js +116 -116
  4. package/controls/README.md +7 -7
  5. package/controls/page/admin.js +74 -74
  6. package/controls/panel/admin.js +11 -11
  7. package/examples/_css/basic.css +913 -913
  8. package/examples/_css/database-control.css +51 -51
  9. package/examples/_css/jsgui.css +66 -66
  10. package/examples/_css/multi-layout.css +23 -23
  11. package/examples/_css/style.css +1669 -1669
  12. package/examples/_css/top-and-bottom-bars.css +54 -54
  13. package/examples/box/1) square box/client.js +188 -188
  14. package/examples/box/1) square box/server.js +112 -112
  15. package/examples/box/2) twenty square boxes/css flex wrap/client.js +112 -248
  16. package/examples/box/2) twenty square boxes/css flex wrap/server.js +39 -112
  17. package/examples/box/3) twenty selectable square boxes/css flex wrap/client.js +129 -0
  18. package/examples/{controls/15) window, text field → box/3) twenty selectable square boxes/css flex wrap}/server.js +38 -38
  19. package/examples/boxes/square_boxes.js +45 -48
  20. package/examples/boxes/square_boxes_client.js +132 -136
  21. package/examples/client-side-popup-menu-button.html +93 -93
  22. package/examples/color_palette.js +51 -51
  23. package/examples/color_palette_client.js +95 -95
  24. package/examples/controls/1) window/client.js +186 -186
  25. package/examples/controls/1) window/server.js +117 -117
  26. package/examples/controls/10) window, mirrored text inputs/client.js +118 -320
  27. package/examples/controls/10) window, mirrored text inputs/server.js +37 -117
  28. package/examples/controls/11) window, mirrored text fields/client.js +493 -251
  29. package/examples/controls/11) window, mirrored text fields/server.js +117 -117
  30. package/examples/controls/11b) window, shared Data_Object model mirrored text fields/client.js +613 -331
  31. package/examples/controls/11b) window, shared Data_Object model mirrored text fields/server.js +117 -117
  32. package/examples/controls/11c) window, shared Data_Value model mirrored text fields/client.js +617 -617
  33. package/examples/controls/11c) window, shared Data_Value model mirrored text fields/server.js +117 -117
  34. package/examples/controls/11d) window, shared model mirrored integer text fields/client.js +611 -280
  35. package/examples/controls/11d) window, shared model mirrored integer text fields/server.js +134 -22
  36. package/examples/controls/12) window, Select_Options control/client.js +66 -452
  37. package/examples/controls/12) window, Select_Options control/server.js +19 -117
  38. package/examples/controls/13) window, Dropdown_Menu control/client.js +66 -0
  39. package/examples/controls/13) window, Dropdown_Menu control/server.js +20 -0
  40. package/examples/controls/2) two windows/client.js +193 -193
  41. package/examples/controls/2) two windows/server.js +113 -113
  42. package/examples/controls/3) five windows/client.js +217 -217
  43. package/examples/controls/3) five windows/server.js +116 -115
  44. package/examples/controls/4) window, tabbed panel/client.js +54 -225
  45. package/examples/controls/4) window, tabbed panel/server.js +17 -117
  46. package/examples/controls/5) window, grid/client.js +204 -484
  47. package/examples/controls/5) window, grid/server.js +117 -119
  48. package/examples/controls/6) window, color_palette/client.js +68 -204
  49. package/examples/controls/6) window, color_palette/server.js +117 -117
  50. package/examples/controls/7) window, month_view/client.js +40 -231
  51. package/examples/controls/7) window, month_view/server.js +117 -117
  52. package/examples/controls/8) window, checkbox/client.js +33 -209
  53. package/examples/controls/8) window, checkbox/server.js +117 -117
  54. package/examples/controls/9) window, date picker/client.js +76 -303
  55. package/examples/controls/9) window, date picker/server.js +117 -117
  56. package/examples/controls/9b) window, shared data.model mirrored date pickers/README.md +51 -0
  57. package/examples/controls/9b) window, shared data.model mirrored date pickers/client.js +83 -398
  58. package/examples/controls/9b) window, shared data.model mirrored date pickers/server.js +117 -117
  59. package/examples/controls/__old/_html-server-color-palette.js +114 -114
  60. package/examples/controls/__old/html-server-combo-box.js +104 -104
  61. package/examples/controls/__old/html-server-list.js +98 -98
  62. package/examples/controls/__old/html-server-popup-menu-button.js +114 -114
  63. package/examples/controls/__old/html-server-start-stop-toggle-button.js +146 -146
  64. package/examples/controls/__old/scs-arrow-button.js +36 -36
  65. package/examples/controls/__old/scs-date-picker.js +157 -157
  66. package/examples/controls/__old/scs-file-browser.js +82 -82
  67. package/examples/controls/__old/scs-item.js +159 -159
  68. package/examples/controls/__old/scs-month-arrow-selector.js +126 -126
  69. package/examples/controls/__old/scs-month-view.js +94 -94
  70. package/examples/controls/__old/scs-start-stop-toggle-button.js +40 -40
  71. package/examples/controls/__old/scs-tree.js +49 -49
  72. package/examples/controls/__old/scs-year-arrow-selector.js +127 -127
  73. package/examples/demos/date-picker.js +119 -119
  74. package/examples/demos/explain-encapsulation.js +9 -9
  75. package/examples/demos/resizing.js +35 -35
  76. package/examples/demos/server_time.js +6 -6
  77. package/examples/grids/grid_1.js +45 -45
  78. package/examples/grids/grid_1_client.js +329 -329
  79. package/examples/html-rendering.js +20 -20
  80. package/examples/html-server.js +105 -105
  81. package/examples/introducing jsgui3/server.js +110 -110
  82. package/examples/mx_display/mx_display_1.js +45 -45
  83. package/examples/mx_display/mx_display_1_client.js +444 -444
  84. package/fs2.js +1836 -1836
  85. package/http/responders/HTTP_Responder.js +15 -15
  86. package/http/responders/static/Static_Route_HTTP_Responder.js +105 -105
  87. package/module.js +34 -34
  88. package/old/_single-control-server.js +418 -418
  89. package/old/single-control-server.js +368 -368
  90. package/old/single-page-app.js +131 -131
  91. package/package.json +42 -42
  92. package/page-context.js +92 -92
  93. package/publishers/helpers/assigners/Assigner.js +10 -10
  94. package/publishers/helpers/assigners/static-compressed-response-buffers/Single_Control_Webpage_Server_Static_Compressed_Response_Buffers_Assigner.js +150 -150
  95. package/publishers/helpers/assigners/static-headers/Single_Control_Webpage_Server_Static_Headers_Assigner.js +109 -109
  96. package/publishers/helpers/assigners/static-routes/Single_Control_Webpage_Server_Static_Routes_Assigner.js +91 -91
  97. package/publishers/helpers/assigners/static-uncompressed-response-buffers/Single_Control_Webpage_Server_Static_Uncompressed_Response_Buffers_Assigner.js +104 -104
  98. package/publishers/helpers/preparers/static/bundle/Ready_To_Serve_Preparer.js +18 -18
  99. package/publishers/helpers/preparers/static/bundle/Static_Routes_Responses_Webpage_Bundle_Preparer.js +44 -44
  100. package/publishers/http-function-publisher.js +212 -212
  101. package/publishers/http-html-page-publisher.js +5 -5
  102. package/publishers/http-html-publisher.js +24 -24
  103. package/publishers/http-js-publisher.js +135 -135
  104. package/publishers/http-observable-publisher.js +124 -124
  105. package/publishers/http-publisher.js +53 -53
  106. package/publishers/http-resource-publisher.js +325 -325
  107. package/publishers/http-webpage-publisher.js +659 -658
  108. package/publishers/http-webpageorsite-publisher.js +343 -343
  109. package/publishers/http-website-publisher.js +640 -640
  110. package/publishers/notes.md +9 -9
  111. package/resources/README.md +16 -16
  112. package/resources/_old_website-javascript-resource.js +994 -994
  113. package/resources/_old_website-resource.js +507 -507
  114. package/resources/compile/server-resource-compilation.js +43 -43
  115. package/resources/data-resource.js +118 -118
  116. package/resources/fs-resource.js +146 -146
  117. package/resources/jsbuilder/Abstract_Single_Declaration.js +105 -105
  118. package/resources/jsbuilder/Abstract_Single_Declaration_Sequence.js +42 -42
  119. package/resources/jsbuilder/JS_AST/JS_AST_Abstract_Node.js +61 -61
  120. package/resources/jsbuilder/JS_AST/JS_AST_Abstract_Node_Group.js +41 -41
  121. package/resources/jsbuilder/JS_AST/JS_AST_Group_Shared.js +61 -61
  122. package/resources/jsbuilder/JS_AST/JS_AST_Node.js +93 -93
  123. package/resources/jsbuilder/JS_AST/JS_AST_Node_0-Core.js +253 -253
  124. package/resources/jsbuilder/JS_AST/JS_AST_Node_1-Babel.js +337 -337
  125. package/resources/jsbuilder/JS_AST/JS_AST_Node_10-Changing.js +39 -39
  126. package/resources/jsbuilder/JS_AST/JS_AST_Node_2.1.1-Child.js +96 -96
  127. package/resources/jsbuilder/JS_AST/JS_AST_Node_2.1.2-Parent.js +37 -37
  128. package/resources/jsbuilder/JS_AST/JS_AST_Node_2.1.3-Ancestor.js +61 -61
  129. package/resources/jsbuilder/JS_AST/JS_AST_Node_2.2-Inner.js +43 -43
  130. package/resources/jsbuilder/JS_AST/JS_AST_Node_2.3-All.js +72 -72
  131. package/resources/jsbuilder/JS_AST/JS_AST_Node_2.4-Sibling.js +92 -92
  132. package/resources/jsbuilder/JS_AST/JS_AST_Node_2.5-Available_In_Scope.js +29 -29
  133. package/resources/jsbuilder/JS_AST/JS_AST_Node_2.9-Signature.js +116 -116
  134. package/resources/jsbuilder/JS_AST/JS_AST_Node_3-Basics.js +159 -159
  135. package/resources/jsbuilder/JS_AST/JS_AST_Node_3.0.0-Basics_First.js +178 -178
  136. package/resources/jsbuilder/JS_AST/JS_AST_Node_3.0.1-Basics_Second.js +87 -87
  137. package/resources/jsbuilder/JS_AST/JS_AST_Node_3.0.99-Basics_Last.js +91 -91
  138. package/resources/jsbuilder/JS_AST/JS_AST_Node_3.1-Basics_Each.js +136 -136
  139. package/resources/jsbuilder/JS_AST/JS_AST_Node_3.1.5-Basics_Count.js +73 -73
  140. package/resources/jsbuilder/JS_AST/JS_AST_Node_3.2-Basics_Filter.js +39 -39
  141. package/resources/jsbuilder/JS_AST/JS_AST_Node_3.3-Basics_Collect.js +85 -85
  142. package/resources/jsbuilder/JS_AST/JS_AST_Node_3.4-Basics_Select.js +42 -42
  143. package/resources/jsbuilder/JS_AST/JS_AST_Node_3.5-Basics_Find.js +40 -40
  144. package/resources/jsbuilder/JS_AST/JS_AST_Node_3.6-Basics_Callmap.js +54 -54
  145. package/resources/jsbuilder/JS_AST/JS_AST_Node_4.0-Index_Indexes.js +45 -45
  146. package/resources/jsbuilder/JS_AST/JS_AST_Node_4.1-Index.js +343 -343
  147. package/resources/jsbuilder/JS_AST/JS_AST_Node_5.0-Category.js +38 -38
  148. package/resources/jsbuilder/JS_AST/JS_AST_Node_5.1-Category_Identifier.js +30 -30
  149. package/resources/jsbuilder/JS_AST/JS_AST_Node_5.2-Category_Literal.js +28 -28
  150. package/resources/jsbuilder/JS_AST/JS_AST_Node_5.3-Category_Expression.js +26 -26
  151. package/resources/jsbuilder/JS_AST/JS_AST_Node_5.4-Category_Pattern.js +8 -8
  152. package/resources/jsbuilder/JS_AST/JS_AST_Node_5.5-Category_Declaration.js +43 -43
  153. package/resources/jsbuilder/JS_AST/JS_AST_Node_5.6-Category_Statement.js +21 -21
  154. package/resources/jsbuilder/JS_AST/JS_AST_Node_6.0-Type.js +89 -89
  155. package/resources/jsbuilder/JS_AST/JS_AST_Node_6.1-Type_Class_Declaration.js +8 -8
  156. package/resources/jsbuilder/JS_AST/JS_AST_Node_6.2-Type_Variable_Declaration.js +27 -27
  157. package/resources/jsbuilder/JS_AST/JS_AST_Node_6.3-Type_Variable_Declarator.js +28 -28
  158. package/resources/jsbuilder/JS_AST/JS_AST_Node_7-Query.js +736 -736
  159. package/resources/jsbuilder/JS_AST/JS_AST_Node_8-Features.js +64 -64
  160. package/resources/jsbuilder/JS_AST/JS_AST_Node_9-Planning.js +31 -31
  161. package/resources/jsbuilder/JS_AST/JS_AST_Node_Arrangement.js +15 -15
  162. package/resources/jsbuilder/JS_AST/JS_AST_Node_Feature/JS_AST_Node_Declared_Object.js +305 -305
  163. package/resources/jsbuilder/JS_AST/JS_AST_Node_Feature/JS_AST_Node_Feature.js +77 -77
  164. package/resources/jsbuilder/JS_AST/JS_AST_Node_Feature/JS_AST_Node_Feature_Declaration.js +248 -248
  165. package/resources/jsbuilder/JS_AST/JS_AST_Node_Feature/JS_AST_Node_Feature_Declarator.js +138 -138
  166. package/resources/jsbuilder/JS_AST/JS_AST_Node_Feature/JS_AST_Root_Node_Feature/JS_AST_Root_Node_Feature.js +10 -10
  167. package/resources/jsbuilder/JS_AST/JS_AST_Node_Feature/JS_AST_Root_Node_Feature/JS_AST_Root_Node_Feature_Exported.js +100 -100
  168. package/resources/jsbuilder/JS_AST/JS_AST_Node_Feature/JS_AST_Root_Node_Feature/JS_AST_Root_Node_Feature_Exports.js +60 -60
  169. package/resources/jsbuilder/JS_AST/JS_AST_Node_Feature/JS_AST_Root_Node_Feature/JS_AST_Root_Node_Interpreted.js +179 -179
  170. package/resources/jsbuilder/JS_AST/JS_AST_Node_Feature/JS_AST_Root_Node_Feature/_JSGUI_Root_Node_Interpreted.js +43 -43
  171. package/resources/jsbuilder/JS_AST/JS_AST_Node_Feature/JS_AST_Root_Node_Feature/special_case_objectassign_to_object.js +12 -12
  172. package/resources/jsbuilder/JS_AST/JS_AST_Node_Group.js +35 -35
  173. package/resources/jsbuilder/JS_AST/JS_AST_Operation.js +11 -11
  174. package/resources/jsbuilder/JS_AST/JS_AST_Operation_On_Relationship.js +31 -31
  175. package/resources/jsbuilder/JS_AST/JS_AST_Ordered_Relationship_Node_To_Group.js +37 -37
  176. package/resources/jsbuilder/JS_AST/JS_AST_Ordinal.js +39 -39
  177. package/resources/jsbuilder/JS_AST/JS_AST_Ordinal_Relationship.js +25 -25
  178. package/resources/jsbuilder/JS_AST/JS_AST_Relationship_Node_To_Group.js +200 -200
  179. package/resources/jsbuilder/JS_AST/JS_AST_Relationship_Node_Within_Group_To_Node.js +43 -43
  180. package/resources/jsbuilder/JS_AST/_JS_AST_Node_3.8-Query_Features.js +76 -76
  181. package/resources/jsbuilder/JS_AST/query/enable_array_as_queryable.js +227 -227
  182. package/resources/jsbuilder/JS_AST/query/find_object_keys.js +404 -404
  183. package/resources/jsbuilder/JS_AST/query/node_queries.js +8 -8
  184. package/resources/jsbuilder/JS_AST/query/root_query_identidy.js +11 -11
  185. package/resources/jsbuilder/JS_AST_Node_Extended/JSGUI_Singular_Declaration.js +85 -85
  186. package/resources/jsbuilder/JS_AST_Node_Extended/JS_AST_Node_Declaration.js +123 -123
  187. package/resources/jsbuilder/JS_AST_Node_Extended/JS_AST_Node_Extended.js +87 -87
  188. package/resources/jsbuilder/JS_AST_Node_Extended/JS_AST_Node_Extended_0-Core.js +10 -10
  189. package/resources/jsbuilder/JS_Builder.js +10 -10
  190. package/resources/jsbuilder/JS_File/Feature/JS_File_Declared_Object.js +31 -31
  191. package/resources/jsbuilder/JS_File/Feature/JS_File_Exported_Object_Info.js +25 -25
  192. package/resources/jsbuilder/JS_File/Feature/JS_File_Exports.js +78 -78
  193. package/resources/jsbuilder/JS_File/Feature/JS_File_Feature.js +17 -17
  194. package/resources/jsbuilder/JS_File/Feature/JS_File_Imported_Object_Info.js +25 -25
  195. package/resources/jsbuilder/JS_File/Feature/JS_File_Imports.js +8 -8
  196. package/resources/jsbuilder/JS_File/JS_File.js +12 -12
  197. package/resources/jsbuilder/JS_File/JS_File_0-Core.js +202 -202
  198. package/resources/jsbuilder/JS_File/JS_File_1-Early_Parse.js +175 -175
  199. package/resources/jsbuilder/JS_File/JS_File_2-Babel.js +81 -81
  200. package/resources/jsbuilder/JS_File/JS_File_3-JS_AST_Node.js +86 -86
  201. package/resources/jsbuilder/JS_File/JS_File_4-Query.js +413 -413
  202. package/resources/jsbuilder/JS_File/JS_File_4.1-Query_Features.js +414 -414
  203. package/resources/jsbuilder/JS_File/JS_File_5-Planning.js +59 -59
  204. package/resources/jsbuilder/JS_File/JS_File_6-Changing.js +24 -24
  205. package/resources/jsbuilder/JS_File/JS_File_Export_Reference.js +12 -12
  206. package/resources/jsbuilder/JS_File/JS_File_Import_Reference.js +23 -23
  207. package/resources/jsbuilder/JS_File/JS_File_Import_References.js +31 -31
  208. package/resources/jsbuilder/JS_File/JS_File_Processor.js +16 -16
  209. package/resources/jsbuilder/JS_File/JS_Files.js +15 -15
  210. package/resources/jsbuilder/Module.js +14 -14
  211. package/resources/jsbuilder/Platform.js +13 -13
  212. package/resources/jsbuilder/Platforms.js +69 -69
  213. package/resources/jsbuilder/Project.js +109 -109
  214. package/resources/jsbuilder/Reference.js +1 -1
  215. package/resources/jsbuilder/Reference_Sequence.js +16 -16
  216. package/resources/jsbuilder/Scope.js +29 -29
  217. package/resources/jsbuilder/Variable_Name_Provider.js +42 -42
  218. package/resources/jsbuilder/_JS_File.js +225 -225
  219. package/resources/jsbuilder/ast_query.js +20 -20
  220. package/resources/jsbuilder/babel/babel_consts.js +162 -162
  221. package/resources/jsbuilder/babel/babel_node_tools.js +541 -541
  222. package/resources/jsbuilder/babel/deep_iterate/deep_iterate_babel.js +923 -904
  223. package/resources/jsbuilder/build.js +16 -16
  224. package/resources/jsbuilder/platform_notes.md +66 -66
  225. package/resources/jsbuilder/test/test_ast_node.js +381 -381
  226. package/resources/jsbuilder/test/test_js_file.js +303 -303
  227. package/resources/jsbuilder/test/test_project.js +157 -157
  228. package/resources/local-server-info-resource.js +96 -96
  229. package/resources/notes.txt +10 -10
  230. package/resources/old/website-image-resource.js +1185 -1185
  231. package/resources/process-js.js +498 -498
  232. package/resources/processors/bundlers/bundle.js +29 -29
  233. package/resources/processors/bundlers/bundler.js +23 -23
  234. package/resources/processors/bundlers/css-bundler.js +234 -234
  235. package/resources/processors/bundlers/js/JS_Bundler.js +51 -51
  236. package/resources/processors/bundlers/js/esbuild/Advanced_JS_Bundler_Using_ESBuild.js +388 -391
  237. package/resources/processors/bundlers/js/esbuild/Bundler_Using_ESBuild.js +8 -8
  238. package/resources/processors/bundlers/js/esbuild/Core_JS_Non_Minifying_Bundler_Using_ESBuild.js +188 -188
  239. package/resources/processors/bundlers/js/esbuild/Core_JS_Single_File_Minifying_Bundler_Using_ESBuild.js +191 -192
  240. package/resources/processors/bundlers/js/esbuild/_Old_CSS_Extractor.js +239 -239
  241. package/resources/processors/bundlers/js-bundler.js +263 -263
  242. package/resources/processors/bundlers/test_ast.js +73 -73
  243. package/resources/processors/bundlers/webpage-bundler.js +404 -404
  244. package/resources/processors/bundlers/website-bundler.js +22 -22
  245. package/resources/processors/extractors/Extractor.js +9 -11
  246. package/resources/processors/extractors/js/css_and_js/AST_Node/CSS_And_JS_From_JS_String_Using_AST_Node_Extractor.js +239 -254
  247. package/resources/processors/extractors/js/css_and_js/CSS_And_JS_From_JS_String_Extractor.js +3 -3
  248. package/resources/processors/extractors/string/Pos_Span_String_Extractor.js +93 -93
  249. package/resources/server-installed-tools.js +28 -28
  250. package/resources/server-resource-pool.js +41 -41
  251. package/resources/website-audio-resource.js +735 -735
  252. package/resources/website-css-resource.js +411 -411
  253. package/resources/website-image-resource.js +412 -412
  254. package/resources/website-javascript-resource-processor.js +908 -908
  255. package/resources/website-javascript-resource.js +874 -874
  256. package/resources/website-resource-processor.js +10 -10
  257. package/resources/website-resource.js +164 -164
  258. package/resources/website-static-html-resource.js +199 -199
  259. package/resources/website-template-html-resource.js +231 -231
  260. package/roadmap.md +75 -75
  261. package/server.js +609 -573
  262. package/static-page-context.js +13 -13
  263. package/website/webpage.js +81 -81
  264. package/website/website-group.js +15 -15
  265. package/website/website.js +260 -260
  266. package/examples/controls/11d) window, shared model mirrored integer text fields/both.js +0 -17
  267. package/examples/controls/13) window, shared model mirrored lat_long/client.js +0 -933
  268. package/examples/controls/13) window, shared model mirrored lat_long/server.js +0 -50
  269. package/examples/controls/14) window, control compositional model/client.js +0 -328
  270. package/examples/controls/14) window, control compositional model/server.js +0 -118
  271. package/examples/controls/14a) window, control spec has compositional model/client.js +0 -440
  272. package/examples/controls/14a) window, control spec has compositional model/server.js +0 -118
  273. package/examples/controls/15) window, text field/client.js +0 -256
  274. package/examples/controls/16) Window([Text_Input])/client.js +0 -266
  275. package/examples/controls/16) Window([Text_Input])/server.js +0 -109
  276. package/examples/controls/16a) Window([Text_Input]) Integer data.model.data_type/client.js +0 -494
  277. package/examples/controls/16a) Window([Text_Input]) Integer data.model.data_type/isomorphic.js +0 -24
  278. package/examples/controls/16a) Window([Text_Input]) Integer data.model.data_type/server.js +0 -73
  279. package/examples/controls/2b) two window, context menus/client.js +0 -193
  280. package/examples/controls/2b) two window, context menus/server.js +0 -114
  281. package/examples/controls/4a) window, tabbed panel with various controls inside/client.js +0 -233
  282. package/examples/controls/4a) window, tabbed panel with various controls inside/server.js +0 -118
@@ -1,995 +1,995 @@
1
- // Sep 2023:
2
- // This Resource itself is huge in scope, but maybe would be better to make the Resource more in terms of representing the Resource itself
3
- // and having things like Resource_Processor? Resource_Analyser? Resource_Miner? Resource_Extracter? Resource_Transformer?
4
- // Resource_Bundler? Resource_Builder?
5
-
6
- // Resource_Verb_Carryouter Resource_Processor seems like the general name. Could do analysis, building, extraction etc.
7
- // Raising events / announcements when it finds things.
8
-
9
- // Does seem like refactoring the Resource so it is much simpler will be worth it, but also going into detail on the
10
- // different ways the resources can be processed, doing it in a polymorphic way, observables, promises, making more classes for it if needed.
11
-
12
- // Maybe do want the classes with processing functions built-in?
13
- // Changing the syntax to more explictly use various files and classes which will be interchangable and separately upgradable
14
- // and testable will help.
15
-
16
- // Need to refactor, this code no longer works as first intended, and was slow when it did its full thing.
17
- // Can do things much more optimially, maybe with esbuild and hashing and caching.
18
-
19
-
20
-
21
-
22
-
23
-
24
-
25
-
26
-
27
- // Nov 2020:
28
- // Need to overhaul this, bugs are on the client, need to be careful and clear about what will be sent to the client.
29
- // Need to get more into the tools for building JS for the client. Can I do the outline / much of the outline of it myself?
30
- // Build up a huge JS AST of the whole thing.
31
- // Build up a system that understands what code does (to an extent) and how it fits together.
32
-
33
- // Could do my own application-level compression.
34
-
35
- // JS-Build.
36
- // Could identify the resources / files used in the site?
37
-
38
- // Load all the files in, made into a function that will return what the module exports.
39
- // Or not...
40
- // Make the module into just the code, store it as a variable, then be able to build
41
-
42
- // Would make quite a difference - with a lot of localised references made possible.
43
- //
44
-
45
-
46
- // JS_File
47
- // Be able to get transformed versions of it
48
- // JS_File_
49
-
50
-
51
- // Much of this could be better expressed as a Compiler_Resource.
52
-
53
-
54
- // Plan: Do more of this through lower level compilation features.
55
- // Accessing a compilation resource makes sense structurally.
56
-
57
- // May want a server to create and test compilation resources / compilers.
58
-
59
- // Compilers, Bundlers, HTTP Request Handlers - Somewhat lower level, ie tools to get things done.
60
- // Then also: resources which make use of upgraded and new lower level components.
61
-
62
- // Server_Resource could help?
63
-
64
- // Late 2023 - Should keep most of this for the moment, see about using parts when / where needed, also add in other (maybe simpler)
65
- // ways to do things that are needed to publish JS.
66
-
67
- // This resource seems like it's responsible for building JS.
68
- // Seems like a piece of 'server' functionality that will be kind of hidden, need to make sure it's not a leaky abstraction.
69
- // Also worth considering 'shorthands' where specific pieces of functionality are not needed to be specified, but usually we
70
- // need to tell it that it needs to compile the JS (and other things).
71
-
72
- // Maybe this JS resource would be responsible for extracting the CSS from JS and providing it to the CSS resource.
73
- // Would be best to work through getting a few examples, and implementations of simple apps with nice (maybe new) APIs that need
74
- // to be supported by jsgui3.
75
-
76
- // For the moment, don't make anything really complex when it's not needed, but make it so on the lower levels (incl mid)
77
- // it accesses functionality that is structured in a somewhat complex way, but uses it to do things which by default make the whole
78
- // process simple.
79
-
80
- // This runs automatically I think.
81
- // Probably need to get it automatically building the client js on server start if needed.
82
- // Likely best to save it locally, as well as to make a hash of all the files that went into the build, save that, only
83
- // rebuild when it has changed.
84
-
85
- // Could even provide a list of the intial control jsgui IDs, some empty items in an array? or the index of the node in the doc
86
- // and then the control id that will be applied.
87
- // This could make cleaner HTML be served by default, with IDs added later on the client-side using possibly a small amount of
88
- // supplementary info.
89
- // Or the ids could be assigned using xpaths.
90
-
91
-
92
-
93
-
94
-
95
-
96
-
97
-
98
-
99
-
100
-
101
- const path = require('path'),
102
- fs = require('fs'),
103
- url = require('url'),
104
- jsgui = require('jsgui3-html'),
105
- os = require('os'),
106
- http = require('http'),
107
- libUrl = require('url'),
108
- Resource = jsgui.Resource,
109
- fs2 = require('../fs2'),
110
- //brotli = require('iltorb').compress,
111
- //UglifyJS = require('uglify-js'),
112
- zlib = require('zlib');
113
-
114
- //fs.createReadStream(filename).pipe(brotli()).pipe(res);
115
-
116
- const fnl = require('fnl');
117
- const prom_or_cb = fnl.prom_or_cb;
118
- const fnlfs = require('fnlfs');
119
-
120
- const each = jsgui.each,
121
- arrayify = jsgui.arrayify,
122
- tof = jsgui.tof;
123
- const filter_map_by_regex = jsgui.filter_map_by_regex;
124
- const Class = jsgui.Class,
125
- Data_Object = jsgui.Data_Object,
126
- Enhanced_Data_Object = jsgui.Enhanced_Data_Object;
127
- const fp = jsgui.fp,
128
- is_defined = jsgui.is_defined;
129
- const Collection = jsgui.Collection;
130
- const call_multi = jsgui.call_multi,
131
- get_truth_map_from_arr = jsgui.get_truth_map_from_arr;
132
-
133
-
134
- //var zlib = require('zlib');
135
- const util = require('util');
136
-
137
- const browserify = require('browserify');
138
- const babel = require('@babel/core');
139
-
140
- // Extends AutoStart_Resource?
141
- const stream_to_array = require('stream-to-array');
142
-
143
-
144
- const process_js = require('./process-js');
145
- const {analyse_js_doc_formatting, extract_client_js} = process_js;
146
-
147
-
148
- var serve_js_file_from_disk_updated_refs = function (filePath, response, callback) {
149
- fs2.load_file_as_string(filePath, function (err, data) {
150
- if (err) {
151
- throw err;
152
- } else {
153
- //console.log('');
154
- //console.log('serve_js_file_from_disk_updated_refs filePath ' + filePath);
155
- //console.log('data ' + data);
156
- //var servableJs = updateReferencesForServing(data);
157
- response.writeHead(200, {
158
- 'Content-Type': 'text/javascript'
159
- });
160
- //response.end(servableJs);
161
- response.end(data);
162
- }
163
- });
164
- }
165
-
166
- var check_served_directories_for_requested_file = function (arr_served_paths, split_path_within_js, callback) {
167
-
168
- var fns = [
169
-
170
- ]
171
- var checkPath = function (path, callback) {
172
- // check to see if an existing file matches up with the path that is requested.
173
- // so, from that path, we use the split_path_within_js for the rest of the file path.
174
- // then we check if such a (JS) file exists.
175
- }
176
- // fns.push([fs2.load_file_as_string, [source_path_item], function(err, res_loaded) {
177
-
178
- // Not so sure I can use the exists function like this...
179
- var reconstitutedPathWithinJs = split_path_within_js.join('/');
180
- var firstFoundPath;
181
- each(arr_served_paths, function (i, fsPath) {
182
- fns.push([function (callback) {
183
- var checkingPath = fsPath + '/' + reconstitutedPathWithinJs;
184
- fs.exists(checkingPath, function (exists) {
185
- //console.log('cb fsPath ' + checkingPath + ' exists ' + exists)
186
- if (exists & !firstFoundPath) {
187
- firstFoundPath = checkingPath;
188
- }
189
- callback(null, exists);
190
- })
191
- },
192
- []
193
- ]);
194
- });
195
- call_multi(fns, function (err, res_multi) {
196
- if (err) {
197
- console.log('err ' + err);
198
- throw 'stop';
199
- } else {
200
- //console.log('res_multi ' + stringify(res_multi));
201
- //throw 'stop';
202
-
203
- if (firstFoundPath) {
204
- callback(null, firstFoundPath);
205
- } else {
206
- callback(null, null);
207
- }
208
- }
209
- });
210
- }
211
-
212
- // A way of serving a file so that it includes custom code.
213
- // Or have a standard client template that is easy to serve.
214
-
215
- // Maybe do more with custom controls, such as custom page controls.
216
- // Those page controls would know which control types are within them.
217
- // That info could then be used to write JS code that sets up the references on the client.
218
-
219
- // Possibly this should have its own routing tree to connect paths with js files?
220
- // Need to set up custom paths.
221
-
222
- class Site_JavaScript extends Resource {
223
- //'fields': {
224
- // 'custom_paths': 'data_object'
225
- //},
226
- constructor(spec) {
227
- super(spec);
228
- //this.meta.set('custom_paths', new Data_Object({}));
229
- //this.custom_paths = new Data_Object({});
230
- // Those are custom file paths.
231
- // could have a collection of directories, indexed by name, that get served.
232
- // Index the collection by string value?
233
- //this.meta.set('served_directories', new Collection({'index_by': 'name'}));
234
-
235
- // But this could be held (only) in the router.
236
- this.served_directories = new Collection({
237
- 'index_by': 'name'
238
- });
239
- }
240
- 'start'(callback) {
241
- //console.log('Site_JavaScript start');
242
- const build_on_start = this.build_on_start;
243
- if (build_on_start) {
244
- this.build_client(function (err, res_build) {
245
- if (err) {
246
- callback(err)
247
- } else {
248
- callback(null, true);
249
- }
250
- })
251
- } else {
252
- callback(null, true);
253
- }
254
- // Let's have it build the client-side code.
255
- // Need the options to ignore various files, as well as to include the source maps in the output.
256
- }
257
- // build client, and serve it from one particular place
258
- // do so with a promise.
259
- // serve_package
260
- // Need to bundle / build together a package from the disk path, then serve it under a URL route.
261
-
262
- // want to give it the file to build.
263
- // There will be a variety of jsgui packages.
264
-
265
-
266
- // Will be better as a promise.
267
-
268
- 'build_client'(callback) {
269
-
270
- // Configurable building mechanisms....
271
- // Want to provide jsgui events / logs on the build process.
272
-
273
- // jsgui.notify could be used for some kinds of internal event logging.
274
- // a specific type of event system.
275
-
276
- // jsgui.raise('notification', )
277
-
278
- // .note may be faster.
279
-
280
-
281
-
282
-
283
- // jsgui.notify('start', 'build_client');
284
-
285
-
286
- // Need the reference relative to the application directory.
287
- //var path = __dirname + '/js/app.js';
288
-
289
- // Can we stream it to a buffer in memory instead?
290
-
291
- // Using a compilation resource may be better long-term.
292
- // Creating and using a relevant abstraction.
293
-
294
- // The server should have already loaded (a few) compilers.
295
-
296
-
297
- var appDir = path.dirname(require.main.filename);
298
-
299
-
300
-
301
-
302
- //console.log('appDir', appDir);
303
- var app_path = appDir + '/js/app.js';
304
- var app_bundle_path = appDir + '/js/app-bundle.js';
305
- var wstream = fs.createWriteStream(app_bundle_path);
306
- var b = browserify();
307
- //b.require(app_path, {
308
- // entry: true,
309
- // debug: true
310
- //});
311
- b.add(app_path);
312
- //console.log('app_path', app_path);
313
- //console.log('pre browserify bundle');
314
- //b.bundle().pipe(process.stdout);
315
-
316
- b.bundle().pipe(wstream);
317
-
318
- wstream.end = function (data) {
319
- //console.log('file bundle write complete');
320
- callback(null, app_bundle_path);
321
- // no more writes after end
322
- // emit "close" (optional)
323
- }
324
- }
325
- // Will could serve all jsgui code?
326
- // May be better not to allow server-side code to be read on the client.
327
- // Could have specific directories within jsgui that get served to the client.
328
-
329
-
330
- // May be best thinking of bundling up one or more objects / files ready for the server to serve.
331
-
332
-
333
- 'serve_directory'(path) {
334
- // Serves that directory, as any files given in that directory can be served from /js
335
-
336
- // Perhaps just using the router would be better.
337
-
338
- var served_directories = this.served_directories;
339
- //console.log('served_directories ' + stringify(served_directories));
340
- //served_directories.push(path);
341
- served_directories.push({
342
- 'name': path
343
- });
344
- //console.log('served_directories ' + stringify(served_directories));
345
- //console.log('path ' + path);
346
- //throw 'stop';
347
- }
348
- 'serve_package'(url, js_package, options = {}, callback) {
349
- //console.log('serve_package', url, js_package);
350
- //console.log('js_package', js_package);
351
- //console.log('typeof js_package', typeof js_package);
352
- //let tjp = typeof js_package;
353
- return this.serve_package_from_path(url, require.resolve(js_package), options, callback);
354
- }
355
-
356
- // Possibly some functionality would be better within the js bundler.
357
-
358
-
359
-
360
- 'package'(js_file_path, options = {}, callback) {
361
-
362
- let a = arguments;
363
- if (typeof a[2] === 'function') {
364
- callback = a[2];
365
- options = {
366
- //'babel': 'mini',
367
- 'include_sourcemaps': true
368
- };
369
- }
370
-
371
- return prom_or_cb((resolve, reject) => {
372
- (async () => {
373
- // options
374
- // may want a replacement within the client-side code.
375
- // Can we call browserify on the code string?
376
- // Creating a modified copy of the file would do.
377
- // Load the file, modify it, save it under a different name
378
-
379
- let s = new require('stream').Readable(),
380
- path = require('path').parse(js_file_path);
381
-
382
- let fileContents = await fnlfs.load(js_file_path);
383
- //console.log('1) fileContents.length', fileContents.length);
384
- // are there any replacements to do?
385
- // options.replacements
386
-
387
- if (options.js_mode === 'debug') {
388
- options.include_sourcemaps = true;
389
- }
390
- if (options.js_mode === 'compress' || options.js_mode === 'mini') {
391
- options.include_sourcemaps = false;
392
- options.babel = 'mini';
393
- }
394
-
395
- //console.log('options.babel', options.babel);
396
-
397
- if (options.replace) {
398
- let s_file_contents = fileContents.toString();
399
- //console.log('s_file_contents', s_file_contents);
400
- each(options.replace, (text, key) => {
401
- //console.log('key', key);
402
- //console.log('text', text);
403
- let running_fn = '(' + text + ')();'
404
- //console.log('running_fn', running_fn);
405
- s_file_contents = s_file_contents.split(key).join(running_fn);
406
- })
407
- fileContents = Buffer.from(s_file_contents);
408
- //console.log('2) fileContents.length', fileContents.length);
409
- }
410
- // Then we can replace some of the file contents with specific content given when we tall it to serve that file.
411
- // We have a space for client-side activation.
412
- s.push(fileContents);
413
- s.push(null);
414
-
415
- //let include_sourcemaps = true;
416
-
417
- let b = browserify(s, {
418
- basedir: path.dir,
419
- //builtins: false,
420
- builtins: ['buffer', 'process'],
421
- 'debug': options.include_sourcemaps
422
- });
423
-
424
- let parts = await stream_to_array(b.bundle());
425
-
426
- const buffers = parts
427
- .map(part => util.isBuffer(part) ? part : Buffer.from(part));
428
- let buf_js = Buffer.concat(buffers);
429
- let str_js = buf_js.toString();
430
-
431
- let babel_option = options.babel
432
- //console.log('babel_option', babel_option);
433
- if (babel_option === 'es5') {
434
-
435
- let o_transform = {
436
- "presets": [
437
- "es2015",
438
- "es2017"
439
- ],
440
- "plugins": [
441
- "transform-runtime"
442
- ] //,
443
- //'sourceMaps': 'inline'
444
- };
445
-
446
- if (options.include_sourcemaps) o_transform.sourceMaps = 'inline';
447
- let res_transform = babel.transform(str_js, o_transform);
448
- //console.log('res_transform', res_transform);
449
- //console.log('Object.keys(res_transform)', Object.keys(res_transform));
450
- let jst_es5 = res_transform.code;
451
- //let {jst_es5, map, ast} = babel.transform(str_js);
452
- //console.log('jst_es5.length', jst_es5.length);
453
- buf_js = Buffer.from(jst_es5);
454
- } else if (babel_option === 'mini') {
455
- /*
456
- let o_transform = {
457
- presets: ["minify"]//,
458
- //'sourceMaps': 'inline'
459
- };
460
- */
461
- let o_transform = {
462
- "presets": [
463
- ["minify", {
464
- //"mangle": {
465
- //"exclude": ["MyCustomError"]
466
- //},
467
- //"unsafe": {
468
- // "typeConstructors": false
469
- //},
470
- //"keepFnName": true
471
- }]
472
- ],
473
- //plugins: ["minify-dead-code-elimination"]
474
- };
475
- if (options.include_sourcemaps) o_transform.sourceMaps = 'inline';
476
-
477
- let res_transform = babel.transform(str_js, o_transform);
478
- buf_js = Buffer.from(res_transform.code);
479
- } else {
480
- buf_js = Buffer.from(str_js);
481
- }
482
- resolve(buf_js);
483
- })();
484
- }, callback);
485
- }
486
-
487
- // This is a lot about creating some 'package' that includes built JS and CSS
488
-
489
- // It is not so clear what 'serve' means here though.
490
- // Perhaps using this functionality could take a few more function calls that are more explicit,
491
- // but also be set up so that it happens by default when appropriate, or some other function
492
- // that uses some of the same newly refactored / referenced functions will do the job.
493
-
494
- // Being more explicit about making sure the server has access to:
495
- // 1) The client side JS
496
- // 2) The means to build the client side JS
497
- // 3) Analysis of the client-side JS source file / files
498
- // If they contain CSS, that extracted CSS, as a CSS file.
499
- // Probably best to make a callback saying that it's got it?
500
- // An 'announcement'? New 'announcement' mechanism, so that when the CSS has been found the CSS publisher hears the announcement.
501
- // Means the JS resource or publisher does not need a direct reference to the CSS resource or publisher.
502
-
503
- // Also, make use of the distinction between a Resource and a Publisher.
504
- // A Resource is something like a file on the disk.
505
- // The Resources get provided to the Publishers.
506
- // Then do the Publishers create Resources? Publications? Published_Resources?
507
-
508
-
509
-
510
-
511
-
512
-
513
-
514
-
515
-
516
- // 3) The built client-side JS (with or without sourcemaps)
517
- // 4) The compression setting (brotli/gzip) to compress that client-side JS
518
-
519
-
520
-
521
-
522
- 'serve_package_from_path'(url, js_file_path, options = {}, callback) {
523
- //console.log('serve_package_from_path', url, js_file_path);
524
- // js_mode option may need to be used.
525
-
526
-
527
- // Make it an observable?
528
- // Raise an event when we have the browserified fill js file (uncompressed?).
529
-
530
-
531
- let a = arguments;
532
- if (typeof a[2] === 'function') {
533
- callback = a[2];
534
- options = {
535
- //'babel': 'mini',
536
- 'include_sourcemaps': false
537
- };
538
- }
539
- let serve_raw = options.serve_raw || options.raw;
540
- let accepts_brotli = false;
541
-
542
- // Need to come up with compressed versions.
543
- // An object that provides different versions.
544
-
545
-
546
- return prom_or_cb((resolve, reject) => {
547
- (async () => {
548
- // options
549
- // may want a replacement within the client-side code.
550
- // Can we call browserify on the code string?
551
- // Creating a modified copy of the file would do.
552
- // Load the file, modify it, save it under a different name
553
- const Stream = require('stream');
554
-
555
- let s = new Stream.Readable(),
556
- path = require('path').parse(js_file_path);
557
-
558
- let fileContents = await fnlfs.load(js_file_path);
559
- //console.log('1) fileContents.length', fileContents.length);
560
- // are there any replacements to do?
561
- // options.replacements
562
- if (options.js_mode === 'debug') {
563
- options.include_sourcemaps = true;
564
- }
565
- if (options.js_mode === 'compress' || options.js_mode === 'mini') {
566
- options.include_sourcemaps = false;
567
- options.babel = 'mini';
568
- }
569
- //console.log('options.babel', options.babel);
570
-
571
- // Likely to remove this....
572
- if (options.replace) {
573
- let s_file_contents = fileContents.toString();
574
- //console.log('s_file_contents', s_file_contents);
575
- each(options.replace, (text, key) => {
576
- //console.log('key', key);
577
- //console.log('text', text);
578
- const running_fn = '(' + text + ')();'
579
- //console.log('running_fn', running_fn);
580
- s_file_contents = s_file_contents.split(key).join(running_fn);
581
- })
582
- fileContents = Buffer.from(s_file_contents);
583
- //console.log('2) fileContents.length', fileContents.length);
584
- }
585
-
586
- // Then we can replace some of the file contents with specific content given when we tall it to serve that file.
587
- // We have a space for client-side activation.
588
- // want a raw option with no browserify.
589
- //console.log('serve_raw', serve_raw);
590
- if (serve_raw) {
591
- const escaped_url = url.replace(/\./g, '☺');
592
- //this.custom_paths.set(escaped_url, fileContents);
593
-
594
- throw 'NYI';
595
- } else {
596
- const formatting_info = analyse_js_doc_formatting(fileContents.toString());
597
- //console.log('formatting_info', formatting_info);
598
-
599
- const {arr_lines, line_break, indentation_analysis} = formatting_info;
600
- const {parsed_lines, str_indentation} = indentation_analysis;
601
- const client_root_js = extract_client_js(formatting_info);
602
-
603
- //fnlfs.save('d:\\saved.js', client_root_js);
604
-
605
-
606
- s.push(client_root_js);
607
- s.push(null);
608
- const lines_file_content = [];
609
-
610
- // Don't always include sourcemap?
611
- // Separate out the sourcemap?
612
-
613
- const b = browserify(s, {
614
- basedir: path.dir,
615
- //builtins: false,
616
- builtins: ['buffer'],
617
- 'debug': options.include_sourcemaps
618
- });
619
- // Prefer the idea of sending a stream to browserify.
620
- const parts = await stream_to_array(b.bundle());
621
- /*
622
- var b = browserify([js_file_path], {
623
- 'debug': true
624
- });
625
- */
626
- //let parts = await stream_to_array(b.bundle());
627
- const buffers = parts
628
- .map(part => util.isBuffer(part) ? part : Buffer.from(part));
629
- let buf_js = Buffer.concat(buffers);
630
- const str_js = buf_js.toString();
631
- const str_js_code = str_js;
632
- let str_sourcemap;
633
-
634
- let pos_prior_sourcemap = str_js.indexOf('//# sourceMappingURL');
635
- if (pos_prior_sourcemap > -1) {
636
- str_js_code = str_js.substr(0, pos_prior_sourcemap);
637
- str_sourcemap = str_js.substr(pos_prior_sourcemap);
638
- }
639
- // filter_extract_css
640
-
641
-
642
- /*
643
- const js_remove_comments = (str_js_code) => {
644
- // comments will be OK within a string.
645
-
646
- // Be able to work out what type of code we are in at all points...?
647
- // Non-tokenising scanner...?
648
-
649
- // Knowing whether or not * / // / * is within a string is important - because if it's in a string its not a comment.
650
- // seems like making the scanning parser is a bit of a large task. It would constantly need to know what symbol type / string encapsulator to use.
651
-
652
- // Could split it into lines, spot whenever a line starts a comment...?
653
- }
654
- */
655
-
656
- const filter_js_extract_control_css = (str_js_code) => {
657
- // res = [css, js_no_css]
658
- // Split the js lines.
659
-
660
- const s_js = str_js_code.split('\n');
661
- let within_class_css = false;
662
- const control_css_lines = [];
663
- const js_non_css_lines = [];
664
- // and the non-css lines.
665
- // And need to look for its stop.
666
- // And leave the first and last line out of the css.
667
- each(s_js, js_line => {
668
- let placed_js_line = false;
669
- const pos_class_css_begin = js_line.indexOf('.css = `');
670
- // if its 0
671
-
672
- if (pos_class_css_begin > -1) {
673
- //console.log('js_line', js_line);
674
- within_class_css = true;
675
- }
676
- // Put empty lines (back) into the js array?
677
-
678
- if (within_class_css) {
679
- //console.log('js_line', js_line);
680
-
681
- const pos_control_css_end = js_line.indexOf('`;');
682
- //console.log('pos_control_css_end', pos_control_css_end);
683
- if (pos_control_css_end > -1) {
684
- within_class_css = false;
685
- } else {
686
- if (pos_class_css_begin > -1) {
687
-
688
- } else {
689
- control_css_lines.push(js_line);
690
- }
691
-
692
- }
693
- } else {
694
- js_non_css_lines.push(js_line);
695
- placed_js_line = true;
696
- }
697
-
698
- if (!placed_js_line) {
699
- js_non_css_lines.push('');
700
- }
701
- //let is_control_css_start = js_line.indexOf()
702
-
703
- if (control_css_lines.length > 200) throw 'stop';
704
-
705
- })
706
- return [control_css_lines.join('\n'), js_non_css_lines.join('\n')];
707
- }
708
-
709
- let [str_css, str_js_no_css] = filter_js_extract_control_css(str_js_code);
710
-
711
- // Add the sourcemaps back? Its working.
712
-
713
- if (str_sourcemap) {
714
- str_js_no_css = str_js_no_css + str_sourcemap;
715
- }
716
- this.raise('extracted-controls-css', str_css);
717
- let babel_option = options.babel;
718
-
719
- //console.log('babel_option', babel_option);
720
- //throw 'stop';
721
- //babel_option = 'es5';
722
- //console.log('babel_option', babel_option);
723
- if (babel_option === 'es5') {
724
- // es5 option
725
- // not sure if it babels async await though.
726
- /*
727
- {
728
- "presets": [
729
- "es2015",
730
- "es2017"
731
- ],
732
- "plugins": [
733
- "transform-runtime"
734
- ]
735
- }
736
- */
737
- /*
738
- let res_transform = babel.transform(str_js, {
739
- //'plugins': ['transform-class']
740
- 'plugins': ['transform-es2015-object-super', 'transform-es2015-classes', 'remove-comments'],
741
- 'sourceMaps': 'inline'
742
- //'plugins': ['transform-es2015-classes']
743
- // transform-es2015-object-super
744
- });
745
- */
746
- let o_tranform = {
747
- "presets": [
748
- "es2015",
749
- "es2017"
750
- ],
751
- "plugins": [
752
- "transform-runtime"
753
- ] //,
754
- //'sourceMaps': 'inline'
755
- };
756
- if (options.include_sourcemaps) o_tranform.sourceMaps = 'inline';
757
-
758
- let res_transform = babel.transform(str_js_no_css, o_tranform);
759
- let jst_es5 = res_transform.code;
760
- //let {jst_es5, map, ast} = babel.transform(str_js);
761
- //console.log('jst_es5.length', jst_es5.length);
762
- buf_js = Buffer.from(jst_es5);
763
- } else if (babel_option === 'mini') {
764
- /*
765
- let o_transform = {
766
- presets: ["minify"]//,
767
- //'sourceMaps': 'inline'
768
- };
769
- */
770
- let o_transform = {
771
- "presets": [
772
- ["minify", {
773
- //"mangle": {
774
- //"exclude": ["MyCustomError"]
775
- //},
776
- //"unsafe": {
777
- // "typeConstructors": false
778
- //},
779
- //"keepFnName": true
780
- }]
781
- ],
782
- "comments": false
783
- //plugins: ["minify-dead-code-elimination"]
784
- };
785
-
786
- if (options.include_sourcemaps) o_transform.sourceMaps = 'inline';
787
- let res_transform = babel.transform(str_js_no_css, o_transform);
788
- //let jst_es5 = res_transform.code;
789
- //let {jst_es5, map, ast} = babel.transform(str_js);
790
- //console.log('jst_es5.length', jst_es5.length);
791
- buf_js = Buffer.from(res_transform.code);
792
- } else {
793
- buf_js = Buffer.from(str_js_no_css);
794
- console.log('no babel use');
795
- }
796
- var escaped_url = url.replace(/\./g, '☺');
797
-
798
- //console.log('pre compress buf_js.length', buf_js.length);
799
- zlib.gzip(buf_js, {level: 9}, (err, buffer) => {
800
- console.log('deflated buf_js buffer.length', buffer.length);
801
-
802
- if (err) {
803
- reject(err);
804
- } else {
805
- //
806
- //buffer.encoding = 'deflate';
807
- console.log('');
808
- console.log('escaped_url', escaped_url);
809
- console.log('url', url);
810
- console.log('');
811
-
812
- const rp = this.pool;
813
- console.log('rp', rp);
814
- console.log('rp.resource_names', rp.resource_names);
815
-
816
- const router = rp.get_resource('Site Router');
817
- console.log('router', router);
818
-
819
- router.set_route(url, this, (req, res) => {
820
- console.log('router', [!!req, !!res]);
821
- });
822
-
823
- /*
824
- 'set_route'(str_route, context, fn_handler) {
825
- */
826
-
827
- // Setting up routing here?
828
- // Or returning it to the server?
829
-
830
- // hack_setup_routing - as in it hacks into another part of the system (which is available)
831
- // to set up the routing. A more top-down approach would be for the Server module to set the
832
- // routing up itself.
833
- // May be nice if components / resources could set up their own routing, with access to the
834
- // Resource_Pool.
835
-
836
-
837
-
838
- /*
839
-
840
- // Would need to check operation of custom paths.
841
- // Maybe its use was removed...?
842
- this.custom_paths.set(escaped_url, {
843
- raw: buf_js,
844
- gzip: buffer
845
- });
846
-
847
- */
848
-
849
-
850
-
851
- resolve(true);
852
- }
853
- });
854
- }
855
- })();
856
- }, callback);
857
- }
858
-
859
- /*
860
- 'set_custom_path'(url, file_path) {
861
- var escaped_url = url.replace(/\./g, '☺');
862
- this.custom_paths.set(escaped_url, file_path);
863
- }
864
- */
865
- //
866
-
867
-
868
- // Not so sure that it should process the request.
869
- // A more general purpose request handler...?
870
- // Have more request handling code within one js file, a cenralised portion of the app.
871
- // And then within those request handlers call on useful abstractions.
872
-
873
- // Setting up one or more Compilers seems like it would solve some of what this is doing.
874
- // Even a Compilation_Process object that provides data for monitoring.
875
- // Published with a Resource_Publisher possibly.
876
-
877
- // Website_HTTP_Publisher maybe
878
-
879
- // or just HTTP_Publisher, a Publisher rather than a Resource.
880
- // HTTP_Publisher, which is focused on publishing HTTP, may be the best option here.
881
- // Seems best to fix what we have already first though. Could then work on HTTP_Publisher.
882
-
883
-
884
-
885
- // Website_HTTP_Publisher_Resource possibly?
886
-
887
- //
888
-
889
-
890
-
891
- // Site_JavaScript seems more about bundling / compiling rather than serving.
892
- // Resources could present their data ahead of time / be asked for them and provide it, and the server
893
- // keeps track of info more centrally.
894
- //
895
-
896
-
897
-
898
-
899
- 'process'(req, res) {
900
- console.log('Site_JavaScript processing req.url', req.url);
901
- var remoteAddress = req.connection.remoteAddress;
902
- var custom_paths = this.custom_paths;
903
- var rurl = req.url.replace(/\./g, '☺');
904
- var custom_response_entry = custom_paths[rurl];
905
- var pool = this.pool;
906
- if (custom_response_entry) {
907
- const ae = req.headers['accept-encoding'];
908
- let data_to_serve;
909
- let o_head = {
910
- 'Content-Type': 'text/javascript'
911
- }
912
- if (ae.includes('gzip')) {
913
- o_head['Content-Encoding'] = 'gzip';
914
- data_to_serve = custom_response_entry._.gzip;
915
- } else {
916
- data_to_serve = custom_response_entry._.raw;
917
- }
918
- res.writeHead(200, o_head);
919
- res.end(data_to_serve);
920
- } else {
921
- //var served_directories = this.served_directories;
922
- //console.log('served_directories', served_directories);
923
- var url_parts = url.parse(req.url, true);
924
- //console.log('url_parts ' + stringify(url_parts));
925
- var splitPath = url_parts.path.substr(1).split('/');
926
-
927
- var wildcard_value = req.params.wildcard_value;
928
- //console.log('*** wildcard_value', wildcard_value);
929
-
930
- if (wildcard_value == 'web/require.js') {
931
-
932
- } else {
933
- var disk_path = path.dirname(require.main.filename) + '/' + 'js/' + wildcard_value;
934
- var compress = false;
935
-
936
-
937
- //console.log('disk_path', disk_path);
938
-
939
- if (compress) {
940
- throw 'NYI with Babel';
941
-
942
- } else {
943
- // try to load it from the project's js path.
944
- //console.log('disk_path', disk_path);
945
- var project_js_path = 'js/' + wildcard_value;
946
- //console.log('project_js_path', project_js_path);
947
-
948
- fs2.load_file_as_string(disk_path, function (err, str_js) {
949
- if (err) {
950
- console.log('error loading from project_js_path: ', project_js_path);
951
- console.log(err);
952
- } else {
953
- // Have loaded the js from the project path, we can serve it.
954
- console.log('have loaded js');
955
- // serve the js.
956
-
957
-
958
- //res.writeHead(200, {'Content-Type': 'text/javascript'});
959
- // Could possibly stream it from disk instead, that would likely be more efficient.
960
- console.log('str_js.length', str_js.length);
961
-
962
-
963
- // use gzip in many cases.
964
- // want to support that.
965
-
966
- // a streaming middleware fn could work...?
967
-
968
- zlib.deflate(str_js, function (err, buffer) {
969
- console.log('deflated buffer.length', buffer.length);
970
-
971
-
972
- if (err) throw err;
973
- res.writeHead(200, {
974
- 'Content-Encoding': 'deflate',
975
- 'Content-Type': 'text/javascript'
976
- });
977
- res.end(buffer);
978
- //res.writeHead(200, {'Content-Type': 'text/javascript'});
979
- //response.end(servableJs);
980
- //res.end(minified.code);
981
- });
982
-
983
-
984
- //response.end(servableJs);
985
- //res.end(str_js);
986
- //throw 'stop';
987
- }
988
- })
989
- }
990
- }
991
- }
992
- }
993
- }
994
-
1
+ // Sep 2023:
2
+ // This Resource itself is huge in scope, but maybe would be better to make the Resource more in terms of representing the Resource itself
3
+ // and having things like Resource_Processor? Resource_Analyser? Resource_Miner? Resource_Extracter? Resource_Transformer?
4
+ // Resource_Bundler? Resource_Builder?
5
+
6
+ // Resource_Verb_Carryouter Resource_Processor seems like the general name. Could do analysis, building, extraction etc.
7
+ // Raising events / announcements when it finds things.
8
+
9
+ // Does seem like refactoring the Resource so it is much simpler will be worth it, but also going into detail on the
10
+ // different ways the resources can be processed, doing it in a polymorphic way, observables, promises, making more classes for it if needed.
11
+
12
+ // Maybe do want the classes with processing functions built-in?
13
+ // Changing the syntax to more explictly use various files and classes which will be interchangable and separately upgradable
14
+ // and testable will help.
15
+
16
+ // Need to refactor, this code no longer works as first intended, and was slow when it did its full thing.
17
+ // Can do things much more optimially, maybe with esbuild and hashing and caching.
18
+
19
+
20
+
21
+
22
+
23
+
24
+
25
+
26
+
27
+ // Nov 2020:
28
+ // Need to overhaul this, bugs are on the client, need to be careful and clear about what will be sent to the client.
29
+ // Need to get more into the tools for building JS for the client. Can I do the outline / much of the outline of it myself?
30
+ // Build up a huge JS AST of the whole thing.
31
+ // Build up a system that understands what code does (to an extent) and how it fits together.
32
+
33
+ // Could do my own application-level compression.
34
+
35
+ // JS-Build.
36
+ // Could identify the resources / files used in the site?
37
+
38
+ // Load all the files in, made into a function that will return what the module exports.
39
+ // Or not...
40
+ // Make the module into just the code, store it as a variable, then be able to build
41
+
42
+ // Would make quite a difference - with a lot of localised references made possible.
43
+ //
44
+
45
+
46
+ // JS_File
47
+ // Be able to get transformed versions of it
48
+ // JS_File_
49
+
50
+
51
+ // Much of this could be better expressed as a Compiler_Resource.
52
+
53
+
54
+ // Plan: Do more of this through lower level compilation features.
55
+ // Accessing a compilation resource makes sense structurally.
56
+
57
+ // May want a server to create and test compilation resources / compilers.
58
+
59
+ // Compilers, Bundlers, HTTP Request Handlers - Somewhat lower level, ie tools to get things done.
60
+ // Then also: resources which make use of upgraded and new lower level components.
61
+
62
+ // Server_Resource could help?
63
+
64
+ // Late 2023 - Should keep most of this for the moment, see about using parts when / where needed, also add in other (maybe simpler)
65
+ // ways to do things that are needed to publish JS.
66
+
67
+ // This resource seems like it's responsible for building JS.
68
+ // Seems like a piece of 'server' functionality that will be kind of hidden, need to make sure it's not a leaky abstraction.
69
+ // Also worth considering 'shorthands' where specific pieces of functionality are not needed to be specified, but usually we
70
+ // need to tell it that it needs to compile the JS (and other things).
71
+
72
+ // Maybe this JS resource would be responsible for extracting the CSS from JS and providing it to the CSS resource.
73
+ // Would be best to work through getting a few examples, and implementations of simple apps with nice (maybe new) APIs that need
74
+ // to be supported by jsgui3.
75
+
76
+ // For the moment, don't make anything really complex when it's not needed, but make it so on the lower levels (incl mid)
77
+ // it accesses functionality that is structured in a somewhat complex way, but uses it to do things which by default make the whole
78
+ // process simple.
79
+
80
+ // This runs automatically I think.
81
+ // Probably need to get it automatically building the client js on server start if needed.
82
+ // Likely best to save it locally, as well as to make a hash of all the files that went into the build, save that, only
83
+ // rebuild when it has changed.
84
+
85
+ // Could even provide a list of the intial control jsgui IDs, some empty items in an array? or the index of the node in the doc
86
+ // and then the control id that will be applied.
87
+ // This could make cleaner HTML be served by default, with IDs added later on the client-side using possibly a small amount of
88
+ // supplementary info.
89
+ // Or the ids could be assigned using xpaths.
90
+
91
+
92
+
93
+
94
+
95
+
96
+
97
+
98
+
99
+
100
+
101
+ const path = require('path'),
102
+ fs = require('fs'),
103
+ url = require('url'),
104
+ jsgui = require('jsgui3-html'),
105
+ os = require('os'),
106
+ http = require('http'),
107
+ libUrl = require('url'),
108
+ Resource = jsgui.Resource,
109
+ fs2 = require('../fs2'),
110
+ //brotli = require('iltorb').compress,
111
+ //UglifyJS = require('uglify-js'),
112
+ zlib = require('zlib');
113
+
114
+ //fs.createReadStream(filename).pipe(brotli()).pipe(res);
115
+
116
+ const fnl = require('fnl');
117
+ const prom_or_cb = fnl.prom_or_cb;
118
+ const fnlfs = require('fnlfs');
119
+
120
+ const each = jsgui.each,
121
+ arrayify = jsgui.arrayify,
122
+ tof = jsgui.tof;
123
+ const filter_map_by_regex = jsgui.filter_map_by_regex;
124
+ const Class = jsgui.Class,
125
+ Data_Object = jsgui.Data_Object,
126
+ Enhanced_Data_Object = jsgui.Enhanced_Data_Object;
127
+ const fp = jsgui.fp,
128
+ is_defined = jsgui.is_defined;
129
+ const Collection = jsgui.Collection;
130
+ const call_multi = jsgui.call_multi,
131
+ get_truth_map_from_arr = jsgui.get_truth_map_from_arr;
132
+
133
+
134
+ //var zlib = require('zlib');
135
+ const util = require('util');
136
+
137
+ const browserify = require('browserify');
138
+ const babel = require('@babel/core');
139
+
140
+ // Extends AutoStart_Resource?
141
+ const stream_to_array = require('stream-to-array');
142
+
143
+
144
+ const process_js = require('./process-js');
145
+ const {analyse_js_doc_formatting, extract_client_js} = process_js;
146
+
147
+
148
+ var serve_js_file_from_disk_updated_refs = function (filePath, response, callback) {
149
+ fs2.load_file_as_string(filePath, function (err, data) {
150
+ if (err) {
151
+ throw err;
152
+ } else {
153
+ //console.log('');
154
+ //console.log('serve_js_file_from_disk_updated_refs filePath ' + filePath);
155
+ //console.log('data ' + data);
156
+ //var servableJs = updateReferencesForServing(data);
157
+ response.writeHead(200, {
158
+ 'Content-Type': 'text/javascript'
159
+ });
160
+ //response.end(servableJs);
161
+ response.end(data);
162
+ }
163
+ });
164
+ }
165
+
166
+ var check_served_directories_for_requested_file = function (arr_served_paths, split_path_within_js, callback) {
167
+
168
+ var fns = [
169
+
170
+ ]
171
+ var checkPath = function (path, callback) {
172
+ // check to see if an existing file matches up with the path that is requested.
173
+ // so, from that path, we use the split_path_within_js for the rest of the file path.
174
+ // then we check if such a (JS) file exists.
175
+ }
176
+ // fns.push([fs2.load_file_as_string, [source_path_item], function(err, res_loaded) {
177
+
178
+ // Not so sure I can use the exists function like this...
179
+ var reconstitutedPathWithinJs = split_path_within_js.join('/');
180
+ var firstFoundPath;
181
+ each(arr_served_paths, function (i, fsPath) {
182
+ fns.push([function (callback) {
183
+ var checkingPath = fsPath + '/' + reconstitutedPathWithinJs;
184
+ fs.exists(checkingPath, function (exists) {
185
+ //console.log('cb fsPath ' + checkingPath + ' exists ' + exists)
186
+ if (exists & !firstFoundPath) {
187
+ firstFoundPath = checkingPath;
188
+ }
189
+ callback(null, exists);
190
+ })
191
+ },
192
+ []
193
+ ]);
194
+ });
195
+ call_multi(fns, function (err, res_multi) {
196
+ if (err) {
197
+ console.log('err ' + err);
198
+ throw 'stop';
199
+ } else {
200
+ //console.log('res_multi ' + stringify(res_multi));
201
+ //throw 'stop';
202
+
203
+ if (firstFoundPath) {
204
+ callback(null, firstFoundPath);
205
+ } else {
206
+ callback(null, null);
207
+ }
208
+ }
209
+ });
210
+ }
211
+
212
+ // A way of serving a file so that it includes custom code.
213
+ // Or have a standard client template that is easy to serve.
214
+
215
+ // Maybe do more with custom controls, such as custom page controls.
216
+ // Those page controls would know which control types are within them.
217
+ // That info could then be used to write JS code that sets up the references on the client.
218
+
219
+ // Possibly this should have its own routing tree to connect paths with js files?
220
+ // Need to set up custom paths.
221
+
222
+ class Site_JavaScript extends Resource {
223
+ //'fields': {
224
+ // 'custom_paths': 'data_object'
225
+ //},
226
+ constructor(spec) {
227
+ super(spec);
228
+ //this.meta.set('custom_paths', new Data_Object({}));
229
+ //this.custom_paths = new Data_Object({});
230
+ // Those are custom file paths.
231
+ // could have a collection of directories, indexed by name, that get served.
232
+ // Index the collection by string value?
233
+ //this.meta.set('served_directories', new Collection({'index_by': 'name'}));
234
+
235
+ // But this could be held (only) in the router.
236
+ this.served_directories = new Collection({
237
+ 'index_by': 'name'
238
+ });
239
+ }
240
+ 'start'(callback) {
241
+ //console.log('Site_JavaScript start');
242
+ const build_on_start = this.build_on_start;
243
+ if (build_on_start) {
244
+ this.build_client(function (err, res_build) {
245
+ if (err) {
246
+ callback(err)
247
+ } else {
248
+ callback(null, true);
249
+ }
250
+ })
251
+ } else {
252
+ callback(null, true);
253
+ }
254
+ // Let's have it build the client-side code.
255
+ // Need the options to ignore various files, as well as to include the source maps in the output.
256
+ }
257
+ // build client, and serve it from one particular place
258
+ // do so with a promise.
259
+ // serve_package
260
+ // Need to bundle / build together a package from the disk path, then serve it under a URL route.
261
+
262
+ // want to give it the file to build.
263
+ // There will be a variety of jsgui packages.
264
+
265
+
266
+ // Will be better as a promise.
267
+
268
+ 'build_client'(callback) {
269
+
270
+ // Configurable building mechanisms....
271
+ // Want to provide jsgui events / logs on the build process.
272
+
273
+ // jsgui.notify could be used for some kinds of internal event logging.
274
+ // a specific type of event system.
275
+
276
+ // jsgui.raise('notification', )
277
+
278
+ // .note may be faster.
279
+
280
+
281
+
282
+
283
+ // jsgui.notify('start', 'build_client');
284
+
285
+
286
+ // Need the reference relative to the application directory.
287
+ //var path = __dirname + '/js/app.js';
288
+
289
+ // Can we stream it to a buffer in memory instead?
290
+
291
+ // Using a compilation resource may be better long-term.
292
+ // Creating and using a relevant abstraction.
293
+
294
+ // The server should have already loaded (a few) compilers.
295
+
296
+
297
+ var appDir = path.dirname(require.main.filename);
298
+
299
+
300
+
301
+
302
+ //console.log('appDir', appDir);
303
+ var app_path = appDir + '/js/app.js';
304
+ var app_bundle_path = appDir + '/js/app-bundle.js';
305
+ var wstream = fs.createWriteStream(app_bundle_path);
306
+ var b = browserify();
307
+ //b.require(app_path, {
308
+ // entry: true,
309
+ // debug: true
310
+ //});
311
+ b.add(app_path);
312
+ //console.log('app_path', app_path);
313
+ //console.log('pre browserify bundle');
314
+ //b.bundle().pipe(process.stdout);
315
+
316
+ b.bundle().pipe(wstream);
317
+
318
+ wstream.end = function (data) {
319
+ //console.log('file bundle write complete');
320
+ callback(null, app_bundle_path);
321
+ // no more writes after end
322
+ // emit "close" (optional)
323
+ }
324
+ }
325
+ // Will could serve all jsgui code?
326
+ // May be better not to allow server-side code to be read on the client.
327
+ // Could have specific directories within jsgui that get served to the client.
328
+
329
+
330
+ // May be best thinking of bundling up one or more objects / files ready for the server to serve.
331
+
332
+
333
+ 'serve_directory'(path) {
334
+ // Serves that directory, as any files given in that directory can be served from /js
335
+
336
+ // Perhaps just using the router would be better.
337
+
338
+ var served_directories = this.served_directories;
339
+ //console.log('served_directories ' + stringify(served_directories));
340
+ //served_directories.push(path);
341
+ served_directories.push({
342
+ 'name': path
343
+ });
344
+ //console.log('served_directories ' + stringify(served_directories));
345
+ //console.log('path ' + path);
346
+ //throw 'stop';
347
+ }
348
+ 'serve_package'(url, js_package, options = {}, callback) {
349
+ //console.log('serve_package', url, js_package);
350
+ //console.log('js_package', js_package);
351
+ //console.log('typeof js_package', typeof js_package);
352
+ //let tjp = typeof js_package;
353
+ return this.serve_package_from_path(url, require.resolve(js_package), options, callback);
354
+ }
355
+
356
+ // Possibly some functionality would be better within the js bundler.
357
+
358
+
359
+
360
+ 'package'(js_file_path, options = {}, callback) {
361
+
362
+ let a = arguments;
363
+ if (typeof a[2] === 'function') {
364
+ callback = a[2];
365
+ options = {
366
+ //'babel': 'mini',
367
+ 'include_sourcemaps': true
368
+ };
369
+ }
370
+
371
+ return prom_or_cb((resolve, reject) => {
372
+ (async () => {
373
+ // options
374
+ // may want a replacement within the client-side code.
375
+ // Can we call browserify on the code string?
376
+ // Creating a modified copy of the file would do.
377
+ // Load the file, modify it, save it under a different name
378
+
379
+ let s = new require('stream').Readable(),
380
+ path = require('path').parse(js_file_path);
381
+
382
+ let fileContents = await fnlfs.load(js_file_path);
383
+ //console.log('1) fileContents.length', fileContents.length);
384
+ // are there any replacements to do?
385
+ // options.replacements
386
+
387
+ if (options.js_mode === 'debug') {
388
+ options.include_sourcemaps = true;
389
+ }
390
+ if (options.js_mode === 'compress' || options.js_mode === 'mini') {
391
+ options.include_sourcemaps = false;
392
+ options.babel = 'mini';
393
+ }
394
+
395
+ //console.log('options.babel', options.babel);
396
+
397
+ if (options.replace) {
398
+ let s_file_contents = fileContents.toString();
399
+ //console.log('s_file_contents', s_file_contents);
400
+ each(options.replace, (text, key) => {
401
+ //console.log('key', key);
402
+ //console.log('text', text);
403
+ let running_fn = '(' + text + ')();'
404
+ //console.log('running_fn', running_fn);
405
+ s_file_contents = s_file_contents.split(key).join(running_fn);
406
+ })
407
+ fileContents = Buffer.from(s_file_contents);
408
+ //console.log('2) fileContents.length', fileContents.length);
409
+ }
410
+ // Then we can replace some of the file contents with specific content given when we tall it to serve that file.
411
+ // We have a space for client-side activation.
412
+ s.push(fileContents);
413
+ s.push(null);
414
+
415
+ //let include_sourcemaps = true;
416
+
417
+ let b = browserify(s, {
418
+ basedir: path.dir,
419
+ //builtins: false,
420
+ builtins: ['buffer', 'process'],
421
+ 'debug': options.include_sourcemaps
422
+ });
423
+
424
+ let parts = await stream_to_array(b.bundle());
425
+
426
+ const buffers = parts
427
+ .map(part => util.isBuffer(part) ? part : Buffer.from(part));
428
+ let buf_js = Buffer.concat(buffers);
429
+ let str_js = buf_js.toString();
430
+
431
+ let babel_option = options.babel
432
+ //console.log('babel_option', babel_option);
433
+ if (babel_option === 'es5') {
434
+
435
+ let o_transform = {
436
+ "presets": [
437
+ "es2015",
438
+ "es2017"
439
+ ],
440
+ "plugins": [
441
+ "transform-runtime"
442
+ ] //,
443
+ //'sourceMaps': 'inline'
444
+ };
445
+
446
+ if (options.include_sourcemaps) o_transform.sourceMaps = 'inline';
447
+ let res_transform = babel.transform(str_js, o_transform);
448
+ //console.log('res_transform', res_transform);
449
+ //console.log('Object.keys(res_transform)', Object.keys(res_transform));
450
+ let jst_es5 = res_transform.code;
451
+ //let {jst_es5, map, ast} = babel.transform(str_js);
452
+ //console.log('jst_es5.length', jst_es5.length);
453
+ buf_js = Buffer.from(jst_es5);
454
+ } else if (babel_option === 'mini') {
455
+ /*
456
+ let o_transform = {
457
+ presets: ["minify"]//,
458
+ //'sourceMaps': 'inline'
459
+ };
460
+ */
461
+ let o_transform = {
462
+ "presets": [
463
+ ["minify", {
464
+ //"mangle": {
465
+ //"exclude": ["MyCustomError"]
466
+ //},
467
+ //"unsafe": {
468
+ // "typeConstructors": false
469
+ //},
470
+ //"keepFnName": true
471
+ }]
472
+ ],
473
+ //plugins: ["minify-dead-code-elimination"]
474
+ };
475
+ if (options.include_sourcemaps) o_transform.sourceMaps = 'inline';
476
+
477
+ let res_transform = babel.transform(str_js, o_transform);
478
+ buf_js = Buffer.from(res_transform.code);
479
+ } else {
480
+ buf_js = Buffer.from(str_js);
481
+ }
482
+ resolve(buf_js);
483
+ })();
484
+ }, callback);
485
+ }
486
+
487
+ // This is a lot about creating some 'package' that includes built JS and CSS
488
+
489
+ // It is not so clear what 'serve' means here though.
490
+ // Perhaps using this functionality could take a few more function calls that are more explicit,
491
+ // but also be set up so that it happens by default when appropriate, or some other function
492
+ // that uses some of the same newly refactored / referenced functions will do the job.
493
+
494
+ // Being more explicit about making sure the server has access to:
495
+ // 1) The client side JS
496
+ // 2) The means to build the client side JS
497
+ // 3) Analysis of the client-side JS source file / files
498
+ // If they contain CSS, that extracted CSS, as a CSS file.
499
+ // Probably best to make a callback saying that it's got it?
500
+ // An 'announcement'? New 'announcement' mechanism, so that when the CSS has been found the CSS publisher hears the announcement.
501
+ // Means the JS resource or publisher does not need a direct reference to the CSS resource or publisher.
502
+
503
+ // Also, make use of the distinction between a Resource and a Publisher.
504
+ // A Resource is something like a file on the disk.
505
+ // The Resources get provided to the Publishers.
506
+ // Then do the Publishers create Resources? Publications? Published_Resources?
507
+
508
+
509
+
510
+
511
+
512
+
513
+
514
+
515
+
516
+ // 3) The built client-side JS (with or without sourcemaps)
517
+ // 4) The compression setting (brotli/gzip) to compress that client-side JS
518
+
519
+
520
+
521
+
522
+ 'serve_package_from_path'(url, js_file_path, options = {}, callback) {
523
+ //console.log('serve_package_from_path', url, js_file_path);
524
+ // js_mode option may need to be used.
525
+
526
+
527
+ // Make it an observable?
528
+ // Raise an event when we have the browserified fill js file (uncompressed?).
529
+
530
+
531
+ let a = arguments;
532
+ if (typeof a[2] === 'function') {
533
+ callback = a[2];
534
+ options = {
535
+ //'babel': 'mini',
536
+ 'include_sourcemaps': false
537
+ };
538
+ }
539
+ let serve_raw = options.serve_raw || options.raw;
540
+ let accepts_brotli = false;
541
+
542
+ // Need to come up with compressed versions.
543
+ // An object that provides different versions.
544
+
545
+
546
+ return prom_or_cb((resolve, reject) => {
547
+ (async () => {
548
+ // options
549
+ // may want a replacement within the client-side code.
550
+ // Can we call browserify on the code string?
551
+ // Creating a modified copy of the file would do.
552
+ // Load the file, modify it, save it under a different name
553
+ const Stream = require('stream');
554
+
555
+ let s = new Stream.Readable(),
556
+ path = require('path').parse(js_file_path);
557
+
558
+ let fileContents = await fnlfs.load(js_file_path);
559
+ //console.log('1) fileContents.length', fileContents.length);
560
+ // are there any replacements to do?
561
+ // options.replacements
562
+ if (options.js_mode === 'debug') {
563
+ options.include_sourcemaps = true;
564
+ }
565
+ if (options.js_mode === 'compress' || options.js_mode === 'mini') {
566
+ options.include_sourcemaps = false;
567
+ options.babel = 'mini';
568
+ }
569
+ //console.log('options.babel', options.babel);
570
+
571
+ // Likely to remove this....
572
+ if (options.replace) {
573
+ let s_file_contents = fileContents.toString();
574
+ //console.log('s_file_contents', s_file_contents);
575
+ each(options.replace, (text, key) => {
576
+ //console.log('key', key);
577
+ //console.log('text', text);
578
+ const running_fn = '(' + text + ')();'
579
+ //console.log('running_fn', running_fn);
580
+ s_file_contents = s_file_contents.split(key).join(running_fn);
581
+ })
582
+ fileContents = Buffer.from(s_file_contents);
583
+ //console.log('2) fileContents.length', fileContents.length);
584
+ }
585
+
586
+ // Then we can replace some of the file contents with specific content given when we tall it to serve that file.
587
+ // We have a space for client-side activation.
588
+ // want a raw option with no browserify.
589
+ //console.log('serve_raw', serve_raw);
590
+ if (serve_raw) {
591
+ const escaped_url = url.replace(/\./g, '☺');
592
+ //this.custom_paths.set(escaped_url, fileContents);
593
+
594
+ throw 'NYI';
595
+ } else {
596
+ const formatting_info = analyse_js_doc_formatting(fileContents.toString());
597
+ //console.log('formatting_info', formatting_info);
598
+
599
+ const {arr_lines, line_break, indentation_analysis} = formatting_info;
600
+ const {parsed_lines, str_indentation} = indentation_analysis;
601
+ const client_root_js = extract_client_js(formatting_info);
602
+
603
+ //fnlfs.save('d:\\saved.js', client_root_js);
604
+
605
+
606
+ s.push(client_root_js);
607
+ s.push(null);
608
+ const lines_file_content = [];
609
+
610
+ // Don't always include sourcemap?
611
+ // Separate out the sourcemap?
612
+
613
+ const b = browserify(s, {
614
+ basedir: path.dir,
615
+ //builtins: false,
616
+ builtins: ['buffer'],
617
+ 'debug': options.include_sourcemaps
618
+ });
619
+ // Prefer the idea of sending a stream to browserify.
620
+ const parts = await stream_to_array(b.bundle());
621
+ /*
622
+ var b = browserify([js_file_path], {
623
+ 'debug': true
624
+ });
625
+ */
626
+ //let parts = await stream_to_array(b.bundle());
627
+ const buffers = parts
628
+ .map(part => util.isBuffer(part) ? part : Buffer.from(part));
629
+ let buf_js = Buffer.concat(buffers);
630
+ const str_js = buf_js.toString();
631
+ const str_js_code = str_js;
632
+ let str_sourcemap;
633
+
634
+ let pos_prior_sourcemap = str_js.indexOf('//# sourceMappingURL');
635
+ if (pos_prior_sourcemap > -1) {
636
+ str_js_code = str_js.substr(0, pos_prior_sourcemap);
637
+ str_sourcemap = str_js.substr(pos_prior_sourcemap);
638
+ }
639
+ // filter_extract_css
640
+
641
+
642
+ /*
643
+ const js_remove_comments = (str_js_code) => {
644
+ // comments will be OK within a string.
645
+
646
+ // Be able to work out what type of code we are in at all points...?
647
+ // Non-tokenising scanner...?
648
+
649
+ // Knowing whether or not * / // / * is within a string is important - because if it's in a string its not a comment.
650
+ // seems like making the scanning parser is a bit of a large task. It would constantly need to know what symbol type / string encapsulator to use.
651
+
652
+ // Could split it into lines, spot whenever a line starts a comment...?
653
+ }
654
+ */
655
+
656
+ const filter_js_extract_control_css = (str_js_code) => {
657
+ // res = [css, js_no_css]
658
+ // Split the js lines.
659
+
660
+ const s_js = str_js_code.split('\n');
661
+ let within_class_css = false;
662
+ const control_css_lines = [];
663
+ const js_non_css_lines = [];
664
+ // and the non-css lines.
665
+ // And need to look for its stop.
666
+ // And leave the first and last line out of the css.
667
+ each(s_js, js_line => {
668
+ let placed_js_line = false;
669
+ const pos_class_css_begin = js_line.indexOf('.css = `');
670
+ // if its 0
671
+
672
+ if (pos_class_css_begin > -1) {
673
+ //console.log('js_line', js_line);
674
+ within_class_css = true;
675
+ }
676
+ // Put empty lines (back) into the js array?
677
+
678
+ if (within_class_css) {
679
+ //console.log('js_line', js_line);
680
+
681
+ const pos_control_css_end = js_line.indexOf('`;');
682
+ //console.log('pos_control_css_end', pos_control_css_end);
683
+ if (pos_control_css_end > -1) {
684
+ within_class_css = false;
685
+ } else {
686
+ if (pos_class_css_begin > -1) {
687
+
688
+ } else {
689
+ control_css_lines.push(js_line);
690
+ }
691
+
692
+ }
693
+ } else {
694
+ js_non_css_lines.push(js_line);
695
+ placed_js_line = true;
696
+ }
697
+
698
+ if (!placed_js_line) {
699
+ js_non_css_lines.push('');
700
+ }
701
+ //let is_control_css_start = js_line.indexOf()
702
+
703
+ if (control_css_lines.length > 200) throw 'stop';
704
+
705
+ })
706
+ return [control_css_lines.join('\n'), js_non_css_lines.join('\n')];
707
+ }
708
+
709
+ let [str_css, str_js_no_css] = filter_js_extract_control_css(str_js_code);
710
+
711
+ // Add the sourcemaps back? Its working.
712
+
713
+ if (str_sourcemap) {
714
+ str_js_no_css = str_js_no_css + str_sourcemap;
715
+ }
716
+ this.raise('extracted-controls-css', str_css);
717
+ let babel_option = options.babel;
718
+
719
+ //console.log('babel_option', babel_option);
720
+ //throw 'stop';
721
+ //babel_option = 'es5';
722
+ //console.log('babel_option', babel_option);
723
+ if (babel_option === 'es5') {
724
+ // es5 option
725
+ // not sure if it babels async await though.
726
+ /*
727
+ {
728
+ "presets": [
729
+ "es2015",
730
+ "es2017"
731
+ ],
732
+ "plugins": [
733
+ "transform-runtime"
734
+ ]
735
+ }
736
+ */
737
+ /*
738
+ let res_transform = babel.transform(str_js, {
739
+ //'plugins': ['transform-class']
740
+ 'plugins': ['transform-es2015-object-super', 'transform-es2015-classes', 'remove-comments'],
741
+ 'sourceMaps': 'inline'
742
+ //'plugins': ['transform-es2015-classes']
743
+ // transform-es2015-object-super
744
+ });
745
+ */
746
+ let o_tranform = {
747
+ "presets": [
748
+ "es2015",
749
+ "es2017"
750
+ ],
751
+ "plugins": [
752
+ "transform-runtime"
753
+ ] //,
754
+ //'sourceMaps': 'inline'
755
+ };
756
+ if (options.include_sourcemaps) o_tranform.sourceMaps = 'inline';
757
+
758
+ let res_transform = babel.transform(str_js_no_css, o_tranform);
759
+ let jst_es5 = res_transform.code;
760
+ //let {jst_es5, map, ast} = babel.transform(str_js);
761
+ //console.log('jst_es5.length', jst_es5.length);
762
+ buf_js = Buffer.from(jst_es5);
763
+ } else if (babel_option === 'mini') {
764
+ /*
765
+ let o_transform = {
766
+ presets: ["minify"]//,
767
+ //'sourceMaps': 'inline'
768
+ };
769
+ */
770
+ let o_transform = {
771
+ "presets": [
772
+ ["minify", {
773
+ //"mangle": {
774
+ //"exclude": ["MyCustomError"]
775
+ //},
776
+ //"unsafe": {
777
+ // "typeConstructors": false
778
+ //},
779
+ //"keepFnName": true
780
+ }]
781
+ ],
782
+ "comments": false
783
+ //plugins: ["minify-dead-code-elimination"]
784
+ };
785
+
786
+ if (options.include_sourcemaps) o_transform.sourceMaps = 'inline';
787
+ let res_transform = babel.transform(str_js_no_css, o_transform);
788
+ //let jst_es5 = res_transform.code;
789
+ //let {jst_es5, map, ast} = babel.transform(str_js);
790
+ //console.log('jst_es5.length', jst_es5.length);
791
+ buf_js = Buffer.from(res_transform.code);
792
+ } else {
793
+ buf_js = Buffer.from(str_js_no_css);
794
+ console.log('no babel use');
795
+ }
796
+ var escaped_url = url.replace(/\./g, '☺');
797
+
798
+ //console.log('pre compress buf_js.length', buf_js.length);
799
+ zlib.gzip(buf_js, {level: 9}, (err, buffer) => {
800
+ console.log('deflated buf_js buffer.length', buffer.length);
801
+
802
+ if (err) {
803
+ reject(err);
804
+ } else {
805
+ //
806
+ //buffer.encoding = 'deflate';
807
+ console.log('');
808
+ console.log('escaped_url', escaped_url);
809
+ console.log('url', url);
810
+ console.log('');
811
+
812
+ const rp = this.pool;
813
+ console.log('rp', rp);
814
+ console.log('rp.resource_names', rp.resource_names);
815
+
816
+ const router = rp.get_resource('Site Router');
817
+ console.log('router', router);
818
+
819
+ router.set_route(url, this, (req, res) => {
820
+ console.log('router', [!!req, !!res]);
821
+ });
822
+
823
+ /*
824
+ 'set_route'(str_route, context, fn_handler) {
825
+ */
826
+
827
+ // Setting up routing here?
828
+ // Or returning it to the server?
829
+
830
+ // hack_setup_routing - as in it hacks into another part of the system (which is available)
831
+ // to set up the routing. A more top-down approach would be for the Server module to set the
832
+ // routing up itself.
833
+ // May be nice if components / resources could set up their own routing, with access to the
834
+ // Resource_Pool.
835
+
836
+
837
+
838
+ /*
839
+
840
+ // Would need to check operation of custom paths.
841
+ // Maybe its use was removed...?
842
+ this.custom_paths.set(escaped_url, {
843
+ raw: buf_js,
844
+ gzip: buffer
845
+ });
846
+
847
+ */
848
+
849
+
850
+
851
+ resolve(true);
852
+ }
853
+ });
854
+ }
855
+ })();
856
+ }, callback);
857
+ }
858
+
859
+ /*
860
+ 'set_custom_path'(url, file_path) {
861
+ var escaped_url = url.replace(/\./g, '☺');
862
+ this.custom_paths.set(escaped_url, file_path);
863
+ }
864
+ */
865
+ //
866
+
867
+
868
+ // Not so sure that it should process the request.
869
+ // A more general purpose request handler...?
870
+ // Have more request handling code within one js file, a cenralised portion of the app.
871
+ // And then within those request handlers call on useful abstractions.
872
+
873
+ // Setting up one or more Compilers seems like it would solve some of what this is doing.
874
+ // Even a Compilation_Process object that provides data for monitoring.
875
+ // Published with a Resource_Publisher possibly.
876
+
877
+ // Website_HTTP_Publisher maybe
878
+
879
+ // or just HTTP_Publisher, a Publisher rather than a Resource.
880
+ // HTTP_Publisher, which is focused on publishing HTTP, may be the best option here.
881
+ // Seems best to fix what we have already first though. Could then work on HTTP_Publisher.
882
+
883
+
884
+
885
+ // Website_HTTP_Publisher_Resource possibly?
886
+
887
+ //
888
+
889
+
890
+
891
+ // Site_JavaScript seems more about bundling / compiling rather than serving.
892
+ // Resources could present their data ahead of time / be asked for them and provide it, and the server
893
+ // keeps track of info more centrally.
894
+ //
895
+
896
+
897
+
898
+
899
+ 'process'(req, res) {
900
+ console.log('Site_JavaScript processing req.url', req.url);
901
+ var remoteAddress = req.connection.remoteAddress;
902
+ var custom_paths = this.custom_paths;
903
+ var rurl = req.url.replace(/\./g, '☺');
904
+ var custom_response_entry = custom_paths[rurl];
905
+ var pool = this.pool;
906
+ if (custom_response_entry) {
907
+ const ae = req.headers['accept-encoding'];
908
+ let data_to_serve;
909
+ let o_head = {
910
+ 'Content-Type': 'text/javascript'
911
+ }
912
+ if (ae.includes('gzip')) {
913
+ o_head['Content-Encoding'] = 'gzip';
914
+ data_to_serve = custom_response_entry._.gzip;
915
+ } else {
916
+ data_to_serve = custom_response_entry._.raw;
917
+ }
918
+ res.writeHead(200, o_head);
919
+ res.end(data_to_serve);
920
+ } else {
921
+ //var served_directories = this.served_directories;
922
+ //console.log('served_directories', served_directories);
923
+ var url_parts = url.parse(req.url, true);
924
+ //console.log('url_parts ' + stringify(url_parts));
925
+ var splitPath = url_parts.path.substr(1).split('/');
926
+
927
+ var wildcard_value = req.params.wildcard_value;
928
+ //console.log('*** wildcard_value', wildcard_value);
929
+
930
+ if (wildcard_value == 'web/require.js') {
931
+
932
+ } else {
933
+ var disk_path = path.dirname(require.main.filename) + '/' + 'js/' + wildcard_value;
934
+ var compress = false;
935
+
936
+
937
+ //console.log('disk_path', disk_path);
938
+
939
+ if (compress) {
940
+ throw 'NYI with Babel';
941
+
942
+ } else {
943
+ // try to load it from the project's js path.
944
+ //console.log('disk_path', disk_path);
945
+ var project_js_path = 'js/' + wildcard_value;
946
+ //console.log('project_js_path', project_js_path);
947
+
948
+ fs2.load_file_as_string(disk_path, function (err, str_js) {
949
+ if (err) {
950
+ console.log('error loading from project_js_path: ', project_js_path);
951
+ console.log(err);
952
+ } else {
953
+ // Have loaded the js from the project path, we can serve it.
954
+ console.log('have loaded js');
955
+ // serve the js.
956
+
957
+
958
+ //res.writeHead(200, {'Content-Type': 'text/javascript'});
959
+ // Could possibly stream it from disk instead, that would likely be more efficient.
960
+ console.log('str_js.length', str_js.length);
961
+
962
+
963
+ // use gzip in many cases.
964
+ // want to support that.
965
+
966
+ // a streaming middleware fn could work...?
967
+
968
+ zlib.deflate(str_js, function (err, buffer) {
969
+ console.log('deflated buffer.length', buffer.length);
970
+
971
+
972
+ if (err) throw err;
973
+ res.writeHead(200, {
974
+ 'Content-Encoding': 'deflate',
975
+ 'Content-Type': 'text/javascript'
976
+ });
977
+ res.end(buffer);
978
+ //res.writeHead(200, {'Content-Type': 'text/javascript'});
979
+ //response.end(servableJs);
980
+ //res.end(minified.code);
981
+ });
982
+
983
+
984
+ //response.end(servableJs);
985
+ //res.end(str_js);
986
+ //throw 'stop';
987
+ }
988
+ })
989
+ }
990
+ }
991
+ }
992
+ }
993
+ }
994
+
995
995
  module.exports = Site_JavaScript;