jsgui3-server 0.0.73 → 0.0.77

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 (155) hide show
  1. package/examples/client-side-popup-menu-button.html +93 -93
  2. package/examples/controls/_html-server-color-palette.js +114 -114
  3. package/examples/controls/html-server-combo-box.js +104 -104
  4. package/examples/controls/html-server-list.js +98 -98
  5. package/examples/controls/html-server-popup-menu-button.js +114 -114
  6. package/examples/controls/html-server-start-stop-toggle-button.js +146 -146
  7. package/examples/controls/scs-arrow-button.js +36 -36
  8. package/examples/controls/scs-date-picker.js +157 -157
  9. package/examples/controls/scs-file-browser.js +82 -82
  10. package/examples/controls/scs-item.js +159 -159
  11. package/examples/controls/scs-month-arrow-selector.js +126 -126
  12. package/examples/controls/scs-month-view.js +95 -95
  13. package/examples/controls/scs-start-stop-toggle-button.js +40 -40
  14. package/examples/controls/scs-tree.js +49 -49
  15. package/examples/controls/scs-year-arrow-selector.js +127 -127
  16. package/examples/demos/date-picker.js +119 -119
  17. package/examples/demos/explain-encapsulation.js +9 -9
  18. package/examples/demos/resizing.js +35 -35
  19. package/examples/demos/server_time.js +6 -6
  20. package/examples/demos/square_box.js +324 -324
  21. package/examples/html-rendering.js +20 -20
  22. package/examples/html-server.js +100 -100
  23. package/fs2.js +1836 -1836
  24. package/module.js +21 -21
  25. package/old/single-control-server.js +418 -418
  26. package/package.json +44 -42
  27. package/publishing/function-publisher.js +202 -202
  28. package/publishing/notes.md +5 -5
  29. package/publishing/observable-publisher.js +118 -118
  30. package/publishing/resource-publisher.js +306 -306
  31. package/resources/data-resource.js +104 -104
  32. package/resources/fs-resource.js +148 -148
  33. package/resources/jsbuilder/Abstract_Single_Declaration.js +105 -0
  34. package/resources/jsbuilder/Abstract_Single_Declaration_Sequence.js +43 -0
  35. package/resources/jsbuilder/JS_AST/JS_AST_Abstract_Node.js +62 -0
  36. package/resources/jsbuilder/JS_AST/JS_AST_Abstract_Node_Group.js +42 -0
  37. package/resources/jsbuilder/JS_AST/JS_AST_Group_Shared.js +62 -0
  38. package/resources/jsbuilder/JS_AST/JS_AST_Node.js +94 -0
  39. package/resources/jsbuilder/JS_AST/JS_AST_Node_0-Core.js +228 -0
  40. package/resources/jsbuilder/JS_AST/JS_AST_Node_1-Babel.js +338 -0
  41. package/resources/jsbuilder/JS_AST/JS_AST_Node_10-Changing.js +40 -0
  42. package/resources/jsbuilder/JS_AST/JS_AST_Node_2.1.1-Child.js +97 -0
  43. package/resources/jsbuilder/JS_AST/JS_AST_Node_2.1.2-Parent.js +38 -0
  44. package/resources/jsbuilder/JS_AST/JS_AST_Node_2.1.3-Ancestor.js +62 -0
  45. package/resources/jsbuilder/JS_AST/JS_AST_Node_2.2-Inner.js +44 -0
  46. package/resources/jsbuilder/JS_AST/JS_AST_Node_2.3-All.js +73 -0
  47. package/resources/jsbuilder/JS_AST/JS_AST_Node_2.4-Sibling.js +93 -0
  48. package/resources/jsbuilder/JS_AST/JS_AST_Node_2.5-Available_In_Scope.js +29 -0
  49. package/resources/jsbuilder/JS_AST/JS_AST_Node_2.9-Signature.js +116 -0
  50. package/resources/jsbuilder/JS_AST/JS_AST_Node_3-Basics.js +160 -0
  51. package/resources/jsbuilder/JS_AST/JS_AST_Node_3.0.0-Basics_First.js +179 -0
  52. package/resources/jsbuilder/JS_AST/JS_AST_Node_3.0.1-Basics_Second.js +88 -0
  53. package/resources/jsbuilder/JS_AST/JS_AST_Node_3.0.99-Basics_Last.js +92 -0
  54. package/resources/jsbuilder/JS_AST/JS_AST_Node_3.1-Basics_Each.js +137 -0
  55. package/resources/jsbuilder/JS_AST/JS_AST_Node_3.1.5-Basics_Count.js +74 -0
  56. package/resources/jsbuilder/JS_AST/JS_AST_Node_3.2-Basics_Filter.js +40 -0
  57. package/resources/jsbuilder/JS_AST/JS_AST_Node_3.3-Basics_Collect.js +86 -0
  58. package/resources/jsbuilder/JS_AST/JS_AST_Node_3.4-Basics_Select.js +43 -0
  59. package/resources/jsbuilder/JS_AST/JS_AST_Node_3.5-Basics_Find.js +41 -0
  60. package/resources/jsbuilder/JS_AST/JS_AST_Node_3.6-Basics_Callmap.js +55 -0
  61. package/resources/jsbuilder/JS_AST/JS_AST_Node_4.0-Index_Indexes.js +46 -0
  62. package/resources/jsbuilder/JS_AST/JS_AST_Node_4.1-Index.js +344 -0
  63. package/resources/jsbuilder/JS_AST/JS_AST_Node_5.0-Category.js +39 -0
  64. package/resources/jsbuilder/JS_AST/JS_AST_Node_5.1-Category_Identifier.js +31 -0
  65. package/resources/jsbuilder/JS_AST/JS_AST_Node_5.2-Category_Literal.js +29 -0
  66. package/resources/jsbuilder/JS_AST/JS_AST_Node_5.3-Category_Expression.js +27 -0
  67. package/resources/jsbuilder/JS_AST/JS_AST_Node_5.4-Category_Pattern.js +9 -0
  68. package/resources/jsbuilder/JS_AST/JS_AST_Node_5.5-Category_Declaration.js +44 -0
  69. package/resources/jsbuilder/JS_AST/JS_AST_Node_5.6-Category_Statement.js +22 -0
  70. package/resources/jsbuilder/JS_AST/JS_AST_Node_6.0-Type.js +87 -0
  71. package/resources/jsbuilder/JS_AST/JS_AST_Node_6.1-Type_Class_Declaration.js +9 -0
  72. package/resources/jsbuilder/JS_AST/JS_AST_Node_6.2-Type_Variable_Declaration.js +28 -0
  73. package/resources/jsbuilder/JS_AST/JS_AST_Node_6.3-Type_Variable_Declarator.js +29 -0
  74. package/resources/jsbuilder/JS_AST/JS_AST_Node_7-Query.js +737 -0
  75. package/resources/jsbuilder/JS_AST/JS_AST_Node_8-Features.js +65 -0
  76. package/resources/jsbuilder/JS_AST/JS_AST_Node_9-Planning.js +32 -0
  77. package/resources/jsbuilder/JS_AST/JS_AST_Node_Arrangement.js +15 -0
  78. package/resources/jsbuilder/JS_AST/JS_AST_Node_Feature/JS_AST_Node_Declared_Object.js +306 -0
  79. package/resources/jsbuilder/JS_AST/JS_AST_Node_Feature/JS_AST_Node_Feature.js +78 -0
  80. package/resources/jsbuilder/JS_AST/JS_AST_Node_Feature/JS_AST_Node_Feature_Declaration.js +249 -0
  81. package/resources/jsbuilder/JS_AST/JS_AST_Node_Feature/JS_AST_Node_Feature_Declarator.js +139 -0
  82. package/resources/jsbuilder/JS_AST/JS_AST_Node_Feature/JS_AST_Root_Node_Feature/JS_AST_Root_Node_Feature.js +10 -0
  83. package/resources/jsbuilder/JS_AST/JS_AST_Node_Feature/JS_AST_Root_Node_Feature/JS_AST_Root_Node_Feature_Exported.js +101 -0
  84. package/resources/jsbuilder/JS_AST/JS_AST_Node_Feature/JS_AST_Root_Node_Feature/JS_AST_Root_Node_Feature_Exports.js +61 -0
  85. package/resources/jsbuilder/JS_AST/JS_AST_Node_Feature/JS_AST_Root_Node_Feature/JS_AST_Root_Node_Interpreted.js +180 -0
  86. package/resources/jsbuilder/JS_AST/JS_AST_Node_Feature/JS_AST_Root_Node_Feature/_JSGUI_Root_Node_Interpreted.js +43 -0
  87. package/resources/jsbuilder/JS_AST/JS_AST_Node_Feature/JS_AST_Root_Node_Feature/special_case_objectassign_to_object.js +12 -0
  88. package/resources/jsbuilder/JS_AST/JS_AST_Node_Group.js +35 -0
  89. package/resources/jsbuilder/JS_AST/JS_AST_Operation.js +11 -0
  90. package/resources/jsbuilder/JS_AST/JS_AST_Operation_On_Relationship.js +32 -0
  91. package/resources/jsbuilder/JS_AST/JS_AST_Ordered_Relationship_Node_To_Group.js +38 -0
  92. package/resources/jsbuilder/JS_AST/JS_AST_Ordinal.js +40 -0
  93. package/resources/jsbuilder/JS_AST/JS_AST_Ordinal_Relationship.js +25 -0
  94. package/resources/jsbuilder/JS_AST/JS_AST_Relationship_Node_To_Group.js +201 -0
  95. package/resources/jsbuilder/JS_AST/JS_AST_Relationship_Node_Within_Group_To_Node.js +44 -0
  96. package/resources/jsbuilder/JS_AST/_JS_AST_Node_3.8-Query_Features.js +77 -0
  97. package/resources/jsbuilder/JS_AST/query/all.js +0 -0
  98. package/resources/jsbuilder/JS_AST/query/enable_array_as_queryable.js +228 -0
  99. package/resources/jsbuilder/JS_AST/query/find_object_keys.js +405 -0
  100. package/resources/jsbuilder/JS_AST/query/node_queries.js +9 -0
  101. package/resources/jsbuilder/JS_AST/query/root_queries.js +0 -0
  102. package/resources/jsbuilder/JS_AST/query/root_query_identidy.js +12 -0
  103. package/resources/jsbuilder/JS_AST_Node_Extended/JSGUI_Singular_Declaration.js +86 -0
  104. package/resources/jsbuilder/JS_AST_Node_Extended/JS_AST_Node_Declaration.js +124 -0
  105. package/resources/jsbuilder/JS_AST_Node_Extended/JS_AST_Node_Extended.js +88 -0
  106. package/resources/jsbuilder/JS_AST_Node_Extended/JS_AST_Node_Extended_0-Core.js +11 -0
  107. package/resources/jsbuilder/JS_Builder.js +11 -0
  108. package/resources/jsbuilder/JS_File/Feature/JS_File_Declared_Object.js +32 -0
  109. package/resources/jsbuilder/JS_File/Feature/JS_File_Exported_Object_Info.js +26 -0
  110. package/resources/jsbuilder/JS_File/Feature/JS_File_Exports.js +79 -0
  111. package/resources/jsbuilder/JS_File/Feature/JS_File_Feature.js +18 -0
  112. package/resources/jsbuilder/JS_File/Feature/JS_File_Imported_Object_Info.js +26 -0
  113. package/resources/jsbuilder/JS_File/Feature/JS_File_Imports.js +9 -0
  114. package/resources/jsbuilder/JS_File/JS_File.js +12 -0
  115. package/resources/jsbuilder/JS_File/JS_File_0-Core.js +202 -0
  116. package/resources/jsbuilder/JS_File/JS_File_1-Early_Parse.js +175 -0
  117. package/resources/jsbuilder/JS_File/JS_File_2-Babel.js +81 -0
  118. package/resources/jsbuilder/JS_File/JS_File_3-JS_AST_Node.js +86 -0
  119. package/resources/jsbuilder/JS_File/JS_File_4-Query.js +414 -0
  120. package/resources/jsbuilder/JS_File/JS_File_4.1-Query_Features.js +415 -0
  121. package/resources/jsbuilder/JS_File/JS_File_5-Planning.js +59 -0
  122. package/resources/jsbuilder/JS_File/JS_File_6-Changing.js +24 -0
  123. package/resources/jsbuilder/JS_File/JS_File_Export_Reference.js +12 -0
  124. package/resources/jsbuilder/JS_File/JS_File_Import_Reference.js +24 -0
  125. package/resources/jsbuilder/JS_File/JS_File_Import_References.js +32 -0
  126. package/resources/jsbuilder/JS_File/JS_File_Processor.js +16 -0
  127. package/resources/jsbuilder/JS_File/JS_Files.js +16 -0
  128. package/resources/jsbuilder/Module.js +14 -0
  129. package/resources/jsbuilder/Platform.js +14 -0
  130. package/resources/jsbuilder/Platforms.js +70 -0
  131. package/resources/jsbuilder/Project.js +109 -0
  132. package/resources/jsbuilder/Reference.js +1 -0
  133. package/resources/jsbuilder/Reference_Sequence.js +16 -0
  134. package/resources/jsbuilder/Scope.js +30 -0
  135. package/resources/jsbuilder/Variable_Name_Provider.js +43 -0
  136. package/resources/jsbuilder/_JS_File.js +226 -0
  137. package/resources/jsbuilder/ast_query.js +21 -0
  138. package/resources/jsbuilder/babel/babel_consts.js +150 -0
  139. package/resources/jsbuilder/babel/babel_node_tools.js +542 -0
  140. package/resources/jsbuilder/babel/deep_iterate/deep_iterate_babel.js +604 -0
  141. package/resources/jsbuilder/build.js +16 -0
  142. package/resources/jsbuilder/platform_notes.md +66 -0
  143. package/resources/jsbuilder/test/test_ast_node.js +451 -0
  144. package/resources/jsbuilder/test/test_js_file.js +304 -0
  145. package/resources/jsbuilder/test/test_project.js +157 -0
  146. package/resources/local-server-info-resource.js +78 -78
  147. package/resources/process-js.js +537 -537
  148. package/resources/server-resource-pool.js +84 -84
  149. package/resources/website-css-resource.js +411 -411
  150. package/resources/website-javascript-resource.js +761 -1347
  151. package/resources/website-resource.js +390 -797
  152. package/resources/website-static-html-resource.js +196 -196
  153. package/server.js +170 -170
  154. package/single-control-server.js +398 -398
  155. package/single-page-app.js +129 -129
@@ -1,1348 +1,762 @@
1
- var path = require('path'),
2
- fs = require('fs'),
3
- url = require('url'),
4
- jsgui = require('jsgui3-html'),
5
- os = require('os'),
6
- http = require('http'),
7
- libUrl = require('url'),
8
- Resource = jsgui.Resource,
9
- fs2 = require('../fs2'),
10
- //brotli = require('iltorb').compress,
11
- //UglifyJS = require('uglify-js'),
12
- zlib = require('zlib');
13
-
14
- //fs.createReadStream(filename).pipe(brotli()).pipe(res);
15
-
16
- const fnl = require('fnl');
17
- const prom_or_cb = fnl.prom_or_cb;
18
- const fnlfs = require('fnlfs');
19
-
20
- var stringify = jsgui.stringify,
21
- each = jsgui.each,
22
- arrayify = jsgui.arrayify,
23
- tof = jsgui.tof;
24
- var filter_map_by_regex = jsgui.filter_map_by_regex;
25
- var Class = jsgui.Class,
26
- Data_Object = jsgui.Data_Object,
27
- Enhanced_Data_Object = jsgui.Enhanced_Data_Object;
28
- var fp = jsgui.fp,
29
- is_defined = jsgui.is_defined;
30
- var Collection = jsgui.Collection;
31
- var call_multi = jsgui.call_multi,
32
- get_truth_map_from_arr = jsgui.get_truth_map_from_arr;
33
-
34
- var browserify = require('browserify');
35
- //var zlib = require('zlib');
36
- var util = require('util');
37
-
38
- const babel = require('@babel/core');
39
-
40
- // Extends AutoStart_Resource?
41
- const stream_to_array = require('stream-to-array');
42
-
43
-
44
- const process_js = require('./process-js');
45
- const {analyse_js_doc_formatting, extract_client_js} = process_js;
46
-
47
- // // analyse_js_doc_formatting extract_client_js
48
-
49
-
50
- // This could do with some overhauling.
51
- // Only need to have it do what the applications need from it.
52
- // Building the app may take place automatically elsewhere.
53
-
54
- // May need to change around a fair few references to make it workable.
55
- // May need some more complicated logic to change it to the path for service.
56
-
57
- // This will also be able to be told to serve some particular files from some particular locations.
58
-
59
- // It can have a custom_serving_map.
60
-
61
- // That means that some specific urls that are given as inputs refer to specific files, perhaps with
62
- // relative paths.
63
-
64
- // Since this is a resource, we could wrap that in the .meta object.
65
- // Or just have a custom_paths_map Data_Object.
66
-
67
- // Not so sure about this.
68
- // Processing of files for serving. Maybe some kind of map would work well.
69
- // Now the path name is needed in order to serve various files.
70
- // Some of the files will be useful on the client as well (possibly resources).
71
-
72
- // This file seems too hackily put together.
73
-
74
- // There may be different categories of JavaScript files to serve or not serve.
75
- // We want the app, by default, to serve necessary files for the JSGUI client.
76
- // May get into compressing and browserifying them too.
77
-
78
- // May need some more general purpose resource for dealing with JavaScript files.
79
- // Want to make it easy to serve the client files in its default configuration.
80
-
81
- // Perhaps we could have availability comments within the JavaScript files.
82
- // So whatever folder it is in, we can know it should be served at /js/jsgui-lang-utils or similar.
83
- // However, it may be best to have the client app mirror the structure on the server.
84
- // Could make the app easier to serve, and mean we don't need to transform references.
85
-
86
- // /js/web/jsgui-html-client
87
- // could start with that path.
88
- // most of what we look for will be within web anyway.
89
- // we could also make some other things available from resources.
90
- // not everything in web is suitable for the client anyway.
91
- // many things from outside web will be suitable for the client.
92
-
93
- // Needs to make sure the require.js file gets served.
94
- // Then there will be a bunch of other files that get requested.
95
- // Better to try serving the files in their paths without modification.
96
-
97
- // 21/02/2018 - Need site JavaScript to be able to send a specified Buffer for a specified JS path.
98
-
99
- var serve_js_file_from_disk_updated_refs = function (filePath, response, callback) {
100
- fs2.load_file_as_string(filePath, function (err, data) {
101
- if (err) {
102
- throw err;
103
- } else {
104
- //console.log('');
105
- //console.log('serve_js_file_from_disk_updated_refs filePath ' + filePath);
106
- //console.log('data ' + data);
107
- //var servableJs = updateReferencesForServing(data);
108
- response.writeHead(200, {
109
- 'Content-Type': 'text/javascript'
110
- });
111
- //response.end(servableJs);
112
- response.end(data);
113
- }
114
- });
115
- }
116
-
117
- var check_served_directories_for_requested_file = function (arr_served_paths, split_path_within_js, callback) {
118
- //console.log('check_served_directories_for_requested_file');
119
- //console.log('split_path_within_js ' + stringify(split_path_within_js));
120
- //console.log('arr_served_paths ' + stringify(arr_served_paths));
121
- // use call_multi.
122
- // maybe we get a result from them all.
123
-
124
- var fns = [
125
-
126
- ]
127
- var checkPath = function (path, callback) {
128
- // check to see if an existing file matches up with the path that is requested.
129
- // so, from that path, we use the split_path_within_js for the rest of the file path.
130
- // then we check if such a (JS) file exists.
131
- }
132
- // fns.push([fs2.load_file_as_string, [source_path_item], function(err, res_loaded) {
133
-
134
- // Not so sure I can use the exists function like this...
135
- var reconstitutedPathWithinJs = split_path_within_js.join('/');
136
- var firstFoundPath;
137
- each(arr_served_paths, function (i, fsPath) {
138
- fns.push([function (callback) {
139
- var checkingPath = fsPath + '/' + reconstitutedPathWithinJs;
140
- fs.exists(checkingPath, function (exists) {
141
- //console.log('cb fsPath ' + checkingPath + ' exists ' + exists)
142
- if (exists & !firstFoundPath) {
143
- firstFoundPath = checkingPath;
144
- }
145
- callback(null, exists);
146
- })
147
- },
148
- []
149
- ]);
150
- });
151
- call_multi(fns, function (err, res_multi) {
152
- if (err) {
153
- console.log('err ' + err);
154
- throw 'stop';
155
- } else {
156
- //console.log('res_multi ' + stringify(res_multi));
157
- //throw 'stop';
158
-
159
- if (firstFoundPath) {
160
- callback(null, firstFoundPath);
161
- } else {
162
- callback(null, null);
163
- }
164
- }
165
- });
166
- }
167
-
168
- // A way of serving a file so that it includes custom code.
169
- // Or have a standard client template that is easy to serve.
170
-
171
- // Maybe do more with custom controls, such as custom page controls.
172
- // Those page controls would know which control types are within them.
173
- // That info could then be used to write JS code that sets up the references on the client.
174
-
175
- // Possibly this should have its own routing tree to connect paths with js files?
176
- // Need to set up custom paths.
177
-
178
- class Site_JavaScript extends Resource {
179
- //'fields': {
180
- // 'custom_paths': 'data_object'
181
- //},
182
- constructor(spec) {
183
- super(spec);
184
- //this.meta.set('custom_paths', new Data_Object({}));
185
- this.custom_paths = new Data_Object({});
186
- // Those are custom file paths.
187
- // could have a collection of directories, indexed by name, that get served.
188
- // Index the collection by string value?
189
- //this.meta.set('served_directories', new Collection({'index_by': 'name'}));
190
- this.served_directories = new Collection({
191
- 'index_by': 'name'
192
- });
193
- }
194
- 'start'(callback) {
195
- //console.log('Site_JavaScript start');
196
- var build_on_start = this.build_on_start;
197
- if (build_on_start) {
198
- this.build_client(function (err, res_build) {
199
- if (err) {
200
- callback(err)
201
- } else {
202
- callback(null, true);
203
- }
204
- })
205
- } else {
206
- callback(null, true);
207
- }
208
- // Let's have it build the client-side code.
209
- // Need the options to ignore various files, as well as to include the source maps in the output.
210
- }
211
- // build client, and serve it from one particular place
212
- // do so with a promise.
213
- // serve_package
214
- // Need to bundle / build together a package from the disk path, then serve it under a URL route.
215
-
216
- // want to give it the file to build.
217
- // There will be a variety of jsgui packages.
218
-
219
- 'build_client'(callback) {
220
- // Need the reference relative to the application directory.
221
- //var path = __dirname + '/js/app.js';
222
- var appDir = path.dirname(require.main.filename);
223
- //console.log('appDir', appDir);
224
- var app_path = appDir + '/js/app.js';
225
- var app_bundle_path = appDir + '/js/app-bundle.js';
226
- var wstream = fs.createWriteStream(app_bundle_path);
227
- var b = browserify();
228
- //b.require(app_path, {
229
- // entry: true,
230
- // debug: true
231
- //});
232
- b.add(app_path);
233
- //console.log('app_path', app_path);
234
- //console.log('pre browserify bundle');
235
- //b.bundle().pipe(process.stdout);
236
-
237
- b.bundle().pipe(wstream);
238
-
239
- wstream.end = function (data) {
240
- //console.log('file bundle write complete');
241
- callback(null, app_bundle_path);
242
- // no more writes after end
243
- // emit "close" (optional)
244
- }
245
- }
246
- // Will could serve all jsgui code?
247
- // May be better not to allow server-side code to be read on the client.
248
- // Could have specific directories within jsgui that get served to the client.
249
-
250
- 'serve_directory'(path) {
251
- // Serves that directory, as any files given in that directory can be served from /js
252
- var served_directories = this.served_directories;
253
- //console.log('served_directories ' + stringify(served_directories));
254
- //served_directories.push(path);
255
- served_directories.push({
256
- 'name': path
257
- });
258
- //console.log('served_directories ' + stringify(served_directories));
259
- //console.log('path ' + path);
260
- //throw 'stop';
261
- }
262
- // Want to be able to serve specific js files.
263
- // Need better syntax than this:
264
- // //site_js.meta.set('custom_paths.js/modernizr-latest☺js', './client/js/modernizr-latest.js');
265
- // .set_custom_path(url, fileName)
266
- // would need to appear in the main routing tree perhaps?
267
-
268
- // However, may set it using a buffer, not a file path.
269
- // The app-bundle may be created on application start.
270
- // options...
271
- // but serving a package when we have the path will be a little different.
272
- // However, loading it from disk allows for content replacement better.
273
- // However, supply the package ourselves, and its fine.
274
-
275
- 'serve_package'(url, js_package, options = {}, callback) {
276
- console.log('serve_package', url, js_package);
277
- console.log('js_package', js_package);
278
- console.log('typeof js_package', typeof js_package);
279
- let tjp = typeof js_package;
280
- return this.serve_package_from_path(url, require.resolve(js_package), options, callback);
281
- }
282
-
283
- 'package'(js_file_path, options = {}, callback) {
284
-
285
- let a = arguments;
286
- if (typeof a[2] === 'function') {
287
- callback = a[2];
288
- options = {
289
- //'babel': 'mini',
290
- 'include_sourcemaps': true
291
- };
292
- }
293
-
294
- return prom_or_cb((resolve, reject) => {
295
- (async () => {
296
- // options
297
- // may want a replacement within the client-side code.
298
- // Can we call browserify on the code string?
299
- // Creating a modified copy of the file would do.
300
- // Load the file, modify it, save it under a different name
301
-
302
- let s = new require('stream').Readable(),
303
- path = require('path').parse(js_file_path);
304
-
305
- let fileContents = await fnlfs.load(js_file_path);
306
- //console.log('1) fileContents.length', fileContents.length);
307
- // are there any replacements to do?
308
- // options.replacements
309
-
310
- if (options.js_mode === 'debug') {
311
- options.include_sourcemaps = true;
312
- }
313
- if (options.js_mode === 'compress' || options.js_mode === 'mini') {
314
- options.include_sourcemaps = false;
315
- options.babel = 'mini';
316
- }
317
-
318
- //console.log('options.babel', options.babel);
319
-
320
- if (options.replace) {
321
- let s_file_contents = fileContents.toString();
322
- //console.log('s_file_contents', s_file_contents);
323
- each(options.replace, (text, key) => {
324
- //console.log('key', key);
325
- //console.log('text', text);
326
- let running_fn = '(' + text + ')();'
327
- //console.log('running_fn', running_fn);
328
- s_file_contents = s_file_contents.split(key).join(running_fn);
329
- })
330
- fileContents = Buffer.from(s_file_contents);
331
- //console.log('2) fileContents.length', fileContents.length);
332
- }
333
- // Then we can replace some of the file contents with specific content given when we tall it to serve that file.
334
- // We have a space for client-side activation.
335
- s.push(fileContents);
336
- s.push(null);
337
-
338
- //let include_sourcemaps = true;
339
-
340
- let b = browserify(s, {
341
- basedir: path.dir,
342
- //builtins: false,
343
- builtins: ['buffer'],
344
- 'debug': options.include_sourcemaps
345
- });
346
-
347
- let parts = await stream_to_array(b.bundle());
348
-
349
- const buffers = parts
350
- .map(part => util.isBuffer(part) ? part : Buffer.from(part));
351
- let buf_js = Buffer.concat(buffers);
352
- let str_js = buf_js.toString();
353
-
354
- let babel_option = options.babel
355
- //console.log('babel_option', babel_option);
356
- if (babel_option === 'es5') {
357
-
358
- let o_tranform = {
359
- "presets": [
360
- "es2015",
361
- "es2017"
362
- ],
363
- "plugins": [
364
- "transform-runtime"
365
- ] //,
366
- //'sourceMaps': 'inline'
367
- };
368
-
369
- if (options.include_sourcemaps) o_tranform.sourceMaps = 'inline';
370
- let res_transform = babel.transform(str_js, o_tranform);
371
- //console.log('res_transform', res_transform);
372
- //console.log('Object.keys(res_transform)', Object.keys(res_transform));
373
- let jst_es5 = res_transform.code;
374
- //let {jst_es5, map, ast} = babel.transform(str_js);
375
- //console.log('jst_es5.length', jst_es5.length);
376
- buf_js = Buffer.from(jst_es5);
377
- } else if (babel_option === 'mini') {
378
- /*
379
- let o_transform = {
380
- presets: ["minify"]//,
381
- //'sourceMaps': 'inline'
382
- };
383
- */
384
- let o_transform = {
385
- "presets": [
386
- ["minify", {
387
- //"mangle": {
388
- //"exclude": ["MyCustomError"]
389
- //},
390
- //"unsafe": {
391
- // "typeConstructors": false
392
- //},
393
- //"keepFnName": true
394
- }]
395
- ],
396
- //plugins: ["minify-dead-code-elimination"]
397
- };
398
- if (options.include_sourcemaps) o_transform.sourceMaps = 'inline';
399
-
400
- let res_transform = babel.transform(str_js, o_transform);
401
- buf_js = Buffer.from(res_transform.code);
402
- } else {
403
- buf_js = Buffer.from(str_js);
404
- }
405
- //var escaped_url = url.replace(/\./g, '☺');
406
- //console.log('pre brot buf_js.length', buf_js.length);
407
- //console.trace();
408
- /*
409
- brotli(buf_js, (err, buffer) => {
410
- console.log('* brotli deflated buffer.length', buffer.length);
411
- if (err) {
412
- reject(err);
413
- } else {
414
- //
415
- buffer.encoding = 'br';
416
- //this.custom_paths.set(escaped_url, buffer);
417
- resolve(buffer);
418
- }
419
- });
420
- */
421
- resolve(buf_js);
422
- })();
423
- }, callback);
424
- }
425
-
426
- // Can't use this for scs any longer I think. Seems we can :)
427
- // May be worth separating out different preparation and compilation functions.
428
-
429
-
430
- // prepare_root_js
431
- // ?compile root js?
432
-
433
- // Moving code out of the resource itself.
434
- // have a directory called js_process?
435
- // a bunch of functions available in process_js?
436
-
437
-
438
-
439
-
440
-
441
- // Different preparation / compilation phases.
442
-
443
-
444
- // Separating out client js, (server js), css
445
- // from one file
446
-
447
- // process single source js file
448
- // splitting for client
449
-
450
-
451
-
452
-
453
- // Then browserify compilation - bringing all the files.
454
-
455
-
456
-
457
-
458
-
459
- 'serve_package_from_path'(url, js_file_path, options = {}, callback) {
460
- //console.log('serve_package_from_path', url, js_file_path);
461
- // js_mode option may need to be used.
462
-
463
-
464
- // Make it an observable?
465
- // Raise an event when we have the browserified fill js file (uncompressed?).
466
-
467
-
468
- let a = arguments;
469
- if (typeof a[2] === 'function') {
470
- callback = a[2];
471
- options = {
472
- //'babel': 'mini',
473
- 'include_sourcemaps': false
474
- };
475
- }
476
- let serve_raw = options.serve_raw || options.raw;
477
- let accepts_brotli = false;
478
-
479
- // Need to come up with compressed versions.
480
- // An object that provides different versions.
481
-
482
-
483
- return prom_or_cb((resolve, reject) => {
484
- (async () => {
485
- // options
486
- // may want a replacement within the client-side code.
487
- // Can we call browserify on the code string?
488
- // Creating a modified copy of the file would do.
489
- // Load the file, modify it, save it under a different name
490
-
491
- let s = new require('stream').Readable(),
492
- path = require('path').parse(js_file_path);
493
-
494
- let fileContents = await fnlfs.load(js_file_path);
495
- //console.log('1) fileContents.length', fileContents.length);
496
- // are there any replacements to do?
497
- // options.replacements
498
- if (options.js_mode === 'debug') {
499
- options.include_sourcemaps = true;
500
- }
501
- if (options.js_mode === 'compress' || options.js_mode === 'mini') {
502
- options.include_sourcemaps = false;
503
- options.babel = 'mini';
504
- }
505
- //console.log('options.babel', options.babel);
506
-
507
- // Likely to remove this....
508
- if (options.replace) {
509
- let s_file_contents = fileContents.toString();
510
- //console.log('s_file_contents', s_file_contents);
511
- each(options.replace, (text, key) => {
512
- //console.log('key', key);
513
- //console.log('text', text);
514
- let running_fn = '(' + text + ')();'
515
- //console.log('running_fn', running_fn);
516
- s_file_contents = s_file_contents.split(key).join(running_fn);
517
- })
518
- fileContents = Buffer.from(s_file_contents);
519
- //console.log('2) fileContents.length', fileContents.length);
520
- }
521
-
522
- // Then we can replace some of the file contents with specific content given when we tall it to serve that file.
523
- // We have a space for client-side activation.
524
- // want a raw option with no browserify.
525
- //console.log('serve_raw', serve_raw);
526
- if (serve_raw) {
527
- var escaped_url = url.replace(/\./g, '☺');
528
- this.custom_paths.set(escaped_url, fileContents);
529
- } else {
530
- // Early filtering / transformation to the client CSS.
531
- // Need to transform a single file, such as in a single page (single file) app, making it work as client-side code.
532
-
533
- // May be nice to move filtering / recompilation like this to a more general file / module?
534
- // Not for the moment, this is quite specific.
535
- // If it would help later on, then do it.
536
-
537
-
538
- // Will be very useful for making apps with just one code file.
539
- // The server-side code gets removed during this compilation.
540
-
541
-
542
- // find indentation scheme.
543
- // and then can find the indentation level on each line.
544
-
545
- // and find the line separation character.
546
- // could count \r\n as well as \n by itself.
547
-
548
-
549
-
550
- // get the line separator
551
- // get the indentation character or sequence (ie 4 spaces)
552
-
553
-
554
-
555
-
556
- const formatting_info = analyse_js_doc_formatting(fileContents.toString());
557
- //console.log('formatting_info', formatting_info);
558
-
559
- const {arr_lines, line_break, indentation_analysis} = formatting_info;
560
- const {parsed_lines, str_indentation} = indentation_analysis;
561
-
562
- //console.log('parsed_lines', parsed_lines);
563
- //console.log('indentation_analysis', indentation_analysis);
564
-
565
- const client_root_js = extract_client_js(formatting_info);
566
-
567
- //let client_js = arr_client_js_lines.join('\n');
568
-
569
-
570
-
571
- fnlfs.save('d:\\saved.js', client_root_js);;
572
-
573
-
574
-
575
- // Then can analyse the lines to see what type of lines they are.
576
- // Comment, server, isomorphic, client
577
-
578
- // Not so sure there will even be client only code apart from code in the filke, or it will be encapsulated deeper in activate.
579
-
580
-
581
- //
582
-
583
-
584
-
585
-
586
-
587
-
588
-
589
- //throw 'stop';
590
-
591
- // &#13 -- Carriage return.
592
- // Maybe there is a prob with windows files using 2 characters for new lines.
593
-
594
-
595
-
596
-
597
-
598
-
599
- //const no_server_js = transform_ensure_client_side_js(fileContents.toString());
600
- //console.log('no_server_js', no_server_js);
601
-
602
- s.push(client_root_js);
603
- s.push(null);
604
- //let include_sourcemaps = true;
605
-
606
- // Filtering out server-side code.
607
-
608
- // recompile js module(s).
609
-
610
- // for the moment keep that functionality here as functions.
611
-
612
-
613
- const lines_file_content = [];
614
-
615
-
616
-
617
-
618
-
619
-
620
-
621
-
622
- // Don't always include sourcemap?
623
- // Separate out the sourcemap?
624
-
625
- let b = browserify(s, {
626
- basedir: path.dir,
627
- //builtins: false,
628
- builtins: ['buffer'],
629
- 'debug': options.include_sourcemaps
630
- });
631
- // Prefer the idea of sending a stream to browserify.
632
- let parts = await stream_to_array(b.bundle());
633
- /*
634
- var b = browserify([js_file_path], {
635
- 'debug': true
636
- });
637
- */
638
- //let parts = await stream_to_array(b.bundle());
639
- const buffers = parts
640
- .map(part => util.isBuffer(part) ? part : Buffer.from(part));
641
- let buf_js = Buffer.concat(buffers);
642
- let str_js = buf_js.toString();
643
-
644
- // the part prior to '//# sourceMappingURL' is the code itself.
645
- // we could parse it into AST?
646
- // and find all controls with .css properties?
647
-
648
- // could do a more rudimentary dearch on each line of code.
649
- // That makes most sense.
650
- // And can use the info to recompile the js code, with the CSS parts removed.
651
-
652
- // This js resource could raise an event saying it's got the extracted / removed CSS.
653
- // Makes sense for the js resource to handle it.
654
-
655
- // This will make it a lot easier to edit the CSS alongside the relevant controls.
656
- // Controls could possibly have different themes that operate too.
657
- // Could make a theme-name css class, such as 'dark', and have css for specific themes declared in the control CSS / SASS.
658
-
659
- let str_js_code = str_js;
660
- let str_sourcemap;
661
-
662
- let pos_prior_sourcemap = str_js.indexOf('//# sourceMappingURL');
663
- if (pos_prior_sourcemap > -1) {
664
- str_js_code = str_js.substr(0, pos_prior_sourcemap);
665
- str_sourcemap = str_js.substr(pos_prior_sourcemap);
666
- }
667
-
668
- // can add the same sourcemap back?
669
- // Would prob be OK with the CSS code removed.
670
-
671
-
672
-
673
-
674
-
675
- // extract css function...
676
- // extract css lines
677
- // returns css, non-css
678
-
679
- // filter_extract_css
680
-
681
- const js_remove_comments = (str_js_code) => {
682
- // comments will be OK within a string.
683
-
684
- // Be able to work out what type of code we are in at all points...?
685
- // Non-tokenising scanner...?
686
-
687
- // Knowing whether or not */ // /* is within a string is important - because if it's in a string its not a comment.
688
- // 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.
689
-
690
- // Could split it into lines, spot whenever a line starts a comment...?
691
- }
692
-
693
- //const filter_js_remove_server_js
694
- // compile_client_js_from_server_js
695
- // is_server_js
696
-
697
-
698
-
699
-
700
- const filter_js_extract_control_css = (str_js_code) => {
701
- // res = [css, js_no_css]
702
- // Split the js lines.
703
-
704
- const s_js = str_js_code.split('\n');
705
-
706
- // Mark the relative lines.
707
- // Could remove comment sections...
708
- // Spot comments begginning, comments ending.
709
- // Then could remove all comments from here, so we don't make use of any commented code.
710
-
711
- // My own (basic) code to strip comments?
712
- // Stripping out commented CSS is relatively important
713
- // And replace some specific comments?
714
- // Could go through the whole js string, char by char, removing comments.
715
- // Make it so that all css that gets used has no indent...
716
- // That could work.
717
-
718
- // Any line with .css = funny quote
719
-
720
- let within_class_css = false;
721
- const control_css_lines = [];
722
- const js_non_css_lines = [];
723
- // and the non-css lines.
724
- // And need to look for its stop.
725
- // And leave the first and last line out of the css.
726
- each(s_js, js_line => {
727
- let placed_js_line = false;
728
- const pos_class_css_begin = js_line.indexOf('.css = `');
729
- // if its 0
730
-
731
- if (pos_class_css_begin > -1) {
732
- //console.log('js_line', js_line);
733
- within_class_css = true;
734
- }
735
- // Put empty lines (back) into the js array?
736
-
737
- if (within_class_css) {
738
- //console.log('js_line', js_line);
739
-
740
- const pos_control_css_end = js_line.indexOf('`;');
741
- //console.log('pos_control_css_end', pos_control_css_end);
742
- if (pos_control_css_end > -1) {
743
- within_class_css = false;
744
- } else {
745
- if (pos_class_css_begin > -1) {
746
-
747
- } else {
748
- control_css_lines.push(js_line);
749
- }
750
-
751
- }
752
- } else {
753
- js_non_css_lines.push(js_line);
754
- placed_js_line = true;
755
- }
756
-
757
- if (!placed_js_line) {
758
- js_non_css_lines.push('');
759
- }
760
- //let is_control_css_start = js_line.indexOf()
761
-
762
- if (control_css_lines.length > 200) throw 'stop';
763
-
764
- })
765
- return [control_css_lines.join('\n'), js_non_css_lines.join('\n')];
766
- }
767
-
768
- let [str_css, str_js_no_css] = filter_js_extract_control_css(str_js_code);
769
-
770
- // Add the sourcemaps back? Its working.
771
-
772
- if (str_sourcemap) {
773
- str_js_no_css = str_js_no_css + str_sourcemap;
774
- }
775
-
776
- //console.log('str_css.length', str_css.length);
777
- //console.log('str_js_no_css.length', str_js_no_css.length);
778
- //console.log('str_css', str_css);
779
-
780
- this.raise('extracted-controls-css', str_css);
781
- // And the server / website resource can listen for these, and then give the data to the css.
782
-
783
-
784
- // string of extracted Control css.
785
-
786
- // Very nice... looks like the css and js separation and compilation is working OK.
787
-
788
- // Work with the JS when serving the JS.
789
- // Could raise an event from the resource saying that we have the extracted / compiled CSS...?
790
-
791
-
792
-
793
-
794
-
795
-
796
-
797
- //throw 'stop';
798
-
799
-
800
-
801
-
802
-
803
-
804
-
805
-
806
-
807
-
808
-
809
-
810
-
811
-
812
- //await fnlfs.save('D:\\saved_no_css.js', str_js_no_css);
813
-
814
- // Then with str_js....
815
- // That is the part where we can find / remove the css parts.
816
-
817
- // Use a JS parser?
818
- // Is that overkill?
819
-
820
- // can we separate statements by ';'?
821
- // then go through them, looking for the css.
822
-
823
- // or look for Class.css = {..
824
-
825
- //console.log('str_js.length', str_js.length);
826
-
827
- //console.log('buf_js.length', buf_js.length);
828
- //console.log('str_js.length', str_js.length);
829
- // options.babel === true
830
-
831
- let babel_option = options.babel;
832
-
833
- //console.log('babel_option', babel_option);
834
-
835
- //babel_option = 'es5';
836
- //console.log('babel_option', babel_option);
837
- if (babel_option === 'es5') {
838
- // es5 option
839
- // not sure if it babels async await though.
840
- /*
841
- {
842
- "presets": [
843
- "es2015",
844
- "es2017"
845
- ],
846
- "plugins": [
847
- "transform-runtime"
848
- ]
849
- }
850
- */
851
- /*
852
- let res_transform = babel.transform(str_js, {
853
- //'plugins': ['transform-class']
854
- 'plugins': ['transform-es2015-object-super', 'transform-es2015-classes', 'remove-comments'],
855
- 'sourceMaps': 'inline'
856
- //'plugins': ['transform-es2015-classes']
857
- // transform-es2015-object-super
858
- });
859
- */
860
- let o_tranform = {
861
- "presets": [
862
- "es2015",
863
- "es2017"
864
- ],
865
- "plugins": [
866
- "transform-runtime"
867
- ] //,
868
- //'sourceMaps': 'inline'
869
- };
870
- if (options.include_sourcemaps) o_tranform.sourceMaps = 'inline';
871
-
872
- let res_transform = babel.transform(str_js_no_css, o_tranform);
873
- //console.log('res_transform', res_transform);
874
- //console.log('Object.keys(res_transform)', Object.keys(res_transform));
875
- let jst_es5 = res_transform.code;
876
- //let {jst_es5, map, ast} = babel.transform(str_js);
877
- //console.log('jst_es5.length', jst_es5.length);
878
- buf_js = Buffer.from(jst_es5);
879
- } else if (babel_option === 'mini') {
880
- /*
881
- let o_transform = {
882
- presets: ["minify"]//,
883
- //'sourceMaps': 'inline'
884
- };
885
- */
886
- let o_transform = {
887
- "presets": [
888
- ["minify", {
889
- //"mangle": {
890
- //"exclude": ["MyCustomError"]
891
- //},
892
- //"unsafe": {
893
- // "typeConstructors": false
894
- //},
895
- //"keepFnName": true
896
- }]
897
- ],
898
- "comments": false
899
- //plugins: ["minify-dead-code-elimination"]
900
- };
901
-
902
- if (options.include_sourcemaps) o_transform.sourceMaps = 'inline';
903
- let res_transform = babel.transform(str_js_no_css, o_transform);
904
- //let jst_es5 = res_transform.code;
905
- //let {jst_es5, map, ast} = babel.transform(str_js);
906
- //console.log('jst_es5.length', jst_es5.length);
907
- buf_js = Buffer.from(res_transform.code);
908
- /*
909
- {
910
- "presets": [["minify", {
911
- "mangle": {
912
- "exclude": ["MyCustomError"]
913
- },
914
- "unsafe": {
915
- "typeConstructors": false
916
- },
917
- "keepFnName": true
918
- }]]
919
- }
920
- */
921
- //
922
-
923
- } else {
924
- buf_js = Buffer.from(str_js_no_css);
925
- }
926
- var escaped_url = url.replace(/\./g, '☺');
927
-
928
- //console.log('pre compress buf_js.length', buf_js.length);
929
- zlib.gzip(buf_js, {level: 9}, (err, buffer) => {
930
- //console.log('deflated buffer.length', buffer.length);
931
-
932
- if (err) {
933
- reject(err);
934
- } else {
935
- //
936
- //buffer.encoding = 'deflate';
937
-
938
- this.custom_paths.set(escaped_url, {
939
- raw: buf_js,
940
- gzip: buffer
941
- });
942
-
943
- resolve(true);
944
- }
945
- //res.writeHead(200, {
946
- // 'Content-Encoding': 'deflate',
947
- // 'Content-Type': 'text/javascript'
948
- //});
949
- //res.end(buffer);
950
- //res.writeHead(200, {'Content-Type': 'text/javascript'});
951
- //response.end(servableJs);
952
- //res.end(minified.code);
953
- });
954
-
955
- // uglify and remove comments?
956
-
957
- // Coming up with different built / compressed versions makes sense.
958
-
959
- // Need to be able to return uncompressed if client cannot accept compressed data.
960
-
961
- //throw 'stop';
962
- // Then run it through babel to change the ES6 classes into older style.
963
-
964
- // then need to serve it under url
965
-
966
-
967
-
968
-
969
- //console.trace();
970
-
971
-
972
- // want it compressed with a few different ways.
973
-
974
- // want to compress to gzip by default
975
-
976
- // Will change the way that .custom paths works.
977
-
978
- // need to come up with both gzip and brotli compressed.
979
- // well, could ignore brotli for the moment
980
- // could also have them become ready.
981
-
982
-
983
-
984
-
985
-
986
- /*
987
-
988
- if (accepts_brotli) {
989
-
990
- brotli(buf_js, (err, buffer) => {
991
- console.log('* brotli deflated buffer.length', buffer.length);
992
-
993
- if (err) {
994
- reject(err);
995
- } else {
996
-
997
- //
998
-
999
-
1000
- buffer.encoding = 'br';
1001
-
1002
- this.custom_paths.set(escaped_url, buffer);
1003
-
1004
- resolve(true);
1005
- }
1006
- //res.writeHead(200, {
1007
- // 'Content-Encoding': 'deflate',
1008
- // 'Content-Type': 'text/javascript'
1009
- //});
1010
- //res.end(buffer);
1011
- //res.writeHead(200, {'Content-Type': 'text/javascript'});
1012
- //response.end(servableJs);
1013
- //res.end(minified.code);
1014
- });
1015
- } else {
1016
-
1017
- }
1018
- */
1019
- }
1020
- /*
1021
- */
1022
- //
1023
- // then need to store that compiled file at that URL.
1024
- })();
1025
- }, callback);
1026
- }
1027
-
1028
- 'set_custom_path'(url, file_path) {
1029
- // But change the URL to have a smiley face instead of fullstops
1030
- //console.log('url', url);
1031
- var escaped_url = url.replace(/\./g, '☺');
1032
- //console.log('escaped_url', escaped_url);
1033
- //this.meta.set('custom_paths.' + escaped_url, file_path);
1034
- //var custom_paths = this.meta.get('custom_paths');
1035
- //console.log('custom_paths', custom_paths);
1036
- this.custom_paths.set(escaped_url, file_path);
1037
- }
1038
-
1039
- //
1040
-
1041
- 'process'(req, res) {
1042
- //console.log('Site_JavaScript processing req.url', req.url);
1043
- var remoteAddress = req.connection.remoteAddress;
1044
- //console.log('remoteAddress ' + remoteAddress);
1045
-
1046
- // Need to be able to get the resource pool from this resource.
1047
- // It routes http calls to particular resources, and resources in the same pool make use of each
1048
-
1049
-
1050
- // Could have specific processing for the app bundle
1051
- // Use browserify to put the bundle into one JavaScript file.
1052
-
1053
- // Need some default client-side bundle too.
1054
- // With jsgui and the various controls.
1055
- //
1056
-
1057
- // Maybe a jsgui-client dependancy would do the job best.
1058
- // Contains HTML and some client-specific tech.
1059
-
1060
- // It should be able to serve jsgui2-client to the client easily, as a default.
1061
-
1062
-
1063
-
1064
-
1065
-
1066
-
1067
-
1068
-
1069
-
1070
- // other.
1071
-
1072
-
1073
- // /js/...js
1074
-
1075
- // //site_js.meta.set('custom_paths.js/app☺js', './client/js/app.js');
1076
-
1077
- // http://192.168.2.3/js/app.js
1078
-
1079
- // need to serve /js/app.js.
1080
- // however the Website Resource should set this up.
1081
-
1082
-
1083
- // the site's static file resources.
1084
- // a file server that serves the files with their mime types.
1085
- // nice to have encapsulation of this because it can do compression.
1086
-
1087
- // It may be useful to get given the rest of the URL.
1088
-
1089
-
1090
- var custom_paths = this.custom_paths;
1091
-
1092
- //console.log('custom_paths', custom_paths);
1093
- //throw 'stop'
1094
- //console.log('tof custom_paths', tof(custom_paths));
1095
-
1096
- var rurl = req.url.replace(/\./g, '☺');
1097
-
1098
- //if (rurl.substr(0, 1) == '/') rurl = rurl.substr(1);
1099
-
1100
-
1101
- //console.log('rurl', rurl);
1102
-
1103
- var custom_response_entry = custom_paths[rurl];
1104
- //console.log('custom_response_entry', custom_response_entry);
1105
- //console.log('custom_response_entry.encoding', custom_response_entry.encoding);
1106
-
1107
- // hmmmm get not working right?
1108
-
1109
-
1110
- //console.log('custom_response_entry', custom_response_entry);
1111
-
1112
- var pool = this.pool;
1113
- if (custom_response_entry) {
1114
-
1115
- //let t = tof(custom_response_entry._);
1116
-
1117
- //console.log('req.headers', req.headers);
1118
- const ae = req.headers['accept-encoding'];
1119
- let data_to_serve;
1120
- let o_head = {
1121
- 'Content-Type': 'text/javascript'
1122
- }
1123
- if (ae.includes('gzip')) {
1124
- o_head['Content-Encoding'] = 'gzip';
1125
- data_to_serve = custom_response_entry._.gzip;
1126
- } else {
1127
- data_to_serve = custom_response_entry._.raw;
1128
- }
1129
- res.writeHead(200, o_head);
1130
- res.end(data_to_serve);
1131
-
1132
-
1133
-
1134
-
1135
- //throw 'stop';
1136
-
1137
-
1138
- // it's an object.
1139
-
1140
- // ._.raw, ._.gzip
1141
-
1142
-
1143
-
1144
- /*
1145
- console.log('t', t);
1146
- if (t === 'buffer') {
1147
- //console.log('sending js');
1148
- let o_head = {
1149
- 'Content-Type': 'text/javascript'
1150
- }
1151
- //console.log('custom_response_entry._.encoding', custom_response_entry._.encoding);
1152
- if (custom_response_entry._.encoding) {
1153
-
1154
- o_head['Content-Encoding'] = custom_response_entry._.encoding;
1155
- }
1156
-
1157
- res.writeHead(200, o_head);
1158
- //response.end(servableJs);
1159
- //console.log('custom_response_entry._', custom_response_entry._);
1160
- //console.log('custom_response_entry._.length', custom_response_entry._.length);
1161
- res.end(custom_response_entry._);
1162
- //console.log('response js written');
1163
-
1164
- } else {
1165
- var file_path = custom_response_entry.value();
1166
- //console.log('file_path', file_path);
1167
-
1168
- //throw 'stop';
1169
- //var disk_path = '../../ws/js/' + wildcard_value;
1170
- fs2.load_file_as_string(file_path, function (err, data) {
1171
- if (err) {
1172
- throw err;
1173
- } else {
1174
- res.writeHead(200, {
1175
- 'Content-Type': 'text/javascript'
1176
- });
1177
- //response.end(servableJs);
1178
- res.end(data);
1179
- }
1180
- });
1181
- }
1182
- */
1183
-
1184
- //
1185
- //console.trace();
1186
- //throw 'stop';
1187
-
1188
- // we serve the file pointed to.
1189
-
1190
- } else {
1191
-
1192
- var served_directories = this.served_directories;
1193
-
1194
- console.log('served_directories', served_directories);
1195
-
1196
- //console.trace();
1197
- //throw 'stop';
1198
-
1199
-
1200
- var url_parts = url.parse(req.url, true);
1201
- //console.log('url_parts ' + stringify(url_parts));
1202
- var splitPath = url_parts.path.substr(1).split('/');
1203
-
1204
- var wildcard_value = req.params.wildcard_value;
1205
- //console.log('*** wildcard_value', wildcard_value);
1206
-
1207
- if (wildcard_value == 'web/require.js') {
1208
-
1209
- } else {
1210
- // Can get the path on disk...
1211
- //console.log('wildcard_value', wildcard_value);
1212
- // Best to check the app's directory.
1213
- // We probably won't need to be serving the whole jsgui framework from here.
1214
- // It can be built and put in the app's js directory.
1215
- // Could also make it buildable on the server?
1216
- //var disk_path = './js/' + wildcard_value;
1217
-
1218
- //console.log('__dirname', __dirname);
1219
- //console.log('require.main.filename', require.main.filename);
1220
- // Would be good to uglify and gzip what gets served.
1221
-
1222
- var disk_path = path.dirname(require.main.filename) + '/' + 'js/' + wildcard_value;
1223
-
1224
-
1225
-
1226
- var compress = false;
1227
-
1228
-
1229
- //console.log('disk_path', disk_path);
1230
-
1231
- if (compress) {
1232
- throw 'NYI with Babel';
1233
-
1234
- // Uglify removed. Using babel instead.
1235
- /*
1236
-
1237
- fs2.load_file_as_string(disk_path, function (err, data) {
1238
- if (err) {
1239
- throw err;
1240
- } else {
1241
- // And gzipped too...
1242
- var minified = UglifyJS.minify(data, {
1243
- fromString: true
1244
- });
1245
- //console.log('minified', minified);
1246
- zlib.deflate(minified.code, function (err, buffer) {
1247
- if (err) throw err;
1248
- res.writeHead(200, {
1249
- 'Content-Encoding': 'deflate',
1250
- 'Content-Type': 'text/javascript'
1251
- });
1252
- res.end(buffer);
1253
-
1254
- //res.writeHead(200, {'Content-Type': 'text/javascript'});
1255
- //response.end(servableJs);
1256
- //res.end(minified.code);
1257
- });
1258
- }
1259
- });
1260
-
1261
- */
1262
- } else {
1263
- // try to load it from the project's js path.
1264
- //console.log('disk_path', disk_path);
1265
- var project_js_path = 'js/' + wildcard_value;
1266
- //console.log('project_js_path', project_js_path);
1267
-
1268
- fs2.load_file_as_string(disk_path, function (err, str_js) {
1269
- if (err) {
1270
- console.log('error loading from project_js_path: ', project_js_path);
1271
- console.log(err);
1272
-
1273
- /*
1274
- var b = browserify();
1275
- b.add(require.resolve(('jsgui2-client')));
1276
-
1277
- //b.bundle().pipe(process.stdout);
1278
- res.writeHead(200, {'Content-Type': 'text/javascript'});
1279
-
1280
- var string = '';
1281
- var stream = b.bundle();
1282
- stream.on('readable',function(buffer){
1283
- var part = buffer.read().toString();
1284
- string += part;
1285
- console.log('stream data ' + part);
1286
- });
1287
-
1288
- stream.on('end',function(){
1289
- console.log('final output ' + string);
1290
-
1291
- console.log('string.length', string.length);
1292
- res.end(string);
1293
- });
1294
-
1295
- //b.bundle().pipe(res);
1296
-
1297
- //res.pipe(b.bundle());
1298
- */
1299
-
1300
- //setTimeout(function() {
1301
- //throw err;
1302
- //}, 5000)
1303
-
1304
-
1305
- } else {
1306
- // Have loaded the js from the project path, we can serve it.
1307
- console.log('have loaded js');
1308
- // serve the js.
1309
-
1310
-
1311
- //res.writeHead(200, {'Content-Type': 'text/javascript'});
1312
- // Could possibly stream it from disk instead, that would likely be more efficient.
1313
- console.log('str_js.length', str_js.length);
1314
-
1315
-
1316
- // use gzip in many cases.
1317
- // want to support that.
1318
-
1319
- // a streaming middleware fn could work...?
1320
-
1321
- zlib.deflate(str_js, function (err, buffer) {
1322
- console.log('deflated buffer.length', buffer.length);
1323
-
1324
-
1325
- if (err) throw err;
1326
- res.writeHead(200, {
1327
- 'Content-Encoding': 'deflate',
1328
- 'Content-Type': 'text/javascript'
1329
- });
1330
- res.end(buffer);
1331
- //res.writeHead(200, {'Content-Type': 'text/javascript'});
1332
- //response.end(servableJs);
1333
- //res.end(minified.code);
1334
- });
1335
-
1336
-
1337
- //response.end(servableJs);
1338
- //res.end(str_js);
1339
- //throw 'stop';
1340
- }
1341
- })
1342
- }
1343
- }
1344
- }
1345
- }
1346
- }
1347
-
1
+ // Nov 2020:
2
+ // Need to overhaul this, bugs are on the client, need to be careful and clear about what will be sent to the client.
3
+ // 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?
4
+ // Build up a huge JS AST of the whole thing.
5
+ // Build up a system that understands what code does (to an extent) and how it fits together.
6
+
7
+ // Could do my own application-level compression.
8
+
9
+ // JS-Build.
10
+ // Could identify the resources / files used in the site?
11
+
12
+ // Load all the files in, made into a function that will return what the module exports.
13
+ // Or not...
14
+ // Make the module into just the code, store it as a variable, then be able to build
15
+
16
+ // Would make quite a difference - with a lot of localised references made possible.
17
+ //
18
+
19
+
20
+ // JS_File
21
+ // Be able to get transformed versions of it
22
+ // JS_File_
23
+
24
+
25
+
26
+
27
+
28
+
29
+
30
+
31
+ var path = require('path'),
32
+ fs = require('fs'),
33
+ url = require('url'),
34
+ jsgui = require('jsgui3-html'),
35
+ os = require('os'),
36
+ http = require('http'),
37
+ libUrl = require('url'),
38
+ Resource = jsgui.Resource,
39
+ fs2 = require('../fs2'),
40
+ //brotli = require('iltorb').compress,
41
+ //UglifyJS = require('uglify-js'),
42
+ zlib = require('zlib');
43
+
44
+ //fs.createReadStream(filename).pipe(brotli()).pipe(res);
45
+
46
+ const fnl = require('fnl');
47
+ const prom_or_cb = fnl.prom_or_cb;
48
+ const fnlfs = require('fnlfs');
49
+
50
+ var stringify = jsgui.stringify,
51
+ each = jsgui.each,
52
+ arrayify = jsgui.arrayify,
53
+ tof = jsgui.tof;
54
+ var filter_map_by_regex = jsgui.filter_map_by_regex;
55
+ var Class = jsgui.Class,
56
+ Data_Object = jsgui.Data_Object,
57
+ Enhanced_Data_Object = jsgui.Enhanced_Data_Object;
58
+ var fp = jsgui.fp,
59
+ is_defined = jsgui.is_defined;
60
+ var Collection = jsgui.Collection;
61
+ var call_multi = jsgui.call_multi,
62
+ get_truth_map_from_arr = jsgui.get_truth_map_from_arr;
63
+
64
+ var browserify = require('browserify');
65
+ //var zlib = require('zlib');
66
+ var util = require('util');
67
+
68
+ const babel = require('@babel/core');
69
+
70
+ // Extends AutoStart_Resource?
71
+ const stream_to_array = require('stream-to-array');
72
+
73
+
74
+ const process_js = require('./process-js');
75
+ const {analyse_js_doc_formatting, extract_client_js} = process_js;
76
+
77
+ var serve_js_file_from_disk_updated_refs = function (filePath, response, callback) {
78
+ fs2.load_file_as_string(filePath, function (err, data) {
79
+ if (err) {
80
+ throw err;
81
+ } else {
82
+ //console.log('');
83
+ //console.log('serve_js_file_from_disk_updated_refs filePath ' + filePath);
84
+ //console.log('data ' + data);
85
+ //var servableJs = updateReferencesForServing(data);
86
+ response.writeHead(200, {
87
+ 'Content-Type': 'text/javascript'
88
+ });
89
+ //response.end(servableJs);
90
+ response.end(data);
91
+ }
92
+ });
93
+ }
94
+
95
+ var check_served_directories_for_requested_file = function (arr_served_paths, split_path_within_js, callback) {
96
+
97
+ var fns = [
98
+
99
+ ]
100
+ var checkPath = function (path, callback) {
101
+ // check to see if an existing file matches up with the path that is requested.
102
+ // so, from that path, we use the split_path_within_js for the rest of the file path.
103
+ // then we check if such a (JS) file exists.
104
+ }
105
+ // fns.push([fs2.load_file_as_string, [source_path_item], function(err, res_loaded) {
106
+
107
+ // Not so sure I can use the exists function like this...
108
+ var reconstitutedPathWithinJs = split_path_within_js.join('/');
109
+ var firstFoundPath;
110
+ each(arr_served_paths, function (i, fsPath) {
111
+ fns.push([function (callback) {
112
+ var checkingPath = fsPath + '/' + reconstitutedPathWithinJs;
113
+ fs.exists(checkingPath, function (exists) {
114
+ //console.log('cb fsPath ' + checkingPath + ' exists ' + exists)
115
+ if (exists & !firstFoundPath) {
116
+ firstFoundPath = checkingPath;
117
+ }
118
+ callback(null, exists);
119
+ })
120
+ },
121
+ []
122
+ ]);
123
+ });
124
+ call_multi(fns, function (err, res_multi) {
125
+ if (err) {
126
+ console.log('err ' + err);
127
+ throw 'stop';
128
+ } else {
129
+ //console.log('res_multi ' + stringify(res_multi));
130
+ //throw 'stop';
131
+
132
+ if (firstFoundPath) {
133
+ callback(null, firstFoundPath);
134
+ } else {
135
+ callback(null, null);
136
+ }
137
+ }
138
+ });
139
+ }
140
+
141
+ // A way of serving a file so that it includes custom code.
142
+ // Or have a standard client template that is easy to serve.
143
+
144
+ // Maybe do more with custom controls, such as custom page controls.
145
+ // Those page controls would know which control types are within them.
146
+ // That info could then be used to write JS code that sets up the references on the client.
147
+
148
+ // Possibly this should have its own routing tree to connect paths with js files?
149
+ // Need to set up custom paths.
150
+
151
+ class Site_JavaScript extends Resource {
152
+ //'fields': {
153
+ // 'custom_paths': 'data_object'
154
+ //},
155
+ constructor(spec) {
156
+ super(spec);
157
+ //this.meta.set('custom_paths', new Data_Object({}));
158
+ this.custom_paths = new Data_Object({});
159
+ // Those are custom file paths.
160
+ // could have a collection of directories, indexed by name, that get served.
161
+ // Index the collection by string value?
162
+ //this.meta.set('served_directories', new Collection({'index_by': 'name'}));
163
+ this.served_directories = new Collection({
164
+ 'index_by': 'name'
165
+ });
166
+ }
167
+ 'start'(callback) {
168
+ //console.log('Site_JavaScript start');
169
+ var build_on_start = this.build_on_start;
170
+ if (build_on_start) {
171
+ this.build_client(function (err, res_build) {
172
+ if (err) {
173
+ callback(err)
174
+ } else {
175
+ callback(null, true);
176
+ }
177
+ })
178
+ } else {
179
+ callback(null, true);
180
+ }
181
+ // Let's have it build the client-side code.
182
+ // Need the options to ignore various files, as well as to include the source maps in the output.
183
+ }
184
+ // build client, and serve it from one particular place
185
+ // do so with a promise.
186
+ // serve_package
187
+ // Need to bundle / build together a package from the disk path, then serve it under a URL route.
188
+
189
+ // want to give it the file to build.
190
+ // There will be a variety of jsgui packages.
191
+
192
+ 'build_client'(callback) {
193
+ // Need the reference relative to the application directory.
194
+ //var path = __dirname + '/js/app.js';
195
+ var appDir = path.dirname(require.main.filename);
196
+ //console.log('appDir', appDir);
197
+ var app_path = appDir + '/js/app.js';
198
+ var app_bundle_path = appDir + '/js/app-bundle.js';
199
+ var wstream = fs.createWriteStream(app_bundle_path);
200
+ var b = browserify();
201
+ //b.require(app_path, {
202
+ // entry: true,
203
+ // debug: true
204
+ //});
205
+ b.add(app_path);
206
+ //console.log('app_path', app_path);
207
+ //console.log('pre browserify bundle');
208
+ //b.bundle().pipe(process.stdout);
209
+
210
+ b.bundle().pipe(wstream);
211
+
212
+ wstream.end = function (data) {
213
+ //console.log('file bundle write complete');
214
+ callback(null, app_bundle_path);
215
+ // no more writes after end
216
+ // emit "close" (optional)
217
+ }
218
+ }
219
+ // Will could serve all jsgui code?
220
+ // May be better not to allow server-side code to be read on the client.
221
+ // Could have specific directories within jsgui that get served to the client.
222
+
223
+ 'serve_directory'(path) {
224
+ // Serves that directory, as any files given in that directory can be served from /js
225
+ var served_directories = this.served_directories;
226
+ //console.log('served_directories ' + stringify(served_directories));
227
+ //served_directories.push(path);
228
+ served_directories.push({
229
+ 'name': path
230
+ });
231
+ //console.log('served_directories ' + stringify(served_directories));
232
+ //console.log('path ' + path);
233
+ //throw 'stop';
234
+ }
235
+ 'serve_package'(url, js_package, options = {}, callback) {
236
+ console.log('serve_package', url, js_package);
237
+ console.log('js_package', js_package);
238
+ console.log('typeof js_package', typeof js_package);
239
+ let tjp = typeof js_package;
240
+ return this.serve_package_from_path(url, require.resolve(js_package), options, callback);
241
+ }
242
+
243
+ 'package'(js_file_path, options = {}, callback) {
244
+
245
+ let a = arguments;
246
+ if (typeof a[2] === 'function') {
247
+ callback = a[2];
248
+ options = {
249
+ //'babel': 'mini',
250
+ 'include_sourcemaps': true
251
+ };
252
+ }
253
+
254
+ return prom_or_cb((resolve, reject) => {
255
+ (async () => {
256
+ // options
257
+ // may want a replacement within the client-side code.
258
+ // Can we call browserify on the code string?
259
+ // Creating a modified copy of the file would do.
260
+ // Load the file, modify it, save it under a different name
261
+
262
+ let s = new require('stream').Readable(),
263
+ path = require('path').parse(js_file_path);
264
+
265
+ let fileContents = await fnlfs.load(js_file_path);
266
+ //console.log('1) fileContents.length', fileContents.length);
267
+ // are there any replacements to do?
268
+ // options.replacements
269
+
270
+ if (options.js_mode === 'debug') {
271
+ options.include_sourcemaps = true;
272
+ }
273
+ if (options.js_mode === 'compress' || options.js_mode === 'mini') {
274
+ options.include_sourcemaps = false;
275
+ options.babel = 'mini';
276
+ }
277
+
278
+ //console.log('options.babel', options.babel);
279
+
280
+ if (options.replace) {
281
+ let s_file_contents = fileContents.toString();
282
+ //console.log('s_file_contents', s_file_contents);
283
+ each(options.replace, (text, key) => {
284
+ //console.log('key', key);
285
+ //console.log('text', text);
286
+ let running_fn = '(' + text + ')();'
287
+ //console.log('running_fn', running_fn);
288
+ s_file_contents = s_file_contents.split(key).join(running_fn);
289
+ })
290
+ fileContents = Buffer.from(s_file_contents);
291
+ //console.log('2) fileContents.length', fileContents.length);
292
+ }
293
+ // Then we can replace some of the file contents with specific content given when we tall it to serve that file.
294
+ // We have a space for client-side activation.
295
+ s.push(fileContents);
296
+ s.push(null);
297
+
298
+ //let include_sourcemaps = true;
299
+
300
+ let b = browserify(s, {
301
+ basedir: path.dir,
302
+ //builtins: false,
303
+ builtins: ['buffer', 'process'],
304
+ 'debug': options.include_sourcemaps
305
+ });
306
+
307
+ let parts = await stream_to_array(b.bundle());
308
+
309
+ const buffers = parts
310
+ .map(part => util.isBuffer(part) ? part : Buffer.from(part));
311
+ let buf_js = Buffer.concat(buffers);
312
+ let str_js = buf_js.toString();
313
+
314
+ let babel_option = options.babel
315
+ //console.log('babel_option', babel_option);
316
+ if (babel_option === 'es5') {
317
+
318
+ let o_tranform = {
319
+ "presets": [
320
+ "es2015",
321
+ "es2017"
322
+ ],
323
+ "plugins": [
324
+ "transform-runtime"
325
+ ] //,
326
+ //'sourceMaps': 'inline'
327
+ };
328
+
329
+ if (options.include_sourcemaps) o_tranform.sourceMaps = 'inline';
330
+ let res_transform = babel.transform(str_js, o_tranform);
331
+ //console.log('res_transform', res_transform);
332
+ //console.log('Object.keys(res_transform)', Object.keys(res_transform));
333
+ let jst_es5 = res_transform.code;
334
+ //let {jst_es5, map, ast} = babel.transform(str_js);
335
+ //console.log('jst_es5.length', jst_es5.length);
336
+ buf_js = Buffer.from(jst_es5);
337
+ } else if (babel_option === 'mini') {
338
+ /*
339
+ let o_transform = {
340
+ presets: ["minify"]//,
341
+ //'sourceMaps': 'inline'
342
+ };
343
+ */
344
+ let o_transform = {
345
+ "presets": [
346
+ ["minify", {
347
+ //"mangle": {
348
+ //"exclude": ["MyCustomError"]
349
+ //},
350
+ //"unsafe": {
351
+ // "typeConstructors": false
352
+ //},
353
+ //"keepFnName": true
354
+ }]
355
+ ],
356
+ //plugins: ["minify-dead-code-elimination"]
357
+ };
358
+ if (options.include_sourcemaps) o_transform.sourceMaps = 'inline';
359
+
360
+ let res_transform = babel.transform(str_js, o_transform);
361
+ buf_js = Buffer.from(res_transform.code);
362
+ } else {
363
+ buf_js = Buffer.from(str_js);
364
+ }
365
+ resolve(buf_js);
366
+ })();
367
+ }, callback);
368
+ }
369
+ 'serve_package_from_path'(url, js_file_path, options = {}, callback) {
370
+ //console.log('serve_package_from_path', url, js_file_path);
371
+ // js_mode option may need to be used.
372
+
373
+
374
+ // Make it an observable?
375
+ // Raise an event when we have the browserified fill js file (uncompressed?).
376
+
377
+
378
+ let a = arguments;
379
+ if (typeof a[2] === 'function') {
380
+ callback = a[2];
381
+ options = {
382
+ //'babel': 'mini',
383
+ 'include_sourcemaps': false
384
+ };
385
+ }
386
+ let serve_raw = options.serve_raw || options.raw;
387
+ let accepts_brotli = false;
388
+
389
+ // Need to come up with compressed versions.
390
+ // An object that provides different versions.
391
+
392
+
393
+ return prom_or_cb((resolve, reject) => {
394
+ (async () => {
395
+ // options
396
+ // may want a replacement within the client-side code.
397
+ // Can we call browserify on the code string?
398
+ // Creating a modified copy of the file would do.
399
+ // Load the file, modify it, save it under a different name
400
+
401
+ let s = new require('stream').Readable(),
402
+ path = require('path').parse(js_file_path);
403
+
404
+ let fileContents = await fnlfs.load(js_file_path);
405
+ //console.log('1) fileContents.length', fileContents.length);
406
+ // are there any replacements to do?
407
+ // options.replacements
408
+ if (options.js_mode === 'debug') {
409
+ options.include_sourcemaps = true;
410
+ }
411
+ if (options.js_mode === 'compress' || options.js_mode === 'mini') {
412
+ options.include_sourcemaps = false;
413
+ options.babel = 'mini';
414
+ }
415
+ //console.log('options.babel', options.babel);
416
+
417
+ // Likely to remove this....
418
+ if (options.replace) {
419
+ let s_file_contents = fileContents.toString();
420
+ //console.log('s_file_contents', s_file_contents);
421
+ each(options.replace, (text, key) => {
422
+ //console.log('key', key);
423
+ //console.log('text', text);
424
+ let running_fn = '(' + text + ')();'
425
+ //console.log('running_fn', running_fn);
426
+ s_file_contents = s_file_contents.split(key).join(running_fn);
427
+ })
428
+ fileContents = Buffer.from(s_file_contents);
429
+ //console.log('2) fileContents.length', fileContents.length);
430
+ }
431
+
432
+ // Then we can replace some of the file contents with specific content given when we tall it to serve that file.
433
+ // We have a space for client-side activation.
434
+ // want a raw option with no browserify.
435
+ //console.log('serve_raw', serve_raw);
436
+ if (serve_raw) {
437
+ var escaped_url = url.replace(/\./g, '☺');
438
+ this.custom_paths.set(escaped_url, fileContents);
439
+ } else {
440
+ const formatting_info = analyse_js_doc_formatting(fileContents.toString());
441
+ //console.log('formatting_info', formatting_info);
442
+
443
+ const {arr_lines, line_break, indentation_analysis} = formatting_info;
444
+ const {parsed_lines, str_indentation} = indentation_analysis;
445
+ const client_root_js = extract_client_js(formatting_info);
446
+ fnlfs.save('d:\\saved.js', client_root_js);
447
+ s.push(client_root_js);
448
+ s.push(null);
449
+ const lines_file_content = [];
450
+
451
+ // Don't always include sourcemap?
452
+ // Separate out the sourcemap?
453
+
454
+ let b = browserify(s, {
455
+ basedir: path.dir,
456
+ //builtins: false,
457
+ builtins: ['buffer'],
458
+ 'debug': options.include_sourcemaps
459
+ });
460
+ // Prefer the idea of sending a stream to browserify.
461
+ let parts = await stream_to_array(b.bundle());
462
+ /*
463
+ var b = browserify([js_file_path], {
464
+ 'debug': true
465
+ });
466
+ */
467
+ //let parts = await stream_to_array(b.bundle());
468
+ const buffers = parts
469
+ .map(part => util.isBuffer(part) ? part : Buffer.from(part));
470
+ let buf_js = Buffer.concat(buffers);
471
+ let str_js = buf_js.toString();
472
+ let str_js_code = str_js;
473
+ let str_sourcemap;
474
+
475
+ let pos_prior_sourcemap = str_js.indexOf('//# sourceMappingURL');
476
+ if (pos_prior_sourcemap > -1) {
477
+ str_js_code = str_js.substr(0, pos_prior_sourcemap);
478
+ str_sourcemap = str_js.substr(pos_prior_sourcemap);
479
+ }
480
+ // filter_extract_css
481
+
482
+ const js_remove_comments = (str_js_code) => {
483
+ // comments will be OK within a string.
484
+
485
+ // Be able to work out what type of code we are in at all points...?
486
+ // Non-tokenising scanner...?
487
+
488
+ // Knowing whether or not */ // /* is within a string is important - because if it's in a string its not a comment.
489
+ // 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.
490
+
491
+ // Could split it into lines, spot whenever a line starts a comment...?
492
+ }
493
+
494
+ const filter_js_extract_control_css = (str_js_code) => {
495
+ // res = [css, js_no_css]
496
+ // Split the js lines.
497
+
498
+ const s_js = str_js_code.split('\n');
499
+ let within_class_css = false;
500
+ const control_css_lines = [];
501
+ const js_non_css_lines = [];
502
+ // and the non-css lines.
503
+ // And need to look for its stop.
504
+ // And leave the first and last line out of the css.
505
+ each(s_js, js_line => {
506
+ let placed_js_line = false;
507
+ const pos_class_css_begin = js_line.indexOf('.css = `');
508
+ // if its 0
509
+
510
+ if (pos_class_css_begin > -1) {
511
+ //console.log('js_line', js_line);
512
+ within_class_css = true;
513
+ }
514
+ // Put empty lines (back) into the js array?
515
+
516
+ if (within_class_css) {
517
+ //console.log('js_line', js_line);
518
+
519
+ const pos_control_css_end = js_line.indexOf('`;');
520
+ //console.log('pos_control_css_end', pos_control_css_end);
521
+ if (pos_control_css_end > -1) {
522
+ within_class_css = false;
523
+ } else {
524
+ if (pos_class_css_begin > -1) {
525
+
526
+ } else {
527
+ control_css_lines.push(js_line);
528
+ }
529
+
530
+ }
531
+ } else {
532
+ js_non_css_lines.push(js_line);
533
+ placed_js_line = true;
534
+ }
535
+
536
+ if (!placed_js_line) {
537
+ js_non_css_lines.push('');
538
+ }
539
+ //let is_control_css_start = js_line.indexOf()
540
+
541
+ if (control_css_lines.length > 200) throw 'stop';
542
+
543
+ })
544
+ return [control_css_lines.join('\n'), js_non_css_lines.join('\n')];
545
+ }
546
+
547
+ let [str_css, str_js_no_css] = filter_js_extract_control_css(str_js_code);
548
+
549
+ // Add the sourcemaps back? Its working.
550
+
551
+ if (str_sourcemap) {
552
+ str_js_no_css = str_js_no_css + str_sourcemap;
553
+ }
554
+ this.raise('extracted-controls-css', str_css);
555
+ let babel_option = options.babel;
556
+
557
+ console.log('babel_option', babel_option);
558
+ //throw 'stop';
559
+ //babel_option = 'es5';
560
+ //console.log('babel_option', babel_option);
561
+ if (babel_option === 'es5') {
562
+ // es5 option
563
+ // not sure if it babels async await though.
564
+ /*
565
+ {
566
+ "presets": [
567
+ "es2015",
568
+ "es2017"
569
+ ],
570
+ "plugins": [
571
+ "transform-runtime"
572
+ ]
573
+ }
574
+ */
575
+ /*
576
+ let res_transform = babel.transform(str_js, {
577
+ //'plugins': ['transform-class']
578
+ 'plugins': ['transform-es2015-object-super', 'transform-es2015-classes', 'remove-comments'],
579
+ 'sourceMaps': 'inline'
580
+ //'plugins': ['transform-es2015-classes']
581
+ // transform-es2015-object-super
582
+ });
583
+ */
584
+ let o_tranform = {
585
+ "presets": [
586
+ "es2015",
587
+ "es2017"
588
+ ],
589
+ "plugins": [
590
+ "transform-runtime"
591
+ ] //,
592
+ //'sourceMaps': 'inline'
593
+ };
594
+ if (options.include_sourcemaps) o_tranform.sourceMaps = 'inline';
595
+
596
+ let res_transform = babel.transform(str_js_no_css, o_tranform);
597
+ let jst_es5 = res_transform.code;
598
+ //let {jst_es5, map, ast} = babel.transform(str_js);
599
+ //console.log('jst_es5.length', jst_es5.length);
600
+ buf_js = Buffer.from(jst_es5);
601
+ } else if (babel_option === 'mini') {
602
+ /*
603
+ let o_transform = {
604
+ presets: ["minify"]//,
605
+ //'sourceMaps': 'inline'
606
+ };
607
+ */
608
+ let o_transform = {
609
+ "presets": [
610
+ ["minify", {
611
+ //"mangle": {
612
+ //"exclude": ["MyCustomError"]
613
+ //},
614
+ //"unsafe": {
615
+ // "typeConstructors": false
616
+ //},
617
+ //"keepFnName": true
618
+ }]
619
+ ],
620
+ "comments": false
621
+ //plugins: ["minify-dead-code-elimination"]
622
+ };
623
+
624
+ if (options.include_sourcemaps) o_transform.sourceMaps = 'inline';
625
+ let res_transform = babel.transform(str_js_no_css, o_transform);
626
+ //let jst_es5 = res_transform.code;
627
+ //let {jst_es5, map, ast} = babel.transform(str_js);
628
+ //console.log('jst_es5.length', jst_es5.length);
629
+ buf_js = Buffer.from(res_transform.code);
630
+ } else {
631
+ buf_js = Buffer.from(str_js_no_css);
632
+ console.log('no babel use');
633
+ }
634
+ var escaped_url = url.replace(/\./g, '☺');
635
+
636
+ //console.log('pre compress buf_js.length', buf_js.length);
637
+ zlib.gzip(buf_js, {level: 9}, (err, buffer) => {
638
+ //console.log('deflated buffer.length', buffer.length);
639
+
640
+ if (err) {
641
+ reject(err);
642
+ } else {
643
+ //
644
+ //buffer.encoding = 'deflate';
645
+
646
+ this.custom_paths.set(escaped_url, {
647
+ raw: buf_js,
648
+ gzip: buffer
649
+ });
650
+
651
+ resolve(true);
652
+ }
653
+ });
654
+ }
655
+ })();
656
+ }, callback);
657
+ }
658
+
659
+ 'set_custom_path'(url, file_path) {
660
+ var escaped_url = url.replace(/\./g, '☺');
661
+ this.custom_paths.set(escaped_url, file_path);
662
+ }
663
+
664
+ //
665
+
666
+ 'process'(req, res) {
667
+ //console.log('Site_JavaScript processing req.url', req.url);
668
+ var remoteAddress = req.connection.remoteAddress;
669
+ var custom_paths = this.custom_paths;
670
+ var rurl = req.url.replace(/\./g, '☺');
671
+ var custom_response_entry = custom_paths[rurl];
672
+ var pool = this.pool;
673
+ if (custom_response_entry) {
674
+ const ae = req.headers['accept-encoding'];
675
+ let data_to_serve;
676
+ let o_head = {
677
+ 'Content-Type': 'text/javascript'
678
+ }
679
+ if (ae.includes('gzip')) {
680
+ o_head['Content-Encoding'] = 'gzip';
681
+ data_to_serve = custom_response_entry._.gzip;
682
+ } else {
683
+ data_to_serve = custom_response_entry._.raw;
684
+ }
685
+ res.writeHead(200, o_head);
686
+ res.end(data_to_serve);
687
+ } else {
688
+ var served_directories = this.served_directories;
689
+ console.log('served_directories', served_directories);
690
+ var url_parts = url.parse(req.url, true);
691
+ //console.log('url_parts ' + stringify(url_parts));
692
+ var splitPath = url_parts.path.substr(1).split('/');
693
+
694
+ var wildcard_value = req.params.wildcard_value;
695
+ //console.log('*** wildcard_value', wildcard_value);
696
+
697
+ if (wildcard_value == 'web/require.js') {
698
+
699
+ } else {
700
+ var disk_path = path.dirname(require.main.filename) + '/' + 'js/' + wildcard_value;
701
+ var compress = false;
702
+
703
+
704
+ //console.log('disk_path', disk_path);
705
+
706
+ if (compress) {
707
+ throw 'NYI with Babel';
708
+
709
+ } else {
710
+ // try to load it from the project's js path.
711
+ //console.log('disk_path', disk_path);
712
+ var project_js_path = 'js/' + wildcard_value;
713
+ //console.log('project_js_path', project_js_path);
714
+
715
+ fs2.load_file_as_string(disk_path, function (err, str_js) {
716
+ if (err) {
717
+ console.log('error loading from project_js_path: ', project_js_path);
718
+ console.log(err);
719
+ } else {
720
+ // Have loaded the js from the project path, we can serve it.
721
+ console.log('have loaded js');
722
+ // serve the js.
723
+
724
+
725
+ //res.writeHead(200, {'Content-Type': 'text/javascript'});
726
+ // Could possibly stream it from disk instead, that would likely be more efficient.
727
+ console.log('str_js.length', str_js.length);
728
+
729
+
730
+ // use gzip in many cases.
731
+ // want to support that.
732
+
733
+ // a streaming middleware fn could work...?
734
+
735
+ zlib.deflate(str_js, function (err, buffer) {
736
+ console.log('deflated buffer.length', buffer.length);
737
+
738
+
739
+ if (err) throw err;
740
+ res.writeHead(200, {
741
+ 'Content-Encoding': 'deflate',
742
+ 'Content-Type': 'text/javascript'
743
+ });
744
+ res.end(buffer);
745
+ //res.writeHead(200, {'Content-Type': 'text/javascript'});
746
+ //response.end(servableJs);
747
+ //res.end(minified.code);
748
+ });
749
+
750
+
751
+ //response.end(servableJs);
752
+ //res.end(str_js);
753
+ //throw 'stop';
754
+ }
755
+ })
756
+ }
757
+ }
758
+ }
759
+ }
760
+ }
761
+
1348
762
  module.exports = Site_JavaScript;