elegance-js 2.0.19 → 2.1.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/build.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  // src/build.ts
2
- import fs3 from "fs";
3
- import path2 from "path";
4
- import { fileURLToPath as fileURLToPath3 } from "url";
2
+ import fs from "fs";
3
+ import path from "path";
4
+ import { fileURLToPath } from "url";
5
5
  import child_process from "node:child_process";
6
6
  import http from "http";
7
7
 
@@ -41,950 +41,11 @@ var log = {
41
41
  error: logError
42
42
  };
43
43
 
44
- // src/dynamic_page.ts
45
- import fs from "fs";
46
- import path from "path";
47
- import esbuild from "esbuild";
48
- import { fileURLToPath } from "url";
49
-
50
- // src/shared/serverElements.ts
51
- var createBuildableElement = (tag) => {
52
- return (options2, ...children) => ({
53
- tag,
54
- options: options2 || {},
55
- children
56
- });
57
- };
58
- var createChildrenlessBuildableElement = (tag) => {
59
- return (options2) => ({
60
- tag,
61
- options: options2 || {},
62
- children: null
63
- });
64
- };
65
- var childrenlessElementTags = [
66
- "area",
67
- "base",
68
- "br",
69
- "col",
70
- "embed",
71
- "hr",
72
- "img",
73
- "input",
74
- "link",
75
- "meta",
76
- "source",
77
- "track",
78
- "path",
79
- "rect"
80
- ];
81
- var elementTags = [
82
- "a",
83
- "address",
84
- "article",
85
- "aside",
86
- "audio",
87
- "blockquote",
88
- "body",
89
- "button",
90
- "canvas",
91
- "caption",
92
- "colgroup",
93
- "data",
94
- "datalist",
95
- "dd",
96
- "del",
97
- "details",
98
- "dialog",
99
- "div",
100
- "dl",
101
- "dt",
102
- "fieldset",
103
- "figcaption",
104
- "figure",
105
- "footer",
106
- "form",
107
- "h1",
108
- "h2",
109
- "h3",
110
- "h4",
111
- "h5",
112
- "h6",
113
- "head",
114
- "header",
115
- "hgroup",
116
- "html",
117
- "iframe",
118
- "ins",
119
- "label",
120
- "legend",
121
- "li",
122
- "main",
123
- "map",
124
- "meter",
125
- "nav",
126
- "noscript",
127
- "object",
128
- "ol",
129
- "optgroup",
130
- "option",
131
- "output",
132
- "p",
133
- "picture",
134
- "pre",
135
- "progress",
136
- "q",
137
- "section",
138
- "select",
139
- "summary",
140
- "table",
141
- "tbody",
142
- "td",
143
- "template",
144
- "textarea",
145
- "tfoot",
146
- "th",
147
- "thead",
148
- "time",
149
- "tr",
150
- "ul",
151
- "video",
152
- "span",
153
- "script",
154
- "abbr",
155
- "b",
156
- "bdi",
157
- "bdo",
158
- "cite",
159
- "code",
160
- "dfn",
161
- "em",
162
- "i",
163
- "kbd",
164
- "mark",
165
- "rp",
166
- "rt",
167
- "ruby",
168
- "s",
169
- "samp",
170
- "small",
171
- "strong",
172
- "sub",
173
- "sup",
174
- "u",
175
- "wbr",
176
- "title",
177
- "svg"
178
- ];
179
- var elements = {};
180
- var childrenlessElements = {};
181
- for (const element of elementTags) {
182
- elements[element] = createBuildableElement(element);
183
- }
184
- for (const element of childrenlessElementTags) {
185
- childrenlessElements[element] = createChildrenlessBuildableElement(element);
186
- }
187
- var allElements = {
188
- ...elements,
189
- ...childrenlessElements
190
- };
191
-
192
- // src/shared/bindServerElements.ts
193
- Object.assign(globalThis, elements);
194
- Object.assign(globalThis, childrenlessElements);
195
-
196
- // src/server/render.ts
197
- var renderRecursively = (element) => {
198
- let returnString = "";
199
- if (typeof element === "boolean") return returnString;
200
- else if (typeof element === "number" || typeof element === "string") {
201
- return returnString + element;
202
- } else if (Array.isArray(element)) {
203
- return returnString + element.join(", ");
204
- }
205
- returnString += `<${element.tag}`;
206
- if (typeof element.options === "object") {
207
- const {
208
- tag: elementTag,
209
- options: elementOptions,
210
- children: elementChildren
211
- } = element.options;
212
- if (elementTag !== void 0 && elementOptions !== void 0 && elementChildren !== void 0) {
213
- const children = element.children;
214
- element.children = [
215
- element.options,
216
- ...children
217
- ];
218
- element.options = {};
219
- } else {
220
- for (const [attrName, attrValue] of Object.entries(element.options)) {
221
- if (typeof attrValue === "object") {
222
- throw `Attr ${attrName}, for element ${element.tag} has obj type. Got: ${JSON.stringify(element, null, 2)}`;
223
- }
224
- returnString += ` ${attrName.toLowerCase()}="${attrValue}"`;
225
- }
226
- }
227
- } else if (typeof element.options !== "object" && element.options !== void 0) {
228
- element.children = [element.options, ...element.children || []];
229
- }
230
- if (element.children === null) {
231
- returnString += "/>";
232
- return returnString;
233
- }
234
- returnString += ">";
235
- for (const child2 of element.children) {
236
- returnString += renderRecursively(child2);
237
- }
238
- returnString += `</${element.tag}>`;
239
- return returnString;
240
- };
241
- var serverSideRenderPage = async (page, pathname) => {
242
- if (!page) {
243
- throw `No Page Provided.`;
244
- }
245
- if (typeof page === "function") {
246
- throw `Unbuilt page provided to ssr page.`;
247
- }
248
- const bodyHTML = renderRecursively(page);
249
- return {
250
- bodyHTML
251
- };
252
- };
253
-
254
- // src/server/generateHTMLTemplate.ts
255
- var generateHTMLTemplate = async ({
256
- pageURL,
257
- head: head2,
258
- serverData = null,
259
- addPageScriptTag = true,
260
- name,
261
- requiredClientModules = [],
262
- environment
263
- }) => {
264
- let StartTemplate = `<meta name="viewport" content="width=device-width, initial-scale=1.0">`;
265
- if (environment === "production") {
266
- StartTemplate += `<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">`;
267
- }
268
- StartTemplate += '<meta charset="UTF-8">';
269
- for (const module of requiredClientModules) {
270
- StartTemplate += `<script data-module="true" src="/shipped/${module}.js" defer="true"></script>`;
271
- }
272
- if (addPageScriptTag === true) {
273
- StartTemplate += `<script data-page="true" type="module" src="${pageURL === "" ? "" : "/"}${pageURL}/${name}_data.js" defer="true"></script>`;
274
- }
275
- StartTemplate += `<script type="module" src="/client.js" defer="true"></script>`;
276
- let builtHead;
277
- if (head2.constructor.name === "AsyncFunction") {
278
- builtHead = await head2();
279
- } else {
280
- builtHead = head2();
281
- }
282
- let HTMLTemplate = renderRecursively(builtHead);
283
- if (serverData) {
284
- HTMLTemplate += serverData;
285
- }
286
- return {
287
- internals: StartTemplate,
288
- builtMetadata: HTMLTemplate
289
- };
290
- };
291
-
292
- // src/server/createState.ts
293
- if (!globalThis.__SERVER_CURRENT_STATE_ID__) {
294
- globalThis.__SERVER_CURRENT_STATE_ID__ = 1;
295
- }
296
- var initializeState = () => {
297
- globalThis.__SERVER_CURRENT_STATE__ = [];
298
- };
299
- var getState = () => {
300
- return globalThis.__SERVER_CURRENT_STATE__;
301
- };
302
- var initializeObjectAttributes = () => globalThis.__SERVER_CURRENT_OBJECT_ATTRIBUTES__ = [];
303
- var getObjectAttributes = () => {
304
- return globalThis.__SERVER_CURRENT_OBJECT_ATTRIBUTES__;
305
- };
306
-
307
- // src/server/loadHook.ts
308
- var resetLoadHooks = () => globalThis.__SERVER_CURRENT_LOADHOOKS__ = [];
309
- var getLoadHooks = () => globalThis.__SERVER_CURRENT_LOADHOOKS__;
310
-
311
- // src/dynamic_page.ts
312
- var packageDir = process.env.PACKAGE_PATH;
313
- if (packageDir === void 0) {
314
- const __filename2 = fileURLToPath(import.meta.url);
315
- const __dirname2 = path.dirname(__filename2);
316
- packageDir = path.resolve(__dirname2, "..");
317
- }
318
- var elementKey = 0;
319
- var processOptionAsObjectAttribute = (element, optionName, optionValue, objectAttributes) => {
320
- const lcOptionName = optionName.toLowerCase();
321
- const options2 = element.options;
322
- let key = options2.key;
323
- if (key == void 0) {
324
- key = elementKey += 1;
325
- options2.key = key;
326
- }
327
- if (!optionValue.type) {
328
- throw `ObjectAttributeType is missing from object attribute. ${element.tag}: ${optionName}/${optionValue}`;
329
- }
330
- let optionFinal = lcOptionName;
331
- switch (optionValue.type) {
332
- case 1 /* STATE */:
333
- const SOA = optionValue;
334
- if (typeof SOA.value === "function") {
335
- delete options2[optionName];
336
- break;
337
- }
338
- if (lcOptionName === "innertext" || lcOptionName === "innerhtml") {
339
- element.children = [SOA.value];
340
- delete options2[optionName];
341
- } else {
342
- delete options2[optionName];
343
- options2[lcOptionName] = SOA.value;
344
- }
345
- break;
346
- case 2 /* OBSERVER */:
347
- const OOA = optionValue;
348
- const firstValue = OOA.update(...OOA.initialValues);
349
- if (lcOptionName === "innertext" || lcOptionName === "innerhtml") {
350
- element.children = [firstValue];
351
- delete options2[optionName];
352
- } else {
353
- delete options2[optionName];
354
- options2[lcOptionName] = firstValue;
355
- }
356
- optionFinal = optionName;
357
- break;
358
- case 4 /* REFERENCE */:
359
- options2["ref"] = optionValue.value;
360
- break;
361
- }
362
- objectAttributes.push({ ...optionValue, key, attribute: optionFinal });
363
- };
364
- var processPageElements = async (element, objectAttributes, parent) => {
365
- if (typeof element === "boolean" || typeof element === "number" || Array.isArray(element)) return element;
366
- if (typeof element === "string") {
367
- return element;
368
- }
369
- const processElementOptionsAsChildAndReturn = async () => {
370
- const children = element.children;
371
- element.children = [
372
- element.options,
373
- ...children
374
- ];
375
- element.options = {};
376
- for (let i = 0; i < children.length + 1; i++) {
377
- const child2 = element.children[i];
378
- const processedChild = await processPageElements(child2, objectAttributes, element);
379
- element.children[i] = processedChild;
380
- }
381
- return {
382
- ...element,
383
- options: {}
384
- };
385
- };
386
- if (typeof element.options !== "object") {
387
- return await processElementOptionsAsChildAndReturn();
388
- }
389
- const {
390
- tag: elementTag,
391
- options: elementOptions,
392
- children: elementChildren
393
- } = element.options;
394
- if (elementTag && elementOptions && elementChildren) {
395
- return await processElementOptionsAsChildAndReturn();
396
- }
397
- const options2 = element.options;
398
- for (const [optionName, optionValue] of Object.entries(options2)) {
399
- const lcOptionName = optionName.toLowerCase();
400
- if (typeof optionValue !== "object") {
401
- if (lcOptionName === "innertext") {
402
- delete options2[optionName];
403
- if (element.children === null) {
404
- throw `Cannot use innerText or innerHTML on childrenless elements.`;
405
- }
406
- element.children = [optionValue, ...element.children];
407
- continue;
408
- } else if (lcOptionName === "innerhtml") {
409
- if (element.children === null) {
410
- throw `Cannot use innerText or innerHTML on childrenless elements.`;
411
- }
412
- delete options2[optionName];
413
- element.children = [optionValue];
414
- continue;
415
- }
416
- continue;
417
- }
418
- ;
419
- processOptionAsObjectAttribute(element, optionName, optionValue, objectAttributes);
420
- }
421
- if (element.children) {
422
- for (let i = 0; i < element.children.length; i++) {
423
- const child2 = element.children[i];
424
- const processedChild = await processPageElements(child2, objectAttributes, element);
425
- element.children[i] = processedChild;
426
- }
427
- }
428
- return element;
429
- };
430
- var generateSuitablePageElements = async (pageLocation, pageElements, metadata, DIST_DIR, pageName, requiredClientModules) => {
431
- if (typeof pageElements === "string" || typeof pageElements === "boolean" || typeof pageElements === "number" || Array.isArray(pageElements)) {
432
- return [];
433
- }
434
- const objectAttributes = [];
435
- const processedPageElements = await processPageElements(pageElements, objectAttributes, []);
436
- elementKey = 0;
437
- const renderedPage = await serverSideRenderPage(
438
- processedPageElements,
439
- pageLocation
440
- );
441
- const template = await generateHTMLTemplate({
442
- pageURL: path.relative(DIST_DIR, pageLocation),
443
- head: metadata,
444
- addPageScriptTag: true,
445
- name: pageName,
446
- requiredClientModules,
447
- environment: "production"
448
- });
449
- const resultHTML = `<!DOCTYPE html>${template}${renderedPage.bodyHTML}`;
450
- return {
451
- objectAttributes,
452
- resultHTML
453
- };
454
- };
455
- var generateClientPageData = async (pageLocation, state, objectAttributes, pageLoadHooks, DIST_DIR, pageName) => {
456
- const pageDiff = path.relative(DIST_DIR, pageLocation);
457
- let clientPageJSText = `${globalThis.__SERVER_PAGE_DATA_BANNER__}
458
- /*ELEGANCE_JS*/
459
- let url="${pageDiff === "" ? "/" : `/${pageDiff}`}";`;
460
- {
461
- clientPageJSText += `export const data = {`;
462
- if (state) {
463
- const nonBoundState = state.filter((subj) => subj.bind === void 0);
464
- clientPageJSText += `state:[`;
465
- for (const subject of nonBoundState) {
466
- if (typeof subject.value === "string") {
467
- const stringified = JSON.stringify(subject.value);
468
- clientPageJSText += `{id:${subject.id},value:${stringified}},`;
469
- } else if (typeof subject.value === "function") {
470
- clientPageJSText += `{id:${subject.id},value:${subject.value.toString()}},`;
471
- } else {
472
- clientPageJSText += `{id:${subject.id},value:${JSON.stringify(subject.value)}},`;
473
- }
474
- }
475
- clientPageJSText += `],`;
476
- const formattedBoundState = {};
477
- const stateBinds = state.map((subj) => subj.bind).filter((bind) => bind !== void 0);
478
- for (const bind of stateBinds) {
479
- formattedBoundState[bind] = [];
480
- }
481
- ;
482
- const boundState = state.filter((subj) => subj.bind !== void 0);
483
- for (const subject of boundState) {
484
- const bindingState = formattedBoundState[subject.bind];
485
- delete subject.bind;
486
- bindingState.push(subject);
487
- }
488
- const bindSubjectPairing = Object.entries(formattedBoundState);
489
- if (bindSubjectPairing.length > 0) {
490
- clientPageJSText += "binds:{";
491
- for (const [bind, subjects] of bindSubjectPairing) {
492
- clientPageJSText += `${bind}:[`;
493
- for (const subject of subjects) {
494
- if (typeof subject.value === "string") {
495
- clientPageJSText += `{id:${subject.id},value:${JSON.stringify(subject.value)}},`;
496
- } else {
497
- clientPageJSText += `{id:${subject.id},value:${JSON.stringify(subject.value)}},`;
498
- }
499
- }
500
- clientPageJSText += "]";
501
- }
502
- clientPageJSText += "},";
503
- }
504
- }
505
- const stateObjectAttributes = objectAttributes.filter((oa) => oa.type === 1 /* STATE */);
506
- if (stateObjectAttributes.length > 0) {
507
- const processed = [...stateObjectAttributes].map((soa) => {
508
- delete soa.type;
509
- return soa;
510
- });
511
- clientPageJSText += `soa:${JSON.stringify(processed)},`;
512
- }
513
- const observerObjectAttributes = objectAttributes.filter((oa) => oa.type === 2 /* OBSERVER */);
514
- if (observerObjectAttributes.length > 0) {
515
- let observerObjectAttributeString = "ooa:[";
516
- for (const observerObjectAttribute of observerObjectAttributes) {
517
- const ooa = observerObjectAttribute;
518
- observerObjectAttributeString += `{key:${ooa.key},attribute:"${ooa.attribute}",update:${ooa.update.toString()},`;
519
- observerObjectAttributeString += `refs:[`;
520
- for (const ref of ooa.refs) {
521
- observerObjectAttributeString += `{id:${ref.id}`;
522
- if (ref.bind !== void 0) observerObjectAttributeString += `,bind:${ref.bind}`;
523
- observerObjectAttributeString += "},";
524
- }
525
- observerObjectAttributeString += "]},";
526
- }
527
- observerObjectAttributeString += "],";
528
- clientPageJSText += observerObjectAttributeString;
529
- }
530
- if (pageLoadHooks.length > 0) {
531
- clientPageJSText += "lh:[";
532
- for (const loadHook of pageLoadHooks) {
533
- const key = loadHook.bind;
534
- clientPageJSText += `{fn:${loadHook.fn},bind:"${key || ""}"},`;
535
- }
536
- clientPageJSText += "],";
537
- }
538
- clientPageJSText += `};`;
539
- }
540
- clientPageJSText += "if(!globalThis.pd) { globalThis.pd = {}; globalThis.pd[url] = data}";
541
- const pageDataPath = path.join(pageLocation, `${pageName}_data.js`);
542
- let sendHardReloadInstruction = false;
543
- const transformedResult = await esbuild.transform(clientPageJSText, { minify: true }).catch((error) => {
544
- console.error("Failed to transform client page js!", error);
545
- });
546
- if (!transformedResult) return { sendHardReloadInstruction };
547
- fs.writeFileSync(pageDataPath, transformedResult.code, "utf-8");
548
- return { sendHardReloadInstruction };
549
- };
550
- var buildDynamicPage = async (filePath, DIST_DIR, req, res) => {
551
- let pageElements;
552
- let metadata;
553
- initializeState();
554
- initializeObjectAttributes();
555
- resetLoadHooks();
556
- globalThis.__SERVER_PAGE_DATA_BANNER__ = "";
557
- globalThis.__SERVER_CURRENT_STATE_ID__ = 1;
558
- let modules = [];
559
- try {
560
- const {
561
- construct
562
- } = await import("file://" + filePath);
563
- const {
564
- page,
565
- metadata: pageMetadata,
566
- isDynamicPage,
567
- requestHook,
568
- requiredClientModules
569
- } = construct();
570
- if (requiredClientModules !== void 0) {
571
- modules = requiredClientModules;
572
- }
573
- if (typeof requestHook === "function") {
574
- if (requestHook.constructor.name === "AsyncFunction") {
575
- const doProcessRequest = await requestHook(req, res);
576
- if (doProcessRequest !== void 0 == doProcessRequest === false) {
577
- return false;
578
- }
579
- } else {
580
- const doProcessRequest = requestHook(req, res);
581
- if (doProcessRequest !== void 0 == doProcessRequest === false) {
582
- return false;
583
- }
584
- }
585
- }
586
- pageElements = page;
587
- metadata = pageMetadata;
588
- if (isDynamicPage === false) {
589
- throw new Error("Cannot dynamically render a non-dynamic page.");
590
- }
591
- } catch (e) {
592
- throw `${filePath} - ${e}
593
- ${e?.stack ?? "No stack."}
594
-
595
- `;
596
- }
597
- if (!metadata || metadata && typeof metadata !== "function") {
598
- console.warn(`WARNING: Dynamic ${filePath} does not export a metadata function. This is *highly* recommended.`);
599
- }
600
- if (!pageElements) {
601
- console.warn(`WARNING: Dynamic ${filePath} should export a const page, which is of type BuiltElement<"body">.`);
602
- }
603
- if (typeof pageElements === "function") {
604
- if (pageElements.constructor.name === "AsyncFunction") {
605
- pageElements = await pageElements();
606
- } else {
607
- pageElements = pageElements();
608
- }
609
- }
610
- const state = getState();
611
- const pageLoadHooks = getLoadHooks();
612
- const objectAttributes = getObjectAttributes();
613
- const foundObjectAttributes = await generateSuitablePageElements(
614
- path.dirname(filePath),
615
- pageElements || body(),
616
- metadata ?? (() => head()),
617
- DIST_DIR,
618
- "page",
619
- modules
620
- );
621
- await generateClientPageData(
622
- path.dirname(filePath),
623
- state || {},
624
- [...objectAttributes, ...foundObjectAttributes.objectAttributes],
625
- pageLoadHooks || [],
626
- DIST_DIR,
627
- "page"
628
- );
629
- return foundObjectAttributes.resultHTML;
630
- };
631
-
632
- // src/server/server.ts
633
- import { createServer as createHttpServer } from "http";
634
- import { promises as fs2 } from "fs";
635
- import { join, normalize, extname, dirname, resolve } from "path";
636
- import { pathToFileURL } from "url";
637
- import { gzip, deflate } from "zlib";
638
- import { promisify } from "util";
639
- var gzipAsync = promisify(gzip);
640
- var deflateAsync = promisify(deflate);
641
- var MIME_TYPES = {
642
- ".html": "text/html; charset=utf-8",
643
- ".css": "text/css; charset=utf-8",
644
- ".js": "application/javascript; charset=utf-8",
645
- ".json": "application/json; charset=utf-8",
646
- ".png": "image/png",
647
- ".jpg": "image/jpeg",
648
- ".jpeg": "image/jpeg",
649
- ".gif": "image/gif",
650
- ".svg": "image/svg+xml",
651
- ".ico": "image/x-icon",
652
- ".txt": "text/plain; charset=utf-8"
653
- };
654
- function startServer({
655
- root,
656
- port = 3e3,
657
- host = "localhost",
658
- environment = "production",
659
- DIST_DIR
660
- }) {
661
- if (!root) throw new Error("Root directory must be specified.");
662
- root = normalize(root).replace(/[\\/]+$/, "");
663
- const requestHandler = async (req, res) => {
664
- try {
665
- if (!req.url) {
666
- await sendResponse(req, res, 400, { "Content-Type": "text/plain; charset=utf-8" }, "Bad Request");
667
- return;
668
- }
669
- res.setHeader("Access-Control-Allow-Origin", "*");
670
- res.setHeader("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE,OPTIONS");
671
- res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
672
- if (req.method === "OPTIONS") {
673
- res.writeHead(204);
674
- res.end();
675
- if (environment === "development") {
676
- log.info(req.method, "::", req.url, "-", res.statusCode);
677
- }
678
- return;
679
- }
680
- const url = new URL(req.url, `http://${req.headers.host}`);
681
- if (url.pathname.startsWith("/api/")) {
682
- await handleApiRequest(root, url.pathname, req, res);
683
- } else {
684
- await handleStaticRequest(root, url.pathname, req, res, DIST_DIR);
685
- }
686
- if (environment === "development") {
687
- log.info(req.method, "::", req.url, "-", res.statusCode);
688
- }
689
- } catch (err) {
690
- log.error(err);
691
- await sendResponse(req, res, 500, { "Content-Type": "text/plain; charset=utf-8" }, "Internal Server Error");
692
- }
693
- };
694
- function attemptListen(p) {
695
- const server = createHttpServer(requestHandler);
696
- server.on("error", (err) => {
697
- if (err.code === "EADDRINUSE") {
698
- attemptListen(p + 1);
699
- } else {
700
- console.error(err);
701
- }
702
- });
703
- server.listen(p, host, () => {
704
- log.info(`Server running at http://${host}:${p}/`);
705
- });
706
- return server;
707
- }
708
- return attemptListen(port);
709
- }
710
- async function handleStaticRequest(root, pathname, req, res, DIST_DIR) {
711
- const originalPathname = pathname;
712
- let filePath = normalize(join(root, decodeURIComponent(pathname))).replace(/[\\/]+$/, "");
713
- if (!filePath.startsWith(root)) {
714
- await sendResponse(req, res, 403, { "Content-Type": "text/plain; charset=utf-8" }, "Forbidden");
715
- return;
716
- }
717
- let stats;
718
- try {
719
- stats = await fs2.stat(filePath);
720
- } catch {
721
- }
722
- let pageDir;
723
- if (stats) {
724
- if (stats.isDirectory()) {
725
- pageDir = filePath;
726
- } else {
727
- pageDir = dirname(filePath);
728
- }
729
- } else {
730
- if (originalPathname.endsWith("/")) {
731
- pageDir = filePath;
732
- } else {
733
- pageDir = dirname(filePath);
734
- }
735
- }
736
- const relDir = pageDir.slice(root.length).replace(/^[\/\\]+/, "");
737
- const parts = relDir.split(/[\\/]/).filter(Boolean);
738
- const middlewareDirs = [];
739
- let current = root;
740
- middlewareDirs.push(current);
741
- for (const part of parts) {
742
- current = join(current, part);
743
- middlewareDirs.push(current);
744
- }
745
- const middlewares = [];
746
- for (const dir of middlewareDirs) {
747
- const mwPath = join(dir, "middleware.mjs");
748
- let mwModule;
749
- try {
750
- await fs2.access(mwPath);
751
- const url = pathToFileURL(mwPath).href;
752
- mwModule = await import(url);
753
- } catch {
754
- continue;
755
- }
756
- const mwKeys = Object.keys(mwModule).sort();
757
- for (const key of mwKeys) {
758
- const f = mwModule[key];
759
- if (typeof f === "function" && !middlewares.some((existing) => existing === f)) {
760
- middlewares.push(f);
761
- }
762
- }
763
- }
764
- let isDynamic = false;
765
- let handlerPath = filePath;
766
- if (stats && stats.isDirectory()) {
767
- const pageMjsPath = join(filePath, "page.mjs");
768
- try {
769
- await fs2.access(pageMjsPath);
770
- handlerPath = pageMjsPath;
771
- isDynamic = true;
772
- } catch {
773
- handlerPath = join(filePath, "index.html");
774
- isDynamic = false;
775
- }
776
- } else {
777
- handlerPath = filePath;
778
- isDynamic = false;
779
- }
780
- let hasHandler = false;
781
- try {
782
- await fs2.access(handlerPath);
783
- hasHandler = true;
784
- } catch {
785
- }
786
- const finalHandler = async (req2, res2) => {
787
- if (!hasHandler) {
788
- await respondWithErrorPage(root, pathname, 404, req2, res2);
789
- return;
790
- }
791
- if (isDynamic) {
792
- try {
793
- const resultHTML = await buildDynamicPage(resolve(handlerPath), DIST_DIR, req2, res2);
794
- if (resultHTML === false) {
795
- return;
796
- }
797
- await sendResponse(req2, res2, 200, { "Content-Type": MIME_TYPES[".html"] }, resultHTML);
798
- } catch (err) {
799
- log.error("Error building dynamic page -", err);
800
- }
801
- } else {
802
- const ext = extname(handlerPath).toLowerCase();
803
- const contentType = MIME_TYPES[ext] || "application/octet-stream";
804
- const data = await fs2.readFile(handlerPath);
805
- await sendResponse(req2, res2, 200, { "Content-Type": contentType }, data);
806
- }
807
- };
808
- const composed = composeMiddlewares(middlewares, finalHandler, { isApi: false, root, pathname });
809
- await composed(req, res);
810
- }
811
- async function handleApiRequest(root, pathname, req, res) {
812
- const apiSubPath = pathname.slice("/api/".length);
813
- const parts = apiSubPath.split("/").filter(Boolean);
814
- const routeDir = join(root, pathname);
815
- const routePath = join(routeDir, "route.mjs");
816
- let hasRoute = false;
817
- try {
818
- await fs2.access(routePath);
819
- hasRoute = true;
820
- } catch {
821
- }
822
- let fn = null;
823
- let module = null;
824
- if (hasRoute) {
825
- try {
826
- const moduleUrl = pathToFileURL(routePath).href;
827
- module = await import(moduleUrl);
828
- fn = module[req.method];
829
- } catch (err) {
830
- console.error(err);
831
- return respondWithJsonError(req, res, 500, "Internal Server Error");
832
- }
833
- }
834
- const middlewareDirs = [];
835
- let current = join(root, "api");
836
- middlewareDirs.push(current);
837
- for (const part of parts) {
838
- current = join(current, part);
839
- middlewareDirs.push(current);
840
- }
841
- const middlewares = [];
842
- for (const dir of middlewareDirs) {
843
- const mwPath = join(dir, "middleware.mjs");
844
- let mwModule;
845
- try {
846
- await fs2.access(mwPath);
847
- const url = pathToFileURL(mwPath).href;
848
- mwModule = await import(url);
849
- } catch {
850
- continue;
851
- }
852
- const mwKeys = Object.keys(mwModule).sort();
853
- for (const key of mwKeys) {
854
- const f = mwModule[key];
855
- if (typeof f === "function" && !middlewares.some((existing) => existing === f)) {
856
- middlewares.push(f);
857
- }
858
- }
859
- }
860
- const finalHandler = async (req2, res2) => {
861
- if (!hasRoute) {
862
- return respondWithJsonError(req2, res2, 404, "Not Found");
863
- }
864
- if (typeof fn !== "function") {
865
- return respondWithJsonError(req2, res2, 405, "Method Not Allowed");
866
- }
867
- await fn(req2, res2);
868
- };
869
- const composed = composeMiddlewares(middlewares, finalHandler, { isApi: true });
870
- await composed(req, res);
871
- }
872
- function composeMiddlewares(mws, final, options2) {
873
- return async function(req, res) {
874
- let index = 0;
875
- async function dispatch(err) {
876
- if (err) {
877
- if (options2.isApi) {
878
- return respondWithJsonError(req, res, 500, err.message || "Internal Server Error");
879
- } else {
880
- return await respondWithErrorPage(options2.root, options2.pathname, 500, req, res);
881
- }
882
- }
883
- if (index >= mws.length) {
884
- return await final(req, res);
885
- }
886
- const thisMw = mws[index++];
887
- const next = (e) => dispatch(e);
888
- const onceNext = (nextFn) => {
889
- let called = false;
890
- return async (e) => {
891
- if (called) {
892
- log.warn("next() was called in a middleware more than once.");
893
- return;
894
- }
895
- called = true;
896
- await nextFn(e);
897
- };
898
- };
899
- try {
900
- await thisMw(req, res, onceNext(next));
901
- } catch (error) {
902
- await dispatch(error);
903
- }
904
- }
905
- await dispatch();
906
- };
907
- }
908
- async function respondWithJsonError(req, res, code, message) {
909
- const body2 = JSON.stringify({ error: message });
910
- await sendResponse(req, res, code, { "Content-Type": "application/json; charset=utf-8" }, body2);
911
- }
912
- async function respondWithErrorPage(root, pathname, code, req, res) {
913
- let currentPath = normalize(join(root, decodeURIComponent(pathname)));
914
- let tried = /* @__PURE__ */ new Set();
915
- let errorFilePath = null;
916
- while (currentPath.startsWith(root)) {
917
- const candidate = join(currentPath, `${code}.html`);
918
- if (!tried.has(candidate)) {
919
- try {
920
- await fs2.access(candidate);
921
- errorFilePath = candidate;
922
- break;
923
- } catch {
924
- }
925
- tried.add(candidate);
926
- }
927
- const parent = dirname(currentPath);
928
- if (parent === currentPath) break;
929
- currentPath = parent;
930
- }
931
- if (!errorFilePath) {
932
- const fallback = join(root, `${code}.html`);
933
- try {
934
- await fs2.access(fallback);
935
- errorFilePath = fallback;
936
- } catch {
937
- }
938
- }
939
- if (errorFilePath) {
940
- try {
941
- const html = await fs2.readFile(errorFilePath, "utf8");
942
- await sendResponse(req, res, code, { "Content-Type": "text/html; charset=utf-8" }, html);
943
- return;
944
- } catch {
945
- }
946
- }
947
- await sendResponse(req, res, code, { "Content-Type": "text/plain; charset=utf-8" }, `${code} Error`);
948
- }
949
- function isCompressible(contentType) {
950
- if (!contentType) return false;
951
- return /text\/|javascript|json|xml|svg/.test(contentType);
952
- }
953
- async function sendResponse(req, res, status, headers, body2) {
954
- if (typeof body2 === "string") {
955
- body2 = Buffer.from(body2);
956
- }
957
- const accept = req.headers["accept-encoding"] || "";
958
- let encoding = null;
959
- if (accept.match(/\bgzip\b/)) {
960
- encoding = "gzip";
961
- } else if (accept.match(/\bdeflate\b/)) {
962
- encoding = "deflate";
963
- }
964
- if (!encoding || !isCompressible(headers["Content-Type"] || "")) {
965
- res.writeHead(status, headers);
966
- res.end(body2);
967
- return;
968
- }
969
- const compressor = encoding === "gzip" ? gzipAsync : deflateAsync;
970
- try {
971
- const compressed = await compressor(body2);
972
- headers["Content-Encoding"] = encoding;
973
- headers["Vary"] = "Accept-Encoding";
974
- res.writeHead(status, headers);
975
- res.end(compressed);
976
- } catch (err) {
977
- log.error("Compression error:", err);
978
- res.writeHead(status, headers);
979
- res.end(body2);
980
- }
981
- }
982
-
983
44
  // src/build.ts
984
- var __filename = fileURLToPath3(import.meta.url);
985
- var __dirname = path2.dirname(__filename);
986
- var packageDir2 = path2.resolve(__dirname, "..");
987
- var builderPath = path2.resolve(packageDir2, "./dist/page_compiler.mjs");
45
+ var __filename = fileURLToPath(import.meta.url);
46
+ var __dirname = path.dirname(__filename);
47
+ var packageDir = path.resolve(__dirname, "..");
48
+ var builderPath = path.resolve(packageDir, "./dist/page_compiler.mjs");
988
49
  var yellow = (text) => {
989
50
  return `\x1B[38;2;238;184;68m${text}`;
990
51
  };
@@ -1003,11 +64,11 @@ var finishLog = (...text) => {
1003
64
  var options = process.env.OPTIONS;
1004
65
  var getAllSubdirectories = (dir, baseDir = dir) => {
1005
66
  let directories = [];
1006
- const items = fs3.readdirSync(dir, { withFileTypes: true });
67
+ const items = fs.readdirSync(dir, { withFileTypes: true });
1007
68
  for (const item of items) {
1008
69
  if (item.isDirectory()) {
1009
- const fullPath = path2.join(dir, item.name);
1010
- const relativePath = path2.relative(baseDir, fullPath);
70
+ const fullPath = path.join(dir, item.name);
71
+ const relativePath = path.relative(baseDir, fullPath);
1011
72
  directories.push(relativePath);
1012
73
  directories = directories.concat(getAllSubdirectories(fullPath, baseDir));
1013
74
  }
@@ -1027,7 +88,7 @@ var runBuild = (filepath, DIST_DIR) => {
1027
88
  }
1028
89
  child = child_process.spawn("node", [filepath], {
1029
90
  stdio: ["inherit", "inherit", "inherit", "ipc"],
1030
- env: { ...process.env, DIST_DIR, OPTIONS: optionsString, PACKAGE_PATH: packageDir2 }
91
+ env: { ...process.env, DIST_DIR, OPTIONS: optionsString, PACKAGE_PATH: packageDir }
1031
92
  });
1032
93
  child.on("error", () => {
1033
94
  log.error("Failed to start child process.");
@@ -1054,9 +115,6 @@ var runBuild = (filepath, DIST_DIR) => {
1054
115
  );
1055
116
  options.postCompile();
1056
117
  }
1057
- } else if (data === "set-layouts") {
1058
- globalThis.__SERVER_CURRENT_LAYOUTS__ = new Map(JSON.parse(message.layouts));
1059
- globalThis.__SERVER_CURRENT_LAYOUT_ID__ = parseInt(message.currentLayoutId);
1060
118
  }
1061
119
  });
1062
120
  };
@@ -1098,31 +156,22 @@ var compile = async (props) => {
1098
156
  options = props;
1099
157
  setQuiet(options.quiet ?? false);
1100
158
  const watch = options.hotReload !== void 0;
1101
- const BUILD_FLAG = path2.join(options.outputDirectory, "ELEGANCE_BUILD_FLAG");
1102
- if (!fs3.existsSync(options.outputDirectory)) {
1103
- fs3.mkdirSync(options.outputDirectory, { recursive: true });
1104
- fs3.writeFileSync(
1105
- path2.join(BUILD_FLAG),
159
+ const BUILD_FLAG = path.join(options.outputDirectory, "ELEGANCE_BUILD_FLAG");
160
+ if (!fs.existsSync(options.outputDirectory)) {
161
+ fs.mkdirSync(options.outputDirectory, { recursive: true });
162
+ fs.writeFileSync(
163
+ path.join(BUILD_FLAG),
1106
164
  "This file just marks this directory as one containing an Elegance Build.",
1107
165
  "utf-8"
1108
166
  );
1109
167
  } else {
1110
- if (!fs3.existsSync(BUILD_FLAG)) {
168
+ if (!fs.existsSync(BUILD_FLAG)) {
1111
169
  throw `The output directory already exists, but is not an Elegance Build directory.`;
1112
170
  }
1113
171
  }
1114
- const DIST_DIR = path2.join(props.outputDirectory, "dist");
1115
- if (!fs3.existsSync(DIST_DIR)) {
1116
- fs3.mkdirSync(DIST_DIR, { recursive: true });
1117
- }
1118
- if (props.server != void 0 && props.server.runServer == true) {
1119
- startServer({
1120
- root: props.server.root ?? DIST_DIR,
1121
- environment: props.environment,
1122
- port: props.server.port ?? 3e3,
1123
- host: props.server.host ?? "localhost",
1124
- DIST_DIR
1125
- });
172
+ const DIST_DIR = path.join(props.outputDirectory, "dist");
173
+ if (!fs.existsSync(DIST_DIR)) {
174
+ fs.mkdirSync(DIST_DIR, { recursive: true });
1126
175
  }
1127
176
  if (watch) {
1128
177
  await registerListener();
@@ -1134,12 +183,12 @@ var compile = async (props) => {
1134
183
  const dirs = options.hotReload?.extraWatchDirectories ?? [];
1135
184
  if (dirs.length !== 0) {
1136
185
  for (const dir of dirs) {
1137
- const subdirs = getAllSubdirectories(dir).map((f) => path2.join(dir, f));
186
+ const subdirs = getAllSubdirectories(dir).map((f) => path.join(dir, f));
1138
187
  extra.push(...subdirs);
1139
188
  }
1140
189
  }
1141
190
  }
1142
- const pagesSubDirs = getAllSubdirectories(options.pagesDirectory).map((f) => path2.join(options.pagesDirectory, f));
191
+ const pagesSubDirs = getAllSubdirectories(options.pagesDirectory).map((f) => path.join(options.pagesDirectory, f));
1143
192
  const subdirectories = [...pagesSubDirs, options.pagesDirectory, ...extra];
1144
193
  finishLog(yellow("Hot-Reload Watching Subdirectories: "), ...subdirectories.join(", "));
1145
194
  const watcherFn = async () => {
@@ -1152,7 +201,7 @@ var compile = async (props) => {
1152
201
  }, 100);
1153
202
  };
1154
203
  for (const directory of subdirectories) {
1155
- const watcher = fs3.watch(
204
+ const watcher = fs.watch(
1156
205
  directory,
1157
206
  {},
1158
207
  watcherFn