svelteesp32 1.16.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cppCode.js CHANGED
@@ -120,212 +120,6 @@ extern "C" void __attribute__((weak)) {{definePrefix}}_onFileServed(const char*
120
120
  const psychicTemplate = `
121
121
  //engine: PsychicHttpServer
122
122
  //config: {{{config}}}
123
- //You should use server.config.max_uri_handlers = {{fileCount}}; or higher value to proper handles all files
124
- {{#if created }}
125
- //created: {{now}}
126
- {{/if}}
127
- //
128
- ${commonHeaderSection}
129
-
130
- //
131
- #include <Arduino.h>
132
- #include <PsychicHttp.h>
133
- #include <PsychicHttpsServer.h>
134
-
135
- //
136
- ${dataArraysSection(false)}
137
-
138
- //
139
- ${etagArraysSection}
140
-
141
- //
142
- ${manifestSection}
143
-
144
- //
145
- ${hookSection}
146
-
147
- //
148
- // Http Handlers
149
- void {{methodName}}(PsychicHttpServer * server) {
150
- {{#each sources}}
151
- //
152
- // {{this.filename}}
153
- {{#if this.isDefault}}{{#unless ../basePath}}server->defaultEndpoint = {{/unless}}{{/if}}server->on("{{../basePath}}/{{this.filename}}", HTTP_GET, [](PsychicRequest * request) {
154
-
155
- {{#switch ../etag}}
156
- {{#case "true"}}
157
- if (request->hasHeader("If-None-Match") && request->header("If-None-Match").equals(etag_{{this.dataname}})) {
158
- PsychicResponse response304(request);
159
- response304.setCode(304);
160
- {{../definePrefix}}_onFileServed("{{../basePath}}/{{this.filename}}", 304);
161
- return response304.send();
162
- }
163
- {{/case}}
164
- {{#case "compiler"}}
165
- #ifdef {{../definePrefix}}_ENABLE_ETAG
166
- if (request->hasHeader("If-None-Match") && request->header("If-None-Match").equals(etag_{{this.dataname}})) {
167
- PsychicResponse response304(request);
168
- response304.setCode(304);
169
- {{../definePrefix}}_onFileServed("{{../basePath}}/{{this.filename}}", 304);
170
- return response304.send();
171
- }
172
- #endif
173
- {{/case}}
174
- {{/switch}}
175
-
176
- PsychicResponse response(request);
177
- response.setContentType("{{this.mime}}");
178
-
179
- {{#switch ../gzip}}
180
- {{#case "true"}}
181
- {{#if this.isGzip}}
182
- response.addHeader("Content-Encoding", "gzip");
183
- {{/if}}
184
- {{/case}}
185
- {{#case "compiler"}}
186
- {{#if this.isGzip}}
187
- #ifdef {{../definePrefix}}_ENABLE_GZIP
188
- response.addHeader("Content-Encoding", "gzip");
189
- #endif
190
- {{/if}}
191
- {{/case}}
192
- {{/switch}}
193
-
194
- {{#switch ../etag}}
195
- {{#case "true"}}
196
- {{#../cacheTime}}
197
- response.addHeader("Cache-Control", "max-age={{value}}");
198
- {{/../cacheTime}}
199
- {{^../cacheTime}}
200
- response.addHeader("Cache-Control", "no-cache");
201
- {{/../cacheTime}}
202
- response.addHeader("ETag", etag_{{this.dataname}});
203
- {{/case}}
204
- {{#case "compiler"}}
205
- #ifdef {{../definePrefix}}_ENABLE_ETAG
206
- {{#../cacheTime}}
207
- response.addHeader("Cache-Control", "max-age={{value}}");
208
- {{/../cacheTime}}
209
- {{^../cacheTime}}
210
- response.addHeader("Cache-Control", "no-cache");
211
- {{/../cacheTime}}
212
- response.addHeader("ETag", etag_{{this.dataname}});
213
- #endif
214
- {{/case}}
215
- {{/switch}}
216
-
217
- {{#switch ../gzip}}
218
- {{#case "true"}}
219
- response.setContent(datagzip_{{this.dataname}}, {{this.lengthGzip}});
220
- {{/case}}
221
- {{#case "false"}}
222
- response.setContent(data_{{this.dataname}}, {{this.length}});
223
- {{/case}}
224
- {{#case "compiler"}}
225
- #ifdef {{../definePrefix}}_ENABLE_GZIP
226
- response.setContent(datagzip_{{this.dataname}}, {{this.lengthGzip}});
227
- #else
228
- response.setContent(data_{{this.dataname}}, {{this.length}});
229
- #endif
230
- {{/case}}
231
- {{/switch}}
232
-
233
- {{../definePrefix}}_onFileServed("{{../basePath}}/{{this.filename}}", 200);
234
- return response.send();
235
- });
236
- {{#if this.isDefault}}{{#if ../basePath}}
237
- //
238
- // {{this.filename}} (base path route)
239
- server->on("{{../basePath}}", HTTP_GET, [](PsychicRequest * request) {
240
-
241
- {{#switch ../etag}}
242
- {{#case "true"}}
243
- if (request->hasHeader("If-None-Match") && request->header("If-None-Match").equals(etag_{{this.dataname}})) {
244
- PsychicResponse response304(request);
245
- response304.setCode(304);
246
- {{../definePrefix}}_onFileServed("{{../basePath}}", 304);
247
- return response304.send();
248
- }
249
- {{/case}}
250
- {{#case "compiler"}}
251
- #ifdef {{../definePrefix}}_ENABLE_ETAG
252
- if (request->hasHeader("If-None-Match") && request->header("If-None-Match").equals(etag_{{this.dataname}})) {
253
- PsychicResponse response304(request);
254
- response304.setCode(304);
255
- {{../definePrefix}}_onFileServed("{{../basePath}}", 304);
256
- return response304.send();
257
- }
258
- #endif
259
- {{/case}}
260
- {{/switch}}
261
-
262
- PsychicResponse response(request);
263
- response.setContentType("{{this.mime}}");
264
-
265
- {{#switch ../gzip}}
266
- {{#case "true"}}
267
- {{#if this.isGzip}}
268
- response.addHeader("Content-Encoding", "gzip");
269
- {{/if}}
270
- {{/case}}
271
- {{#case "compiler"}}
272
- {{#if this.isGzip}}
273
- #ifdef {{../definePrefix}}_ENABLE_GZIP
274
- response.addHeader("Content-Encoding", "gzip");
275
- #endif
276
- {{/if}}
277
- {{/case}}
278
- {{/switch}}
279
-
280
- {{#switch ../etag}}
281
- {{#case "true"}}
282
- {{#../cacheTime}}
283
- response.addHeader("Cache-Control", "max-age={{value}}");
284
- {{/../cacheTime}}
285
- {{^../cacheTime}}
286
- response.addHeader("Cache-Control", "no-cache");
287
- {{/../cacheTime}}
288
- response.addHeader("ETag", etag_{{this.dataname}});
289
- {{/case}}
290
- {{#case "compiler"}}
291
- #ifdef {{../definePrefix}}_ENABLE_ETAG
292
- {{#../cacheTime}}
293
- response.addHeader("Cache-Control", "max-age={{value}}");
294
- {{/../cacheTime}}
295
- {{^../cacheTime}}
296
- response.addHeader("Cache-Control", "no-cache");
297
- {{/../cacheTime}}
298
- response.addHeader("ETag", etag_{{this.dataname}});
299
- #endif
300
- {{/case}}
301
- {{/switch}}
302
-
303
- {{#switch ../gzip}}
304
- {{#case "true"}}
305
- response.setContent(datagzip_{{this.dataname}}, {{this.lengthGzip}});
306
- {{/case}}
307
- {{#case "false"}}
308
- response.setContent(data_{{this.dataname}}, {{this.length}});
309
- {{/case}}
310
- {{#case "compiler"}}
311
- #ifdef {{../definePrefix}}_ENABLE_GZIP
312
- response.setContent(datagzip_{{this.dataname}}, {{this.lengthGzip}});
313
- #else
314
- response.setContent(data_{{this.dataname}}, {{this.length}});
315
- #endif
316
- {{/case}}
317
- {{/switch}}
318
-
319
- {{../definePrefix}}_onFileServed("{{../basePath}}", 200);
320
- return response.send();
321
- });
322
- {{/if}}{{/if}}
323
-
324
- {{/each}}
325
- }`;
326
- const psychic2Template = `
327
- //engine: PsychicHttpServerV2
328
- //config: {{{config}}}
329
123
  {{#if created }}
330
124
  //created: {{now}}
331
125
  {{/if}}
@@ -704,21 +498,29 @@ const getTemplate = (engine) => {
704
498
  switch (engine) {
705
499
  case 'psychic':
706
500
  return psychicTemplate;
707
- case 'psychic2':
708
- return psychic2Template;
501
+ case 'async':
502
+ return asyncTemplate;
709
503
  case 'espidf':
710
504
  return cppCodeEspIdf_1.espidfTemplate;
711
505
  default:
712
- return asyncTemplate;
506
+ throw new Error(`Unknown engine: ${engine}`);
713
507
  }
714
508
  };
509
+ const bufferToByteString = (buffer) => {
510
+ if (buffer.length === 0)
511
+ return '';
512
+ let result = buffer[0].toString(10);
513
+ for (let index = 1; index < buffer.length; index++)
514
+ result += ',' + buffer[index].toString(10);
515
+ return result;
516
+ };
715
517
  const transformSourceToTemplateData = (s, etag) => ({
716
518
  ...s,
717
519
  length: s.content.length,
718
- bytes: [...s.content].map((v) => `${v.toString(10)}`).join(','),
520
+ bytes: bufferToByteString(s.content),
719
521
  lengthGzip: s.contentGzip.length,
720
- bytesGzip: [...s.contentGzip].map((v) => `${v.toString(10)}`).join(','),
721
- isDefault: s.filename.startsWith('index.htm'),
522
+ bytesGzip: bufferToByteString(s.contentGzip),
523
+ isDefault: s.filename === 'index.html' || s.filename === 'index.htm',
722
524
  gzipSizeForManifest: s.isGzip ? s.contentGzip.length : 0,
723
525
  etagForManifest: etag === 'false' ? 'NULL' : `etag_${s.dataname}`
724
526
  });
@@ -728,7 +530,7 @@ const postProcessCppCode = (code) => code
728
530
  .filter(Boolean)
729
531
  .map((line) => (line === '//' ? '' : line))
730
532
  .join('\n')
731
- .replace(/\\n{2}/, '\n');
533
+ .replace(/\n{2,}/g, '\n');
732
534
  const createHandlebarsHelpers = () => {
733
535
  let switchValue;
734
536
  return {
@@ -752,7 +554,10 @@ const getCppCode = (sources, filesByExtension) => {
752
554
  const template = (0, handlebars_1.compile)(getTemplate(commandLine_1.cmdLine.engine));
753
555
  const templateData = {
754
556
  config: (0, commandLine_1.formatConfiguration)(commandLine_1.cmdLine),
755
- now: `${new Date().toLocaleDateString()} ${new Date().toLocaleTimeString()}`,
557
+ now: (() => {
558
+ const d = new Date();
559
+ return `${d.toLocaleDateString()} ${d.toLocaleTimeString()}`;
560
+ })(),
756
561
  fileCount: sources.length.toString(),
757
562
  fileSize: sources.reduce((previous, current) => previous + current.content.length, 0).toString(),
758
563
  fileGzipSize: sources.reduce((previous, current) => previous + current.contentGzip.length, 0).toString(),
@@ -1 +1 @@
1
- export declare const espidfTemplate = "\n//engine: espidf\n//config: {{{config}}}\n{{#if created }}\n//created: {{now}}\n{{/if}}\n//\n\n{{#switch etag}}\n{{#case \"true\"}}\n#ifdef {{definePrefix}}_ENABLE_ETAG\n#warning {{definePrefix}}_ENABLE_ETAG has no effect because it is permanently switched ON\n#endif\n{{/case}}\n{{#case \"false\"}}\n#ifdef {{definePrefix}}_ENABLE_ETAG\n#warning {{definePrefix}}_ENABLE_ETAG has no effect because it is permanently switched OFF\n#endif\n{{/case}}\n{{/switch}}\n\n{{#switch gzip}}\n{{#case \"true\"}}\n#ifdef {{definePrefix}}_ENABLE_GZIP\n#warning {{definePrefix}}_ENABLE_GZIP has no effect because it is permanently switched ON\n#endif\n{{/case}}\n{{#case \"false\"}}\n#ifdef {{definePrefix}}_ENABLE_GZIP\n#warning {{definePrefix}}_ENABLE_GZIP has no effect because it is permanently switched OFF\n#endif\n{{/case}}\n{{/switch}}\n\n//\n{{#if version }}\n#define {{definePrefix}}_VERSION \"{{version}}\"\n{{/if}}\n#define {{definePrefix}}_COUNT {{fileCount}}\n#define {{definePrefix}}_SIZE {{fileSize}}\n#define {{definePrefix}}_SIZE_GZIP {{fileGzipSize}}\n\n//\n{{#each sources}}\n#define {{../definePrefix}}_FILE_{{this.datanameUpperCase}}\n{{/each}}\n\n//\n{{#each filesByExtension}}\n#define {{../definePrefix}}_{{this.extension}}_FILES {{this.count}}\n{{/each}}\n\n#include <stdint.h>\n#include <string.h>\n#include <stdlib.h>\n#include <esp_err.h>\n#include <esp_http_server.h>\n\n//\n{{#switch gzip}}\n{{#case \"true\"}}\n {{#each sources}}\nconst char datagzip_{{this.dataname}}[{{this.lengthGzip}}] = { {{this.bytesGzip}} };\n {{/each}}\n{{/case}}\n{{#case \"false\"}}\n {{#each sources}}\nconst char data_{{this.dataname}}[{{this.length}}] = { {{this.bytes}} };\n {{/each}}\n{{/case}}\n{{#case \"compiler\"}}\n#ifdef {{definePrefix}}_ENABLE_GZIP\n {{#each sources}}\nconst char datagzip_{{this.dataname}}[{{this.lengthGzip}}] = { {{this.bytesGzip}} };\n {{/each}}\n#else\n {{#each sources}}\nconst char data_{{this.dataname}}[{{this.length}}] = { {{this.bytes}} };\n {{/each}}\n#endif \n{{/case}}\n{{/switch}}\n\n//\n{{#switch etag}}\n{{#case \"true\"}}\n {{#each sources}}\nstatic const char etag_{{this.dataname}}[] = \"{{this.sha256}}\";\n {{/each}}\n{{/case}}\n{{#case \"false\"}}\n{{/case}}\n{{#case \"compiler\"}}\n#ifdef {{definePrefix}}_ENABLE_ETAG\n {{#each sources}}\nstatic const char etag_{{this.dataname}}[] = \"{{this.sha256}}\";\n {{/each}}\n#endif\n{{/case}}\n{{/switch}}\n\n// File manifest struct (C-compatible typedef)\ntypedef struct {\n const char* path;\n uint32_t size;\n uint32_t gzipSize;\n const char* etag;\n const char* contentType;\n} {{definePrefix}}_FileInfo;\n\n// File manifest array\nstatic const {{definePrefix}}_FileInfo {{definePrefix}}_FILES[] = {\n{{#each sources}}\n { \"{{../basePath}}/{{this.filename}}\", {{this.length}}, {{this.gzipSizeForManifest}}, {{this.etagForManifest}}, \"{{this.mime}}\" },\n{{/each}}\n};\nstatic const size_t {{definePrefix}}_FILE_COUNT = sizeof({{definePrefix}}_FILES) / sizeof({{definePrefix}}_FILES[0]);\n\n// File served hook - override with your own implementation\n__attribute__((weak)) void {{definePrefix}}_onFileServed(const char* path, int statusCode) {}\n\n{{#each sources}}\n\nstatic esp_err_t file_handler_{{this.datanameUpperCase}} (httpd_req_t *req)\n{\n{{#switch ../etag}}\n{{#case \"true\"}}\n size_t hdr_len = httpd_req_get_hdr_value_len(req, \"If-None-Match\");\n if (hdr_len > 0) {\n char* hdr_value = malloc(hdr_len + 1);\n if (httpd_req_get_hdr_value_str(req, \"If-None-Match\", hdr_value, hdr_len + 1) == ESP_OK) {\n if (strcmp(hdr_value, etag_{{this.dataname}}) == 0) {\n free(hdr_value);\n httpd_resp_set_status(req, \"304 Not Modified\");\n {{../definePrefix}}_onFileServed(\"{{../basePath}}/{{this.filename}}\", 304);\n httpd_resp_send(req, NULL, 0);\n return ESP_OK;\n }\n }\n free(hdr_value);\n }\n{{/case}}\n{{#case \"compiler\"}}\n #ifdef {{../definePrefix}}_ENABLE_ETAG\n size_t hdr_len = httpd_req_get_hdr_value_len(req, \"If-None-Match\");\n if (hdr_len > 0) {\n char* hdr_value = malloc(hdr_len + 1);\n if (httpd_req_get_hdr_value_str(req, \"If-None-Match\", hdr_value, hdr_len + 1) == ESP_OK) {\n if (strcmp(hdr_value, etag_{{this.dataname}}) == 0) {\n free(hdr_value);\n httpd_resp_set_status(req, \"304 Not Modified\");\n {{../definePrefix}}_onFileServed(\"{{../basePath}}/{{this.filename}}\", 304);\n httpd_resp_send(req, NULL, 0);\n return ESP_OK;\n }\n }\n free(hdr_value);\n }\n #endif\n{{/case}}\n{{/switch}}\n httpd_resp_set_type(req, \"{{this.mime}}\");\n{{#switch ../gzip}}\n{{#case \"true\"}}\n{{#if this.isGzip}}\n httpd_resp_set_hdr(req, \"Content-Encoding\", \"gzip\");\n{{/if}}\n{{/case}}\n{{#case \"compiler\"}}\n {{#if this.isGzip}}\n #ifdef {{../definePrefix}}_ENABLE_GZIP\n httpd_resp_set_hdr(req, \"Content-Encoding\", \"gzip\");\n #endif \n {{/if}}\n{{/case}}\n{{/switch}}\n\n{{#switch ../etag}}\n{{#case \"true\"}}\n{{#../cacheTime}}\n httpd_resp_set_hdr(req, \"Cache-Control\", \"max-age={{value}}\");\n{{/../cacheTime}}\n{{^../cacheTime}}\n httpd_resp_set_hdr(req, \"Cache-Control\", \"no-cache\");\n{{/../cacheTime}}\n httpd_resp_set_hdr(req, \"ETag\", etag_{{this.dataname}});\n{{/case}}\n{{#case \"compiler\"}}\n #ifdef {{../definePrefix}}_ENABLE_ETAG\n{{#../cacheTime}}\n httpd_resp_set_hdr(req, \"Cache-Control\", \"max-age={{value}}\");\n{{/../cacheTime}}\n{{^../cacheTime}}\n httpd_resp_set_hdr(req, \"Cache-Control\", \"no-cache\");\n{{/../cacheTime}}\n httpd_resp_set_hdr(req, \"ETag\", etag_{{this.dataname}});\n #endif \n{{/case}}\n{{/switch}}\n\n{{#switch ../gzip}}\n{{#case \"true\"}}\n {{../definePrefix}}_onFileServed(\"{{../basePath}}/{{this.filename}}\", 200);\n httpd_resp_send(req, datagzip_{{this.dataname}}, {{this.lengthGzip}});\n{{/case}}\n{{#case \"false\"}}\n {{../definePrefix}}_onFileServed(\"{{../basePath}}/{{this.filename}}\", 200);\n httpd_resp_send(req, data_{{this.dataname}}, {{this.length}});\n{{/case}}\n{{#case \"compiler\"}}\n {{../definePrefix}}_onFileServed(\"{{../basePath}}/{{this.filename}}\", 200);\n #ifdef {{../definePrefix}}_ENABLE_GZIP\n httpd_resp_send(req, datagzip_{{this.dataname}}, {{this.lengthGzip}});\n #else\n httpd_resp_send(req, data_{{this.dataname}}, {{this.length}});\n #endif\n{{/case}}\n{{/switch}}\n return ESP_OK;\n}\n\n{{#if this.isDefault}}\nstatic const httpd_uri_t route_def_{{this.datanameUpperCase}} = {\n .uri = \"{{#if ../basePath}}{{../basePath}}{{else}}/{{/if}}\",\n .method = HTTP_GET,\n .handler = file_handler_{{this.datanameUpperCase}},\n};\n{{/if}}\n\nstatic const httpd_uri_t route_{{this.datanameUpperCase}} = {\n .uri = \"{{../basePath}}/{{this.filename}}\",\n .method = HTTP_GET,\n .handler = file_handler_{{this.datanameUpperCase}},\n};\n\n{{/each}}\n\n\n\nstatic inline void {{methodName}}(httpd_handle_t server) {\n{{#each sources}}\n{{#if this.isDefault}}\n httpd_register_uri_handler(server, &route_def_{{this.datanameUpperCase}});\n{{/if}}\n httpd_register_uri_handler(server, &route_{{this.datanameUpperCase}});\n{{/each}}\n\n}";
1
+ export declare const espidfTemplate = "\n//engine: espidf\n//config: {{{config}}}\n{{#if created }}\n//created: {{now}}\n{{/if}}\n//\n\n{{#switch etag}}\n{{#case \"true\"}}\n#ifdef {{definePrefix}}_ENABLE_ETAG\n#warning {{definePrefix}}_ENABLE_ETAG has no effect because it is permanently switched ON\n#endif\n{{/case}}\n{{#case \"false\"}}\n#ifdef {{definePrefix}}_ENABLE_ETAG\n#warning {{definePrefix}}_ENABLE_ETAG has no effect because it is permanently switched OFF\n#endif\n{{/case}}\n{{/switch}}\n\n{{#switch gzip}}\n{{#case \"true\"}}\n#ifdef {{definePrefix}}_ENABLE_GZIP\n#warning {{definePrefix}}_ENABLE_GZIP has no effect because it is permanently switched ON\n#endif\n{{/case}}\n{{#case \"false\"}}\n#ifdef {{definePrefix}}_ENABLE_GZIP\n#warning {{definePrefix}}_ENABLE_GZIP has no effect because it is permanently switched OFF\n#endif\n{{/case}}\n{{/switch}}\n\n//\n{{#if version }}\n#define {{definePrefix}}_VERSION \"{{version}}\"\n{{/if}}\n#define {{definePrefix}}_COUNT {{fileCount}}\n#define {{definePrefix}}_SIZE {{fileSize}}\n#define {{definePrefix}}_SIZE_GZIP {{fileGzipSize}}\n\n//\n{{#each sources}}\n#define {{../definePrefix}}_FILE_{{this.datanameUpperCase}}\n{{/each}}\n\n//\n{{#each filesByExtension}}\n#define {{../definePrefix}}_{{this.extension}}_FILES {{this.count}}\n{{/each}}\n\n#include <stdint.h>\n#include <string.h>\n#include <stdlib.h>\n#include <esp_err.h>\n#include <esp_http_server.h>\n\n//\n{{#switch gzip}}\n{{#case \"true\"}}\n {{#each sources}}\nconst unsigned char datagzip_{{this.dataname}}[{{this.lengthGzip}}] = { {{this.bytesGzip}} };\n {{/each}}\n{{/case}}\n{{#case \"false\"}}\n {{#each sources}}\nconst unsigned char data_{{this.dataname}}[{{this.length}}] = { {{this.bytes}} };\n {{/each}}\n{{/case}}\n{{#case \"compiler\"}}\n#ifdef {{definePrefix}}_ENABLE_GZIP\n {{#each sources}}\nconst unsigned char datagzip_{{this.dataname}}[{{this.lengthGzip}}] = { {{this.bytesGzip}} };\n {{/each}}\n#else\n {{#each sources}}\nconst unsigned char data_{{this.dataname}}[{{this.length}}] = { {{this.bytes}} };\n {{/each}}\n#endif \n{{/case}}\n{{/switch}}\n\n//\n{{#switch etag}}\n{{#case \"true\"}}\n {{#each sources}}\nstatic const char etag_{{this.dataname}}[] = \"{{this.sha256}}\";\n {{/each}}\n{{/case}}\n{{#case \"false\"}}\n{{/case}}\n{{#case \"compiler\"}}\n#ifdef {{definePrefix}}_ENABLE_ETAG\n {{#each sources}}\nstatic const char etag_{{this.dataname}}[] = \"{{this.sha256}}\";\n {{/each}}\n#endif\n{{/case}}\n{{/switch}}\n\n// File manifest struct (C-compatible typedef)\ntypedef struct {\n const char* path;\n uint32_t size;\n uint32_t gzipSize;\n const char* etag;\n const char* contentType;\n} {{definePrefix}}_FileInfo;\n\n// File manifest array\nstatic const {{definePrefix}}_FileInfo {{definePrefix}}_FILES[] = {\n{{#each sources}}\n { \"{{../basePath}}/{{this.filename}}\", {{this.length}}, {{this.gzipSizeForManifest}}, {{this.etagForManifest}}, \"{{this.mime}}\" },\n{{/each}}\n};\nstatic const size_t {{definePrefix}}_FILE_COUNT = sizeof({{definePrefix}}_FILES) / sizeof({{definePrefix}}_FILES[0]);\n\n// File served hook - override with your own implementation\n__attribute__((weak)) void {{definePrefix}}_onFileServed(const char* path, int statusCode) {}\n\n{{#each sources}}\n\nstatic esp_err_t file_handler_{{this.datanameUpperCase}} (httpd_req_t *req)\n{\n{{#switch ../etag}}\n{{#case \"true\"}}\n size_t hdr_len = httpd_req_get_hdr_value_len(req, \"If-None-Match\");\n if (hdr_len > 0) {\n char* hdr_value = malloc(hdr_len + 1);\n if (hdr_value == NULL) { httpd_resp_send_500(req); return ESP_FAIL; }\n if (httpd_req_get_hdr_value_str(req, \"If-None-Match\", hdr_value, hdr_len + 1) == ESP_OK) {\n if (strcmp(hdr_value, etag_{{this.dataname}}) == 0) {\n free(hdr_value);\n httpd_resp_set_status(req, \"304 Not Modified\");\n {{../definePrefix}}_onFileServed(\"{{../basePath}}/{{this.filename}}\", 304);\n httpd_resp_send(req, NULL, 0);\n return ESP_OK;\n }\n }\n free(hdr_value);\n }\n{{/case}}\n{{#case \"compiler\"}}\n #ifdef {{../definePrefix}}_ENABLE_ETAG\n size_t hdr_len = httpd_req_get_hdr_value_len(req, \"If-None-Match\");\n if (hdr_len > 0) {\n char* hdr_value = malloc(hdr_len + 1);\n if (hdr_value == NULL) { httpd_resp_send_500(req); return ESP_FAIL; }\n if (httpd_req_get_hdr_value_str(req, \"If-None-Match\", hdr_value, hdr_len + 1) == ESP_OK) {\n if (strcmp(hdr_value, etag_{{this.dataname}}) == 0) {\n free(hdr_value);\n httpd_resp_set_status(req, \"304 Not Modified\");\n {{../definePrefix}}_onFileServed(\"{{../basePath}}/{{this.filename}}\", 304);\n httpd_resp_send(req, NULL, 0);\n return ESP_OK;\n }\n }\n free(hdr_value);\n }\n #endif\n{{/case}}\n{{/switch}}\n httpd_resp_set_type(req, \"{{this.mime}}\");\n{{#switch ../gzip}}\n{{#case \"true\"}}\n{{#if this.isGzip}}\n httpd_resp_set_hdr(req, \"Content-Encoding\", \"gzip\");\n{{/if}}\n{{/case}}\n{{#case \"compiler\"}}\n {{#if this.isGzip}}\n #ifdef {{../definePrefix}}_ENABLE_GZIP\n httpd_resp_set_hdr(req, \"Content-Encoding\", \"gzip\");\n #endif \n {{/if}}\n{{/case}}\n{{/switch}}\n\n{{#switch ../etag}}\n{{#case \"true\"}}\n{{#../cacheTime}}\n httpd_resp_set_hdr(req, \"Cache-Control\", \"max-age={{value}}\");\n{{/../cacheTime}}\n{{^../cacheTime}}\n httpd_resp_set_hdr(req, \"Cache-Control\", \"no-cache\");\n{{/../cacheTime}}\n httpd_resp_set_hdr(req, \"ETag\", etag_{{this.dataname}});\n{{/case}}\n{{#case \"compiler\"}}\n #ifdef {{../definePrefix}}_ENABLE_ETAG\n{{#../cacheTime}}\n httpd_resp_set_hdr(req, \"Cache-Control\", \"max-age={{value}}\");\n{{/../cacheTime}}\n{{^../cacheTime}}\n httpd_resp_set_hdr(req, \"Cache-Control\", \"no-cache\");\n{{/../cacheTime}}\n httpd_resp_set_hdr(req, \"ETag\", etag_{{this.dataname}});\n #endif \n{{/case}}\n{{/switch}}\n\n{{#switch ../gzip}}\n{{#case \"true\"}}\n {{../definePrefix}}_onFileServed(\"{{../basePath}}/{{this.filename}}\", 200);\n httpd_resp_send(req, (const char *)datagzip_{{this.dataname}}, {{this.lengthGzip}});\n{{/case}}\n{{#case \"false\"}}\n {{../definePrefix}}_onFileServed(\"{{../basePath}}/{{this.filename}}\", 200);\n httpd_resp_send(req, (const char *)data_{{this.dataname}}, {{this.length}});\n{{/case}}\n{{#case \"compiler\"}}\n {{../definePrefix}}_onFileServed(\"{{../basePath}}/{{this.filename}}\", 200);\n #ifdef {{../definePrefix}}_ENABLE_GZIP\n httpd_resp_send(req, (const char *)datagzip_{{this.dataname}}, {{this.lengthGzip}});\n #else\n httpd_resp_send(req, (const char *)data_{{this.dataname}}, {{this.length}});\n #endif\n{{/case}}\n{{/switch}}\n return ESP_OK;\n}\n\n{{#if this.isDefault}}\nstatic const httpd_uri_t route_def_{{this.datanameUpperCase}} = {\n .uri = \"{{#if ../basePath}}{{../basePath}}{{else}}/{{/if}}\",\n .method = HTTP_GET,\n .handler = file_handler_{{this.datanameUpperCase}},\n};\n{{/if}}\n\nstatic const httpd_uri_t route_{{this.datanameUpperCase}} = {\n .uri = \"{{../basePath}}/{{this.filename}}\",\n .method = HTTP_GET,\n .handler = file_handler_{{this.datanameUpperCase}},\n};\n\n{{/each}}\n\n\n\nstatic inline void {{methodName}}(httpd_handle_t server) {\n{{#each sources}}\n{{#if this.isDefault}}\n httpd_register_uri_handler(server, &route_def_{{this.datanameUpperCase}});\n{{/if}}\n httpd_register_uri_handler(server, &route_{{this.datanameUpperCase}});\n{{/each}}\n\n}";
@@ -63,22 +63,22 @@ exports.espidfTemplate = `
63
63
  {{#switch gzip}}
64
64
  {{#case "true"}}
65
65
  {{#each sources}}
66
- const char datagzip_{{this.dataname}}[{{this.lengthGzip}}] = { {{this.bytesGzip}} };
66
+ const unsigned char datagzip_{{this.dataname}}[{{this.lengthGzip}}] = { {{this.bytesGzip}} };
67
67
  {{/each}}
68
68
  {{/case}}
69
69
  {{#case "false"}}
70
70
  {{#each sources}}
71
- const char data_{{this.dataname}}[{{this.length}}] = { {{this.bytes}} };
71
+ const unsigned char data_{{this.dataname}}[{{this.length}}] = { {{this.bytes}} };
72
72
  {{/each}}
73
73
  {{/case}}
74
74
  {{#case "compiler"}}
75
75
  #ifdef {{definePrefix}}_ENABLE_GZIP
76
76
  {{#each sources}}
77
- const char datagzip_{{this.dataname}}[{{this.lengthGzip}}] = { {{this.bytesGzip}} };
77
+ const unsigned char datagzip_{{this.dataname}}[{{this.lengthGzip}}] = { {{this.bytesGzip}} };
78
78
  {{/each}}
79
79
  #else
80
80
  {{#each sources}}
81
- const char data_{{this.dataname}}[{{this.length}}] = { {{this.bytes}} };
81
+ const unsigned char data_{{this.dataname}}[{{this.length}}] = { {{this.bytes}} };
82
82
  {{/each}}
83
83
  #endif
84
84
  {{/case}}
@@ -131,6 +131,7 @@ static esp_err_t file_handler_{{this.datanameUpperCase}} (httpd_req_t *req)
131
131
  size_t hdr_len = httpd_req_get_hdr_value_len(req, "If-None-Match");
132
132
  if (hdr_len > 0) {
133
133
  char* hdr_value = malloc(hdr_len + 1);
134
+ if (hdr_value == NULL) { httpd_resp_send_500(req); return ESP_FAIL; }
134
135
  if (httpd_req_get_hdr_value_str(req, "If-None-Match", hdr_value, hdr_len + 1) == ESP_OK) {
135
136
  if (strcmp(hdr_value, etag_{{this.dataname}}) == 0) {
136
137
  free(hdr_value);
@@ -148,6 +149,7 @@ static esp_err_t file_handler_{{this.datanameUpperCase}} (httpd_req_t *req)
148
149
  size_t hdr_len = httpd_req_get_hdr_value_len(req, "If-None-Match");
149
150
  if (hdr_len > 0) {
150
151
  char* hdr_value = malloc(hdr_len + 1);
152
+ if (hdr_value == NULL) { httpd_resp_send_500(req); return ESP_FAIL; }
151
153
  if (httpd_req_get_hdr_value_str(req, "If-None-Match", hdr_value, hdr_len + 1) == ESP_OK) {
152
154
  if (strcmp(hdr_value, etag_{{this.dataname}}) == 0) {
153
155
  free(hdr_value);
@@ -204,18 +206,18 @@ static esp_err_t file_handler_{{this.datanameUpperCase}} (httpd_req_t *req)
204
206
  {{#switch ../gzip}}
205
207
  {{#case "true"}}
206
208
  {{../definePrefix}}_onFileServed("{{../basePath}}/{{this.filename}}", 200);
207
- httpd_resp_send(req, datagzip_{{this.dataname}}, {{this.lengthGzip}});
209
+ httpd_resp_send(req, (const char *)datagzip_{{this.dataname}}, {{this.lengthGzip}});
208
210
  {{/case}}
209
211
  {{#case "false"}}
210
212
  {{../definePrefix}}_onFileServed("{{../basePath}}/{{this.filename}}", 200);
211
- httpd_resp_send(req, data_{{this.dataname}}, {{this.length}});
213
+ httpd_resp_send(req, (const char *)data_{{this.dataname}}, {{this.length}});
212
214
  {{/case}}
213
215
  {{#case "compiler"}}
214
216
  {{../definePrefix}}_onFileServed("{{../basePath}}/{{this.filename}}", 200);
215
217
  #ifdef {{../definePrefix}}_ENABLE_GZIP
216
- httpd_resp_send(req, datagzip_{{this.dataname}}, {{this.lengthGzip}});
218
+ httpd_resp_send(req, (const char *)datagzip_{{this.dataname}}, {{this.lengthGzip}});
217
219
  #else
218
- httpd_resp_send(req, data_{{this.dataname}}, {{this.length}});
220
+ httpd_resp_send(req, (const char *)data_{{this.dataname}}, {{this.length}});
219
221
  #endif
220
222
  {{/case}}
221
223
  {{/switch}}
@@ -2,4 +2,4 @@ export declare function getMissingIndexError(engine: string): string;
2
2
  export declare function getInvalidEngineError(attempted: string): string;
3
3
  export declare function getSourcepathNotFoundError(sourcepath: string, reason: 'not_found' | 'not_directory'): string;
4
4
  export declare function getSizeBudgetExceededError(type: 'size' | 'gzipSize', limit: number, actual: number): string;
5
- export declare function getMaxUriHandlersHint(engine: string, routeCount: number): string;
5
+ export declare function getMaxUriHandlersHint(engine: string, routeCount: number, espmethod?: string): string;
@@ -13,7 +13,6 @@ const consoleColor_1 = require("./consoleColor");
13
13
  function getEngineName(engine) {
14
14
  const names = {
15
15
  psychic: 'PsychicHttpServer',
16
- psychic2: 'PsychicHttpServer V2',
17
16
  async: 'ESPAsyncWebServer',
18
17
  espidf: 'ESP-IDF'
19
18
  };
@@ -24,9 +23,6 @@ function getMissingIndexError(engine) {
24
23
  psychic: ` 1. Add an index.html file to your source directory
25
24
  2. The file will automatically be set as the default route ("/")
26
25
  3. PsychicHttpServer uses: server->defaultEndpoint = ...`,
27
- psychic2: ` 1. Add an index.html file to your source directory
28
- 2. The file will automatically be set as the default route ("/")
29
- 3. PsychicHttpServer V2 uses: server->defaultEndpoint = ...`,
30
26
  async: ` 1. Add an index.html file to your source directory
31
27
  2. The file will automatically create a "/" route handler
32
28
  3. ESPAsyncWebServer uses: server.on("/", HTTP_GET, ...)`,
@@ -55,7 +51,6 @@ function getInvalidEngineError(attempted) {
55
51
 
56
52
  Valid engines are:
57
53
  ${(0, consoleColor_1.cyanLog)('• psychic')} - PsychicHttpServer (ESP32 only, fastest performance)
58
- ${(0, consoleColor_1.cyanLog)('• psychic2')} - PsychicHttpServer V2 (ESP32 only, modern API)
59
54
  ${(0, consoleColor_1.cyanLog)('• async')} - ESPAsyncWebServer (ESP32/ESP8266 compatible)
60
55
  ${(0, consoleColor_1.cyanLog)('• espidf')} - Native ESP-IDF web server (ESP32 only, no Arduino)
61
56
 
@@ -136,22 +131,18 @@ CI integration:
136
131
  This non-zero exit code allows build pipelines to fail early when
137
132
  the frontend exceeds allocated flash space.`);
138
133
  }
139
- function getMaxUriHandlersHint(engine, routeCount) {
134
+ function getMaxUriHandlersHint(engine, routeCount, espmethod = 'initSvelteStaticFiles') {
140
135
  const recommended = routeCount + 5;
141
136
  const hints = {
142
137
  psychic: `PsychicHttpServer server;
143
138
  server.config.max_uri_handlers = ${recommended}; // Default is 8, you need at least ${routeCount}
144
- initSvelteStaticFiles(&server);
145
- server.listen(80);`,
146
- psychic2: `PsychicHttpServer server;
147
- server.config.max_uri_handlers = ${recommended}; // Default is 8, you need at least ${routeCount}
148
- initSvelteStaticFiles(&server);
139
+ ${espmethod}(&server);
149
140
  server.listen(80);`,
150
141
  espidf: `httpd_config_t config = HTTPD_DEFAULT_CONFIG();
151
142
  config.max_uri_handlers = ${recommended}; // Default is 8, you need at least ${routeCount}
152
143
  httpd_handle_t server = NULL;
153
144
  httpd_start(&server, &config);
154
- initSvelteStaticFiles(server);`
145
+ ${espmethod}(server);`
155
146
  };
156
147
  const hint = hints[engine];
157
148
  if (!hint)
package/dist/file.d.ts CHANGED
@@ -1 +1,5 @@
1
- export declare const getFiles: () => Map<string, Buffer>;
1
+ export type FileData = {
2
+ content: Buffer;
3
+ hash: string;
4
+ };
5
+ export declare const getFiles: () => Map<string, FileData>;
package/dist/file.js CHANGED
@@ -14,13 +14,12 @@ const consoleColor_1 = require("./consoleColor");
14
14
  const errorMessages_1 = require("./errorMessages");
15
15
  const findSimilarFiles = (files) => {
16
16
  const contentComparer = new Map();
17
- for (const [filename, content] of files.entries()) {
18
- const hash = (0, node_crypto_1.createHash)('sha256').update(content).digest('hex');
19
- const existingFiles = contentComparer.get(hash);
17
+ for (const [filename, fileData] of files.entries()) {
18
+ const existingFiles = contentComparer.get(fileData.hash);
20
19
  if (existingFiles)
21
20
  existingFiles.push(filename);
22
21
  else
23
- contentComparer.set(hash, [filename]);
22
+ contentComparer.set(fileData.hash, [filename]);
24
23
  }
25
24
  const result = [];
26
25
  for (const filenames of contentComparer.values())
@@ -30,7 +29,7 @@ const findSimilarFiles = (files) => {
30
29
  };
31
30
  const shouldSkipFile = (filename, allFilenames) => {
32
31
  const extension = node_path_1.default.extname(filename);
33
- const compressedExtensions = ['.gz', '.brottli', '.br'];
32
+ const compressedExtensions = ['.gz', '.brotli', '.br'];
34
33
  if (compressedExtensions.includes(extension)) {
35
34
  const original = filename.slice(0, -1 * extension.length);
36
35
  if (allFilenames.includes(original)) {
@@ -72,10 +71,14 @@ const getFiles = () => {
72
71
  console.log((0, consoleColor_1.cyanLog)(`... and ${excludedFiles.length - displayLimit} more`));
73
72
  console.log();
74
73
  }
74
+ else if (excludePatterns.length > 0)
75
+ console.log((0, consoleColor_1.yellowLog)(`Warning: --exclude patterns matched no files: ${excludePatterns.join(', ')}`));
75
76
  const result = new Map();
76
77
  for (const filename of filenames) {
77
78
  const filePath = node_path_1.default.join(commandLine_1.cmdLine.sourcepath, filename);
78
- result.set(filename, (0, node_fs_1.readFileSync)(filePath, { flag: 'r' }));
79
+ const content = (0, node_fs_1.readFileSync)(filePath, { flag: 'r' });
80
+ const hash = (0, node_crypto_1.createHash)('sha256').update(content).digest('hex');
81
+ result.set(filename, { content, hash });
79
82
  }
80
83
  const duplicates = findSimilarFiles(result);
81
84
  for (const sameFiles of duplicates)
package/dist/index.d.ts CHANGED
@@ -1,7 +1,9 @@
1
- import { CppCodeSource } from './cppCode';
1
+ import { CppCodeSource, ExtensionGroups } from './cppCode';
2
2
  declare const shouldUseGzip: (originalSize: number, compressedSize: number) => boolean;
3
3
  declare const calculateCompressionRatio: (originalSize: number, compressedSize: number) => number;
4
4
  declare const formatCompressionLog: (filename: string, padding: string, originalSize: number, compressedSize: number, useGzip: boolean) => string;
5
+ declare const formatSize: (bytes: number) => string;
5
6
  declare const createSourceEntry: (filename: string, dataname: string, content: Buffer, contentGzip: Buffer, mimeType: string, sha256: string, isGzip: boolean) => CppCodeSource;
6
- declare const updateExtensionGroup: (extension: string) => void;
7
- export { calculateCompressionRatio, createSourceEntry, formatCompressionLog, shouldUseGzip, updateExtensionGroup };
7
+ declare const updateExtensionGroup: (filesByExtension: ExtensionGroups, extension: string) => void;
8
+ export declare function main(): void;
9
+ export { calculateCompressionRatio, createSourceEntry, formatCompressionLog, formatSize, shouldUseGzip, updateExtensionGroup };
package/dist/index.js CHANGED
@@ -3,8 +3,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.updateExtensionGroup = exports.shouldUseGzip = exports.formatCompressionLog = exports.createSourceEntry = exports.calculateCompressionRatio = void 0;
7
- const node_crypto_1 = require("node:crypto");
6
+ exports.updateExtensionGroup = exports.shouldUseGzip = exports.formatSize = exports.formatCompressionLog = exports.createSourceEntry = exports.calculateCompressionRatio = void 0;
7
+ exports.main = main;
8
8
  const node_fs_1 = require("node:fs");
9
9
  const node_path_1 = __importDefault(require("node:path"));
10
10
  const node_zlib_1 = require("node:zlib");
@@ -16,13 +16,6 @@ const errorMessages_1 = require("./errorMessages");
16
16
  const file_1 = require("./file");
17
17
  const GZIP_MIN_SIZE = 1024;
18
18
  const GZIP_MIN_REDUCTION_RATIO = 0.85;
19
- const summary = {
20
- filecount: 0,
21
- size: 0,
22
- gzipsize: 0
23
- };
24
- const sources = [];
25
- const filesByExtension = [];
26
19
  const shouldUseGzip = (originalSize, compressedSize) => originalSize > GZIP_MIN_SIZE && compressedSize < originalSize * GZIP_MIN_REDUCTION_RATIO;
27
20
  exports.shouldUseGzip = shouldUseGzip;
28
21
  const calculateCompressionRatio = (originalSize, compressedSize) => Math.round((compressedSize / originalSize) * 100);
@@ -36,6 +29,12 @@ const formatCompressionLog = (filename, padding, originalSize, compressedSize, u
36
29
  return (0, consoleColor_1.yellowLog)(` [${filename}] ${padding} x gzip unused ${tooSmall}${sizeInfo}`);
37
30
  };
38
31
  exports.formatCompressionLog = formatCompressionLog;
32
+ const formatSize = (bytes) => {
33
+ if (bytes < 1024)
34
+ return `${bytes}B`;
35
+ return `${Math.round(bytes / 1024)}kB`;
36
+ };
37
+ exports.formatSize = formatSize;
39
38
  const createSourceEntry = (filename, dataname, content, contentGzip, mimeType, sha256, isGzip) => ({
40
39
  filename,
41
40
  dataname,
@@ -47,7 +46,7 @@ const createSourceEntry = (filename, dataname, content, contentGzip, mimeType, s
47
46
  sha256
48
47
  });
49
48
  exports.createSourceEntry = createSourceEntry;
50
- const updateExtensionGroup = (extension) => {
49
+ const updateExtensionGroup = (filesByExtension, extension) => {
51
50
  const group = filesByExtension.find((fe) => fe.extension === extension);
52
51
  if (group)
53
52
  group.count += 1;
@@ -55,47 +54,66 @@ const updateExtensionGroup = (extension) => {
55
54
  filesByExtension.push({ extension, count: 1 });
56
55
  };
57
56
  exports.updateExtensionGroup = updateExtensionGroup;
58
- console.log('Collecting source files');
59
- const files = (0, file_1.getFiles)();
60
- if (files.size === 0) {
61
- console.error(`Directory ${commandLine_1.cmdLine.sourcepath} is empty`);
62
- process.exit(1);
63
- }
64
- console.log();
65
- console.log('Translation to header file');
66
- const longestFilename = [...files.keys()].reduce((p, c) => Math.max(c.length, p), 0);
67
- for (const [originalFilename, content] of files) {
68
- const mimeType = (0, mime_types_1.lookup)(originalFilename) || 'text/plain';
69
- summary.filecount++;
70
- const filename = originalFilename.replace(/\\/g, '/');
71
- const dataname = filename.replace(/[!&()+./@{}~-]/g, '_');
72
- let extension = node_path_1.default.extname(filename).toUpperCase();
73
- if (extension.startsWith('.'))
74
- extension = extension.slice(1);
75
- updateExtensionGroup(extension);
76
- const sha256 = (0, node_crypto_1.createHash)('sha256').update(content).digest('hex');
77
- summary.size += content.length;
78
- const zipContent = (0, node_zlib_1.gzipSync)(content, { level: 9 });
79
- summary.gzipsize += zipContent.length;
80
- const useGzip = shouldUseGzip(content.length, zipContent.length);
81
- sources.push(createSourceEntry(filename, dataname, content, zipContent, mimeType, sha256, useGzip));
82
- const padding = ' '.repeat(longestFilename - originalFilename.length);
83
- console.log(formatCompressionLog(originalFilename, padding, content.length, zipContent.length, useGzip));
84
- }
85
- console.log('');
86
- filesByExtension.sort((left, right) => left.extension.localeCompare(right.extension));
87
- if (commandLine_1.cmdLine.maxSize !== undefined && summary.size > commandLine_1.cmdLine.maxSize) {
88
- console.error((0, errorMessages_1.getSizeBudgetExceededError)('size', commandLine_1.cmdLine.maxSize, summary.size));
89
- process.exit(1);
90
- }
91
- if (commandLine_1.cmdLine.maxGzipSize !== undefined && summary.gzipsize > commandLine_1.cmdLine.maxGzipSize) {
92
- console.error((0, errorMessages_1.getSizeBudgetExceededError)('gzipSize', commandLine_1.cmdLine.maxGzipSize, summary.gzipsize));
93
- process.exit(1);
57
+ function main() {
58
+ const summary = {
59
+ filecount: 0,
60
+ size: 0,
61
+ gzipsize: 0
62
+ };
63
+ const sources = [];
64
+ const filesByExtension = [];
65
+ console.log('Collecting source files');
66
+ const files = (0, file_1.getFiles)();
67
+ if (files.size === 0) {
68
+ console.error(`Directory ${commandLine_1.cmdLine.sourcepath} is empty`);
69
+ process.exit(1);
70
+ }
71
+ console.log();
72
+ console.log('Translation to header file');
73
+ const longestFilename = [...files.keys()].reduce((p, c) => Math.max(c.length, p), 0);
74
+ for (const [originalFilename, fileData] of files) {
75
+ const { content, hash: sha256 } = fileData;
76
+ const mimeType = (0, mime_types_1.lookup)(originalFilename) || 'text/plain';
77
+ if (!(0, mime_types_1.lookup)(originalFilename))
78
+ console.log((0, consoleColor_1.yellowLog)(` [${originalFilename}] unknown MIME type for extension '${node_path_1.default.extname(originalFilename)}', using text/plain`));
79
+ summary.filecount++;
80
+ const filename = originalFilename.replace(/\\/g, '/');
81
+ let dataname = filename.replace(/\W/g, '_');
82
+ if (/^\d/.test(dataname))
83
+ dataname = '_' + dataname;
84
+ let extension = node_path_1.default.extname(filename).toUpperCase();
85
+ if (extension.startsWith('.'))
86
+ extension = extension.slice(1);
87
+ updateExtensionGroup(filesByExtension, extension);
88
+ summary.size += content.length;
89
+ const zipContent = (0, node_zlib_1.gzipSync)(content, { level: 9 });
90
+ const useGzip = shouldUseGzip(content.length, zipContent.length);
91
+ summary.gzipsize += useGzip ? zipContent.length : content.length;
92
+ sources.push(createSourceEntry(filename, dataname, content, zipContent, mimeType, sha256, useGzip));
93
+ const padding = ' '.repeat(longestFilename - originalFilename.length);
94
+ console.log(formatCompressionLog(originalFilename, padding, content.length, zipContent.length, useGzip));
95
+ }
96
+ console.log('');
97
+ filesByExtension.sort((left, right) => left.extension.localeCompare(right.extension));
98
+ if (commandLine_1.cmdLine.maxSize !== undefined && summary.size > commandLine_1.cmdLine.maxSize) {
99
+ console.error((0, errorMessages_1.getSizeBudgetExceededError)('size', commandLine_1.cmdLine.maxSize, summary.size));
100
+ process.exit(1);
101
+ }
102
+ if (commandLine_1.cmdLine.maxGzipSize !== undefined && summary.gzipsize > commandLine_1.cmdLine.maxGzipSize) {
103
+ console.error((0, errorMessages_1.getSizeBudgetExceededError)('gzipSize', commandLine_1.cmdLine.maxGzipSize, summary.gzipsize));
104
+ process.exit(1);
105
+ }
106
+ if (commandLine_1.cmdLine.dryRun) {
107
+ console.log(`[DRY RUN] ${summary.filecount} files, ${formatSize(summary.size)} original size, ${formatSize(summary.gzipsize)} gzip size`);
108
+ console.log(`[DRY RUN] Would write to ${commandLine_1.cmdLine.outputfile}`);
109
+ return;
110
+ }
111
+ const cppFile = (0, cppCode_1.getCppCode)(sources, filesByExtension);
112
+ (0, node_fs_1.mkdirSync)(node_path_1.default.normalize(node_path_1.default.dirname(commandLine_1.cmdLine.outputfile)), { recursive: true });
113
+ (0, node_fs_1.writeFileSync)(commandLine_1.cmdLine.outputfile, cppFile, { flush: true, encoding: 'utf8' });
114
+ console.log(`${summary.filecount} files, ${formatSize(summary.size)} original size, ${formatSize(summary.gzipsize)} gzip size`);
115
+ console.log(`${commandLine_1.cmdLine.outputfile} ${formatSize(cppFile.length)} size`);
116
+ if (commandLine_1.cmdLine.engine === 'psychic' || commandLine_1.cmdLine.engine === 'espidf')
117
+ console.log('\n' + (0, errorMessages_1.getMaxUriHandlersHint)(commandLine_1.cmdLine.engine, sources.length, commandLine_1.cmdLine.espmethod));
94
118
  }
95
- const cppFile = (0, cppCode_1.getCppCode)(sources, filesByExtension);
96
- (0, node_fs_1.mkdirSync)(node_path_1.default.normalize(node_path_1.default.dirname(commandLine_1.cmdLine.outputfile)), { recursive: true });
97
- (0, node_fs_1.writeFileSync)(commandLine_1.cmdLine.outputfile, cppFile, { flush: true, encoding: 'utf8' });
98
- console.log(`${summary.filecount} files, ${Math.round(summary.size / 1024)}kB original size, ${Math.round(summary.gzipsize / 1024)}kB gzip size`);
99
- console.log(`${commandLine_1.cmdLine.outputfile} ${Math.round(cppFile.length / 1024)}kB size`);
100
- if (commandLine_1.cmdLine.engine === 'psychic' || commandLine_1.cmdLine.engine === 'psychic2' || commandLine_1.cmdLine.engine === 'espidf')
101
- console.log('\n' + (0, errorMessages_1.getMaxUriHandlersHint)(commandLine_1.cmdLine.engine, sources.length));
119
+ main();