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