coralite 0.40.1 → 0.41.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/lib/collection-handlers.d.ts.map +1 -1
- package/dist/lib/component-setup.d.ts.map +1 -1
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/coralite-element.d.ts.map +1 -1
- package/dist/lib/coralite-element.js +36 -2
- package/dist/lib/coralite-element.js.map +2 -2
- package/dist/lib/coralite.d.ts +1 -1
- package/dist/lib/coralite.d.ts.map +1 -1
- package/dist/lib/index.js +261 -142
- package/dist/lib/index.js.map +3 -3
- package/dist/lib/renderer.d.ts.map +1 -1
- package/dist/lib/utils/client/runtime.d.ts.map +1 -1
- package/dist/lib/utils/server/render.d.ts +2 -1
- package/dist/lib/utils/server/render.d.ts.map +1 -1
- package/dist/plugins/testing.d.ts.map +1 -1
- package/dist/types/core.d.ts +26 -4
- package/dist/types/core.d.ts.map +1 -1
- package/dist/types/plugin.d.ts +5 -1
- package/dist/types/plugin.d.ts.map +1 -1
- package/llms.txt +76 -7
- package/package.json +5 -3
package/dist/lib/index.js
CHANGED
|
@@ -3460,59 +3460,106 @@ var staticAssetPlugin = (assets = []) => {
|
|
|
3460
3460
|
};
|
|
3461
3461
|
|
|
3462
3462
|
// plugins/testing.js
|
|
3463
|
-
function traverseAndAddTestId(children) {
|
|
3463
|
+
function traverseAndAddTestId(children, instanceId, { autoTestId = false, counters = {} } = {}) {
|
|
3464
3464
|
if (!Array.isArray(children)) {
|
|
3465
3465
|
return;
|
|
3466
3466
|
}
|
|
3467
3467
|
for (let i = 0; i < children.length; i++) {
|
|
3468
3468
|
const node = children[i];
|
|
3469
|
-
if (node.type === "tag"
|
|
3470
|
-
if (
|
|
3471
|
-
node.attribs["data-testid"]
|
|
3469
|
+
if (node.type === "tag") {
|
|
3470
|
+
if (node.attribs?.ref) {
|
|
3471
|
+
if (!node.attribs["data-testid"]) {
|
|
3472
|
+
const refValue = node.attribs.ref;
|
|
3473
|
+
const prefix = instanceId ? `${instanceId}__` : "";
|
|
3474
|
+
if (instanceId === "page" && refValue.includes("__")) {
|
|
3475
|
+
node.attribs["data-testid"] = refValue;
|
|
3476
|
+
} else {
|
|
3477
|
+
node.attribs["data-testid"] = `${prefix}${refValue}`;
|
|
3478
|
+
}
|
|
3479
|
+
}
|
|
3480
|
+
} else if (autoTestId && instanceId) {
|
|
3481
|
+
const tagName = node.name.toLowerCase();
|
|
3482
|
+
const isInteractive = [
|
|
3483
|
+
"button",
|
|
3484
|
+
"a",
|
|
3485
|
+
"input",
|
|
3486
|
+
"form",
|
|
3487
|
+
"select",
|
|
3488
|
+
"textarea"
|
|
3489
|
+
].includes(tagName) || node.attribs && (node.attribs.tabindex !== void 0 || node.attribs.role && ["button", "link", "checkbox"].includes(node.attribs.role)) || node.slots;
|
|
3490
|
+
if (isInteractive) {
|
|
3491
|
+
if (!counters[tagName]) {
|
|
3492
|
+
counters[tagName] = 0;
|
|
3493
|
+
}
|
|
3494
|
+
const index = counters[tagName]++;
|
|
3495
|
+
if (!node.attribs) {
|
|
3496
|
+
node.attribs = {};
|
|
3497
|
+
}
|
|
3498
|
+
if (!node.attribs["data-testid"]) {
|
|
3499
|
+
node.attribs["data-testid"] = `${instanceId}__${tagName}-${index}`;
|
|
3500
|
+
}
|
|
3501
|
+
}
|
|
3472
3502
|
}
|
|
3473
3503
|
}
|
|
3474
3504
|
if (node.children?.length > 0) {
|
|
3475
|
-
traverseAndAddTestId(node.children
|
|
3505
|
+
traverseAndAddTestId(node.children, instanceId, {
|
|
3506
|
+
autoTestId,
|
|
3507
|
+
counters
|
|
3508
|
+
});
|
|
3476
3509
|
}
|
|
3477
3510
|
}
|
|
3478
3511
|
}
|
|
3479
3512
|
var testingPlugin = definePlugin({
|
|
3480
3513
|
name: "testing",
|
|
3481
3514
|
server: {
|
|
3482
|
-
|
|
3483
|
-
|
|
3484
|
-
|
|
3485
|
-
const uniqueRefValue = `${instanceId}__${ref.name}`;
|
|
3486
|
-
if (ref.element.attribs) {
|
|
3487
|
-
const currentTestId = ref.element.attribs["data-testid"];
|
|
3488
|
-
if (!currentTestId || currentTestId === ref.name) {
|
|
3489
|
-
ref.element.attribs["data-testid"] = uniqueRefValue;
|
|
3490
|
-
}
|
|
3491
|
-
}
|
|
3515
|
+
onBeforeBuild: ({ app }) => {
|
|
3516
|
+
if (app.options.mode !== "testing") {
|
|
3517
|
+
return;
|
|
3492
3518
|
}
|
|
3519
|
+
app.options.externalStyles = app.options.externalStyles || [];
|
|
3520
|
+
const velocityStyle = `
|
|
3521
|
+
*, *::before, *::after {
|
|
3522
|
+
transition: none !important;
|
|
3523
|
+
animation: none !important;
|
|
3524
|
+
scroll-behavior: auto !important;
|
|
3525
|
+
}
|
|
3526
|
+
`.trim();
|
|
3527
|
+
app.options.externalStyles.push(`data:text/css;base64,${Buffer.from(velocityStyle).toString("base64")}`);
|
|
3493
3528
|
},
|
|
3494
|
-
|
|
3495
|
-
const
|
|
3496
|
-
|
|
3497
|
-
|
|
3529
|
+
onBeforeComponentRender: ({ instanceId, template, app }) => {
|
|
3530
|
+
const isTesting = app.options.mode === "testing";
|
|
3531
|
+
const counters = {};
|
|
3532
|
+
const templateNode = template;
|
|
3533
|
+
if (templateNode && templateNode.children) {
|
|
3534
|
+
traverseAndAddTestId(templateNode.children, instanceId, {
|
|
3535
|
+
autoTestId: isTesting,
|
|
3536
|
+
counters
|
|
3537
|
+
});
|
|
3498
3538
|
}
|
|
3499
3539
|
},
|
|
3500
|
-
onPageSet: ({ elements }) => {
|
|
3501
|
-
const
|
|
3502
|
-
|
|
3503
|
-
|
|
3504
|
-
|
|
3540
|
+
onPageSet: ({ elements, app }) => {
|
|
3541
|
+
const isTesting = app.options.mode === "testing";
|
|
3542
|
+
const counters = {};
|
|
3543
|
+
traverseAndAddTestId(elements?.root?.children, "page", {
|
|
3544
|
+
autoTestId: isTesting,
|
|
3545
|
+
counters
|
|
3546
|
+
});
|
|
3505
3547
|
}
|
|
3506
3548
|
},
|
|
3507
3549
|
client: {
|
|
3508
3550
|
onBeforeComponentRender: ({ instanceId, refs }) => {
|
|
3509
3551
|
for (let i = 0; i < refs.length; i++) {
|
|
3510
3552
|
const ref = refs[i];
|
|
3511
|
-
const
|
|
3553
|
+
const prefix = `${instanceId}__`;
|
|
3554
|
+
const uniqueRefValue = ref.element && ref.element.getAttribute("ref");
|
|
3512
3555
|
if (ref.element && ref.element.setAttribute) {
|
|
3513
3556
|
const currentTestId = ref.element.getAttribute("data-testid");
|
|
3514
3557
|
if (!currentTestId || currentTestId === ref.name) {
|
|
3515
|
-
|
|
3558
|
+
if (uniqueRefValue && uniqueRefValue.startsWith(prefix)) {
|
|
3559
|
+
ref.element.setAttribute("data-testid", uniqueRefValue);
|
|
3560
|
+
} else {
|
|
3561
|
+
ref.element.setAttribute("data-testid", `${prefix}${ref.name}`);
|
|
3562
|
+
}
|
|
3516
3563
|
}
|
|
3517
3564
|
}
|
|
3518
3565
|
}
|
|
@@ -4190,8 +4237,15 @@ function createComponentDefinition({ app }) {
|
|
|
4190
4237
|
}
|
|
4191
4238
|
}
|
|
4192
4239
|
}
|
|
4193
|
-
|
|
4194
|
-
|
|
4240
|
+
let serverToExecute = server;
|
|
4241
|
+
if (app.options.mode === "testing" && app.options.testing?.mocks) {
|
|
4242
|
+
const mock = app.options.testing.mocks[module.id];
|
|
4243
|
+
if (mock && typeof mock.server === "function") {
|
|
4244
|
+
serverToExecute = mock.server;
|
|
4245
|
+
}
|
|
4246
|
+
}
|
|
4247
|
+
if (typeof serverToExecute === "function") {
|
|
4248
|
+
const serverResult = await serverToExecute({
|
|
4195
4249
|
...context2,
|
|
4196
4250
|
...initialState
|
|
4197
4251
|
});
|
|
@@ -4566,7 +4620,6 @@ function createPageHandlers({
|
|
|
4566
4620
|
scriptManager,
|
|
4567
4621
|
createSession
|
|
4568
4622
|
}) {
|
|
4569
|
-
const { pageCustomElements, childCustomElements } = app._dependencyGraph;
|
|
4570
4623
|
const onFileSetLocal = async (data) => {
|
|
4571
4624
|
const rootPath = data.type === "component" ? app.options.path.components : app.options.path.pages;
|
|
4572
4625
|
const urlPathname = pathToFileURL3(join3("/", relative2(rootPath, data.path.pathname))).pathname;
|
|
@@ -4597,34 +4650,11 @@ function createPageHandlers({
|
|
|
4597
4650
|
};
|
|
4598
4651
|
}
|
|
4599
4652
|
const elements = parseHTML(data.content, app.options.ignoreByAttribute, app.options.skipRenderByAttribute, handleError2);
|
|
4600
|
-
|
|
4601
|
-
|
|
4602
|
-
|
|
4603
|
-
|
|
4604
|
-
|
|
4605
|
-
pageCustomElements[name] = /* @__PURE__ */ new Set();
|
|
4606
|
-
app._dependencyGraph.pageCustomElements[name] = pageCustomElements[name];
|
|
4607
|
-
const component = app.components.getItem(name);
|
|
4608
|
-
if (component && component.result && component.result.customElements && component.result.customElements.length) {
|
|
4609
|
-
const stack = [component.result.customElements];
|
|
4610
|
-
while (stack.length > 0) {
|
|
4611
|
-
const current = stack.pop();
|
|
4612
|
-
for (let i2 = 0; i2 < current.length; i2++) {
|
|
4613
|
-
const element = current[i2];
|
|
4614
|
-
if (!childCustomElements[element.name]) {
|
|
4615
|
-
childCustomElements[element.name] = name;
|
|
4616
|
-
const comp = app.components.getItem(element.name);
|
|
4617
|
-
if (comp && comp.result && comp.result.customElements && comp.result.customElements.length) {
|
|
4618
|
-
stack.push(comp.result.customElements);
|
|
4619
|
-
}
|
|
4620
|
-
}
|
|
4621
|
-
}
|
|
4622
|
-
}
|
|
4623
|
-
}
|
|
4624
|
-
}
|
|
4625
|
-
const customElements = pageCustomElements[name];
|
|
4626
|
-
customElements.add(data.path.pathname);
|
|
4627
|
-
}
|
|
4653
|
+
const directPageComponents = app._dependencyGraph.directPageComponents;
|
|
4654
|
+
if (elements && elements.customElements && directPageComponents) {
|
|
4655
|
+
const directComponents = elements.customElements.map((el) => el.name);
|
|
4656
|
+
directPageComponents[data.path.pathname] = directComponents;
|
|
4657
|
+
app._refreshDependencyGraph();
|
|
4628
4658
|
}
|
|
4629
4659
|
const mappedContext = await triggerHook("onPageSet", {
|
|
4630
4660
|
elements,
|
|
@@ -4633,8 +4663,8 @@ function createPageHandlers({
|
|
|
4633
4663
|
data,
|
|
4634
4664
|
app
|
|
4635
4665
|
});
|
|
4636
|
-
const
|
|
4637
|
-
if (
|
|
4666
|
+
const isStatic = app.options.mode === "production" || app.options.mode === "testing";
|
|
4667
|
+
if (isStatic && !data.virtual) {
|
|
4638
4668
|
delete data.content;
|
|
4639
4669
|
}
|
|
4640
4670
|
return {
|
|
@@ -4643,27 +4673,25 @@ function createPageHandlers({
|
|
|
4643
4673
|
state: mappedContext.state,
|
|
4644
4674
|
page: mappedContext.page,
|
|
4645
4675
|
path: mappedContext.data.path,
|
|
4646
|
-
root:
|
|
4647
|
-
customElements:
|
|
4648
|
-
tempElements:
|
|
4649
|
-
skipRenderElements:
|
|
4676
|
+
root: isStatic ? null : mappedContext.elements.root,
|
|
4677
|
+
customElements: isStatic ? null : mappedContext.elements.customElements,
|
|
4678
|
+
tempElements: isStatic ? null : mappedContext.elements.tempElements,
|
|
4679
|
+
skipRenderElements: isStatic ? null : mappedContext.elements.skipRenderElements
|
|
4650
4680
|
},
|
|
4651
4681
|
state: mappedContext.state
|
|
4652
4682
|
};
|
|
4653
4683
|
};
|
|
4654
4684
|
const onPageUpdateLocal = async (newValue, oldValue) => {
|
|
4655
|
-
if (app.options.mode === "production") {
|
|
4685
|
+
if (app.options.mode === "production" || app.options.mode === "testing") {
|
|
4686
|
+
if (!newValue.result) {
|
|
4687
|
+
await onFileSetLocal(newValue);
|
|
4688
|
+
}
|
|
4656
4689
|
return newValue.result;
|
|
4657
4690
|
}
|
|
4658
|
-
let newCustomElements;
|
|
4659
4691
|
if (!newValue.result) {
|
|
4660
4692
|
const res = await onFileSetLocal(newValue);
|
|
4661
4693
|
newValue.result = res.value;
|
|
4662
|
-
newCustomElements = res.value.customElements;
|
|
4663
|
-
} else {
|
|
4664
|
-
newCustomElements = newValue.result.customElements;
|
|
4665
4694
|
}
|
|
4666
|
-
const oldElements = (oldValue.result.customElements || []).slice();
|
|
4667
4695
|
const mappedContext = await triggerHook("onPageUpdate", {
|
|
4668
4696
|
elements: newValue.result,
|
|
4669
4697
|
page: newValue.result.page,
|
|
@@ -4673,51 +4701,31 @@ function createPageHandlers({
|
|
|
4673
4701
|
});
|
|
4674
4702
|
newValue.result = mappedContext.elements;
|
|
4675
4703
|
newValue = mappedContext.newValue;
|
|
4676
|
-
|
|
4677
|
-
|
|
4678
|
-
|
|
4679
|
-
|
|
4680
|
-
|
|
4681
|
-
|
|
4682
|
-
|
|
4683
|
-
|
|
4684
|
-
}
|
|
4685
|
-
}
|
|
4686
|
-
if (!hasElement) {
|
|
4687
|
-
if (!pageCustomElements[name]) {
|
|
4688
|
-
pageCustomElements[name] = /* @__PURE__ */ new Set();
|
|
4689
|
-
app._dependencyGraph.pageCustomElements[name] = pageCustomElements[name];
|
|
4690
|
-
}
|
|
4691
|
-
const customElements = pageCustomElements[name];
|
|
4692
|
-
customElements.add(newValue.path.pathname);
|
|
4704
|
+
const elements = parseHTML(newValue.content, app.options.ignoreByAttribute, app.options.skipRenderByAttribute, handleError2);
|
|
4705
|
+
const directPageComponents = app._dependencyGraph.directPageComponents;
|
|
4706
|
+
if (directPageComponents) {
|
|
4707
|
+
if (elements && elements.customElements) {
|
|
4708
|
+
const directComponents = elements.customElements.map((el) => el.name);
|
|
4709
|
+
directPageComponents[newValue.path.pathname] = directComponents;
|
|
4710
|
+
} else {
|
|
4711
|
+
delete directPageComponents[newValue.path.pathname];
|
|
4693
4712
|
}
|
|
4694
4713
|
}
|
|
4695
|
-
|
|
4696
|
-
if (pageCustomElements[oe.name]) {
|
|
4697
|
-
const customElements = pageCustomElements[oe.name];
|
|
4698
|
-
customElements.delete(newValue.path.pathname);
|
|
4699
|
-
}
|
|
4700
|
-
});
|
|
4714
|
+
app._refreshDependencyGraph();
|
|
4701
4715
|
return newValue.result;
|
|
4702
4716
|
};
|
|
4703
4717
|
const onPageDeleteLocal = async (value) => {
|
|
4704
|
-
if (app.options.mode === "production") {
|
|
4705
|
-
return;
|
|
4706
|
-
}
|
|
4707
4718
|
const res = await triggerHook("onPageDelete", {
|
|
4708
4719
|
data: value,
|
|
4709
4720
|
app
|
|
4710
4721
|
});
|
|
4711
|
-
|
|
4712
|
-
|
|
4713
|
-
|
|
4714
|
-
|
|
4715
|
-
|
|
4716
|
-
const customElements = pageCustomElements[ceName];
|
|
4717
|
-
customElements.delete(value.path.pathname);
|
|
4718
|
-
}
|
|
4719
|
-
});
|
|
4722
|
+
const finalData = res?.data || value;
|
|
4723
|
+
const pathname = finalData?.path?.pathname;
|
|
4724
|
+
const directPageComponents = app._dependencyGraph.directPageComponents;
|
|
4725
|
+
if (pathname && directPageComponents) {
|
|
4726
|
+
delete directPageComponents[pathname];
|
|
4720
4727
|
}
|
|
4728
|
+
app._refreshDependencyGraph();
|
|
4721
4729
|
};
|
|
4722
4730
|
const onComponentSetLocal = async (v) => {
|
|
4723
4731
|
if (v.content === void 0) {
|
|
@@ -4915,7 +4923,7 @@ ${css}
|
|
|
4915
4923
|
root.children.unshift(styleElement);
|
|
4916
4924
|
}
|
|
4917
4925
|
}
|
|
4918
|
-
function injectReadinessScript(root, head, hasScripts) {
|
|
4926
|
+
function injectReadinessScript(root, head, hasScripts, mode) {
|
|
4919
4927
|
const readinessScriptElement = createCoraliteElement({
|
|
4920
4928
|
type: "tag",
|
|
4921
4929
|
name: "script",
|
|
@@ -4924,6 +4932,9 @@ function injectReadinessScript(root, head, hasScripts) {
|
|
|
4924
4932
|
children: []
|
|
4925
4933
|
});
|
|
4926
4934
|
let data = "class CoraliteLifecycleManager { constructor() { this.defined = new Promise(r => this._dr = r); this.rendered = new Promise(r => this._rr = r); this.hydrated = new Promise(r => this._hr = r); this._t = 0; this._rc = 0; this._hc = 0; this._ts = 0; this._dt = new Set(); this._ip = new WeakMap(); this._ir = new WeakMap(); this._rs = new WeakSet(); this._hs = new WeakSet(); this._s = false; } _start(t, ts) { this._t = t; this._ts = ts; this._s = true; this._check(); } _check() { if (!this._s) return; if (this._rc >= this._t) this._rr(); if (this._hc >= this._t) this._hr(); if (this._dt.size >= this._ts) this._dr(); } _markDefined(tag) { this._dt.add(tag); this._check(); } _markInstanceRendered(el) { if (el.hasAttribute('data-coralite-initial') && !this._rs.has(el)) { this._rs.add(el); this._rc++; this._check(); } } _markInstanceReady(el) { const r = this._ir.get(el); r && r(); this._ip.set(el, Promise.resolve()); if (el.hasAttribute('data-coralite-initial') && !this._hs.has(el)) { this._hs.add(el); this._hc++; this._check(); } } waitFor(el) { let p = this._ip.get(el); if (!p) { p = new Promise(r => this._ir.set(el, r)); this._ip.set(el, p); } return p; } } window.__coralite__ = { lifecycle: new CoraliteLifecycleManager() };";
|
|
4935
|
+
if (mode === "testing") {
|
|
4936
|
+
data += " window.__coralite__.components = {}; window.__coralite__.events = [];";
|
|
4937
|
+
}
|
|
4927
4938
|
if (!hasScripts) {
|
|
4928
4939
|
data += " window.__coralite__.lifecycle._start(0, 0);";
|
|
4929
4940
|
}
|
|
@@ -5030,8 +5041,32 @@ import { getClientContext, createCoraliteClass, globalClientHooks } from '${base
|
|
|
5030
5041
|
(async () => {
|
|
5031
5042
|
const hydrationData = ${hydrationData};
|
|
5032
5043
|
const declarativeTags = ${JSON.stringify(declarativeTags)};
|
|
5033
|
-
|
|
5034
|
-
|
|
5044
|
+
|
|
5045
|
+
const initialElements = Array.from(document.querySelectorAll('[data-cid]'))
|
|
5046
|
+
.filter(el => {
|
|
5047
|
+
const tagName = el.tagName.toLowerCase();
|
|
5048
|
+
const isDeclarative = declarativeTags.includes(tagName);
|
|
5049
|
+
const isInitial = el.hasAttribute('data-coralite-initial');
|
|
5050
|
+
|
|
5051
|
+
if (window['__coralite__'] && window['__coralite__'].components && isInitial) {
|
|
5052
|
+
const cid = el.getAttribute('data-cid');
|
|
5053
|
+
if (cid && !hydrationData[cid]) {
|
|
5054
|
+
const error = new Error('Coralite Hydration Mismatch: Component with data-cid "' + cid + '" (' + tagName + ') has no matching server hydration data.');
|
|
5055
|
+
if (typeof window['showCoraliteError'] === 'function') {
|
|
5056
|
+
window['showCoraliteError'](error);
|
|
5057
|
+
} else {
|
|
5058
|
+
console.error(error);
|
|
5059
|
+
const overlay = document.createElement('div');
|
|
5060
|
+
overlay.style = 'position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(255,0,0,0.9);color:white;padding:20px;z-index:10000;font-family:monospace;white-space:pre-wrap;overflow:auto;';
|
|
5061
|
+
overlay.innerHTML = '<h1>Coralite Hydration Mismatch</h1><p>' + error.message + '</p>';
|
|
5062
|
+
document.body.appendChild(overlay);
|
|
5063
|
+
}
|
|
5064
|
+
throw error;
|
|
5065
|
+
}
|
|
5066
|
+
}
|
|
5067
|
+
|
|
5068
|
+
return isDeclarative && isInitial;
|
|
5069
|
+
});
|
|
5035
5070
|
if (window.__coralite__ && window.__coralite__.lifecycle) {
|
|
5036
5071
|
window.__coralite__.lifecycle._start(initialElements.length, declarativeTags.length);
|
|
5037
5072
|
}
|
|
@@ -5080,16 +5115,6 @@ import { getClientContext, createCoraliteClass, globalClientHooks } from '${base
|
|
|
5080
5115
|
customElements.define(id, createCoraliteClass(module.default, getClientContext, globalClientHooks, hydrationData));
|
|
5081
5116
|
if (window.__coralite__ && window.__coralite__.lifecycle) window.__coralite__.lifecycle._markDefined(id);
|
|
5082
5117
|
}
|
|
5083
|
-
|
|
5084
|
-
// Upgrade any existing elements that might have been created before the definition was loaded
|
|
5085
|
-
const elements = document.querySelectorAll(id);
|
|
5086
|
-
for (const el of elements) {
|
|
5087
|
-
if (el.constructor === HTMLElement) {
|
|
5088
|
-
// Re-trigger the lifecycle by replacing the element or manually calling upgrade if supported
|
|
5089
|
-
// For most cases, customElements.define handles this automatically if the element is already in DOM,
|
|
5090
|
-
// but if it's currently disconnected it might need help.
|
|
5091
|
-
}
|
|
5092
|
-
}
|
|
5093
5118
|
}
|
|
5094
5119
|
})();
|
|
5095
5120
|
return loadCache[componentId];
|
|
@@ -5480,20 +5505,11 @@ function createRenderer({
|
|
|
5480
5505
|
componentState = cleanKeys(componentState);
|
|
5481
5506
|
}
|
|
5482
5507
|
const module = cloneModuleInstance(moduleComponent.result);
|
|
5483
|
-
if (module.values && module.values.refs) {
|
|
5484
|
-
for (let i = 0; i < module.values.refs.length; i++) {
|
|
5485
|
-
const ref = module.values.refs[i];
|
|
5486
|
-
const uniqueRefValue = `${instanceId}__${ref.name}`;
|
|
5487
|
-
if (ref.element && ref.element.attribs) {
|
|
5488
|
-
ref.element.attribs.ref = uniqueRefValue;
|
|
5489
|
-
}
|
|
5490
|
-
componentState[`ref_${ref.name}`] = uniqueRefValue;
|
|
5491
|
-
}
|
|
5492
|
-
}
|
|
5493
5508
|
const mappedComponentContext = await hooks.trigger("onBeforeComponentRender", {
|
|
5494
5509
|
state: componentState,
|
|
5495
5510
|
componentId: module.id,
|
|
5496
5511
|
instanceId,
|
|
5512
|
+
template: module.template,
|
|
5497
5513
|
refs: module.values.refs,
|
|
5498
5514
|
textNodes: module.values.textNodes,
|
|
5499
5515
|
attributes: module.values.attributes,
|
|
@@ -5503,6 +5519,16 @@ function createRenderer({
|
|
|
5503
5519
|
app
|
|
5504
5520
|
});
|
|
5505
5521
|
componentState = mappedComponentContext.state;
|
|
5522
|
+
if (module.values && module.values.refs) {
|
|
5523
|
+
for (let i = 0; i < module.values.refs.length; i++) {
|
|
5524
|
+
const ref = module.values.refs[i];
|
|
5525
|
+
const uniqueRefValue = `${instanceId}__${ref.name}`;
|
|
5526
|
+
if (ref.element && ref.element.attribs) {
|
|
5527
|
+
ref.element.attribs.ref = uniqueRefValue;
|
|
5528
|
+
}
|
|
5529
|
+
componentState[`ref_${ref.name}`] = uniqueRefValue;
|
|
5530
|
+
}
|
|
5531
|
+
}
|
|
5506
5532
|
const result = module.template;
|
|
5507
5533
|
if (module.styles.length) {
|
|
5508
5534
|
const selector = module.id;
|
|
@@ -6080,7 +6106,7 @@ function createRenderer({
|
|
|
6080
6106
|
chunkManifest[tag] = scriptResult.manifest[tag];
|
|
6081
6107
|
}
|
|
6082
6108
|
}
|
|
6083
|
-
injectReadinessScript(mappedComponent.root, headElement, true);
|
|
6109
|
+
injectReadinessScript(mappedComponent.root, headElement, true, normalizedOptions.mode);
|
|
6084
6110
|
injectImportMap(mappedComponent.root, headElement, scriptResult.importMap);
|
|
6085
6111
|
const base = normalizedOptions.baseURL.endsWith("/") ? normalizedOptions.baseURL : normalizedOptions.baseURL + "/";
|
|
6086
6112
|
const hydrationData = {};
|
|
@@ -6113,7 +6139,7 @@ function createRenderer({
|
|
|
6113
6139
|
}
|
|
6114
6140
|
removeElements(mappedComponent.skipRenderElements, true);
|
|
6115
6141
|
if (!mappedSessionObject.scripts.content[mappedComponent.path.pathname]) {
|
|
6116
|
-
injectReadinessScript(mappedComponent.root, headElement, false);
|
|
6142
|
+
injectReadinessScript(mappedComponent.root, headElement, false, normalizedOptions.mode);
|
|
6117
6143
|
}
|
|
6118
6144
|
const rawHTML = transformNode(mappedComponent.root);
|
|
6119
6145
|
const result = {
|
|
@@ -6214,7 +6240,7 @@ function createRenderer({
|
|
|
6214
6240
|
if (!buildOptions) {
|
|
6215
6241
|
buildOptions = {};
|
|
6216
6242
|
}
|
|
6217
|
-
if (normalizedOptions.mode === "production") {
|
|
6243
|
+
if (normalizedOptions.mode === "production" || normalizedOptions.mode === "testing") {
|
|
6218
6244
|
const allComponentIds = app.components.list.map((c) => c.result.id);
|
|
6219
6245
|
globalScriptResult = await scriptManager.compileAllInstances(allComponentIds, normalizedOptions.mode);
|
|
6220
6246
|
Object.assign(outputFiles, globalScriptResult.outputFiles);
|
|
@@ -6286,6 +6312,17 @@ function createRenderer({
|
|
|
6286
6312
|
try {
|
|
6287
6313
|
const content = await readFile3(manifestPath, "utf8");
|
|
6288
6314
|
manifest = JSON.parse(content);
|
|
6315
|
+
for (const [path2, metadata] of Object.entries(manifest.physical || {})) {
|
|
6316
|
+
if (metadata.dependencies) {
|
|
6317
|
+
app._dependencyGraph.directPageComponents[path2] = metadata.dependencies;
|
|
6318
|
+
}
|
|
6319
|
+
}
|
|
6320
|
+
for (const [path2, metadata] of Object.entries(manifest.virtual || {})) {
|
|
6321
|
+
if (metadata.dependencies) {
|
|
6322
|
+
app._dependencyGraph.directPageComponents[path2] = metadata.dependencies;
|
|
6323
|
+
}
|
|
6324
|
+
}
|
|
6325
|
+
app._refreshDependencyGraph();
|
|
6289
6326
|
} catch (e) {
|
|
6290
6327
|
if (e.code !== "ENOENT") {
|
|
6291
6328
|
handleError2({
|
|
@@ -6294,30 +6331,39 @@ function createRenderer({
|
|
|
6294
6331
|
});
|
|
6295
6332
|
}
|
|
6296
6333
|
}
|
|
6334
|
+
const mocksStr = app.options.testing?.mocks ? serialize2(app.options.testing.mocks) : "";
|
|
6335
|
+
const mocksHash = hash(mocksStr);
|
|
6336
|
+
const mocksChanged = manifest.testingMocksHash !== mocksHash;
|
|
6297
6337
|
const pagesToRender = [];
|
|
6298
6338
|
const skippedPages = [];
|
|
6299
6339
|
const newManifest = {
|
|
6300
6340
|
physical: {},
|
|
6301
6341
|
virtual: {},
|
|
6302
|
-
dependencies: {}
|
|
6342
|
+
dependencies: {},
|
|
6343
|
+
testingMocksHash: mocksHash
|
|
6303
6344
|
};
|
|
6304
6345
|
const componentChanges = /* @__PURE__ */ new Map();
|
|
6305
6346
|
const allComponents = app.components.list;
|
|
6347
|
+
let anyComponentChanged = false;
|
|
6306
6348
|
for (const component of allComponents) {
|
|
6307
6349
|
const { changed, metadata } = await checkFileChange(component.path.pathname, manifest.physical[component.path.pathname]);
|
|
6308
6350
|
newManifest.physical[component.path.pathname] = metadata;
|
|
6309
|
-
if (changed) {
|
|
6351
|
+
if (changed || !manifest.physical[component.path.pathname]) {
|
|
6310
6352
|
componentChanges.set(component.result.id, true);
|
|
6353
|
+
anyComponentChanged = true;
|
|
6311
6354
|
await app.components.updateItem(component.path.pathname);
|
|
6312
6355
|
}
|
|
6313
6356
|
}
|
|
6357
|
+
if (anyComponentChanged) {
|
|
6358
|
+
app._refreshDependencyGraph();
|
|
6359
|
+
}
|
|
6314
6360
|
const pageCustomElements = {
|
|
6315
6361
|
...manifest.dependencies,
|
|
6316
6362
|
...app._dependencyGraph.pageCustomElements
|
|
6317
6363
|
};
|
|
6318
6364
|
for (const pageItem of queue) {
|
|
6319
6365
|
let shouldRebuild = false;
|
|
6320
|
-
if (normalizedOptions.output && normalizedOptions.mode === "production") {
|
|
6366
|
+
if (normalizedOptions.output && (normalizedOptions.mode === "production" || normalizedOptions.mode === "testing")) {
|
|
6321
6367
|
const relativeDir = relative3(normalizedOptions.path.pages, pageItem.path.dirname);
|
|
6322
6368
|
const outFile = join4(normalizedOptions.output, relativeDir, pageItem.path.filename);
|
|
6323
6369
|
try {
|
|
@@ -6336,6 +6382,9 @@ function createRenderer({
|
|
|
6336
6382
|
if (componentIds.some((id) => componentChanges.get(id))) {
|
|
6337
6383
|
shouldRebuild = true;
|
|
6338
6384
|
}
|
|
6385
|
+
if (mocksChanged) {
|
|
6386
|
+
shouldRebuild = true;
|
|
6387
|
+
}
|
|
6339
6388
|
if (pageItem.virtual) {
|
|
6340
6389
|
if (shouldRebuild || pageItem.volatile || !manifest.virtual || !manifest.virtual[pageItem.path.pathname] || String(manifest.virtual[pageItem.path.pathname].cacheKey) !== String(pageItem.cacheKey) || normalizedOptions.mode === "development") {
|
|
6341
6390
|
shouldRebuild = true;
|
|
@@ -6385,10 +6434,17 @@ function createRenderer({
|
|
|
6385
6434
|
}
|
|
6386
6435
|
}
|
|
6387
6436
|
}
|
|
6388
|
-
const { pageCustomElements: livePageCustomElements } = app._dependencyGraph;
|
|
6437
|
+
const { pageCustomElements: livePageCustomElements, directPageComponents: liveDirectPageComponents } = app._dependencyGraph;
|
|
6389
6438
|
for (const [id, pages] of Object.entries(livePageCustomElements)) {
|
|
6390
6439
|
newManifest.dependencies[id] = Array.from(pages);
|
|
6391
6440
|
}
|
|
6441
|
+
for (const [path2, deps] of Object.entries(liveDirectPageComponents)) {
|
|
6442
|
+
if (newManifest.physical[path2]) {
|
|
6443
|
+
newManifest.physical[path2].dependencies = deps;
|
|
6444
|
+
} else if (newManifest.virtual[path2]) {
|
|
6445
|
+
newManifest.virtual[path2].dependencies = deps;
|
|
6446
|
+
}
|
|
6447
|
+
}
|
|
6392
6448
|
for (const [id, pages] of Object.entries(manifest.dependencies || {})) {
|
|
6393
6449
|
if (!newManifest.dependencies[id]) {
|
|
6394
6450
|
newManifest.dependencies[id] = pages;
|
|
@@ -6490,7 +6546,6 @@ function createRenderer({
|
|
|
6490
6546
|
});
|
|
6491
6547
|
renderQueues.delete(buildId);
|
|
6492
6548
|
sealedQueues.delete(buildId);
|
|
6493
|
-
app._clearDependencies();
|
|
6494
6549
|
pagesToRender.length = 0;
|
|
6495
6550
|
skippedPages.length = 0;
|
|
6496
6551
|
}
|
|
@@ -6528,7 +6583,8 @@ async function createCoralite({
|
|
|
6528
6583
|
skipRenderByAttribute,
|
|
6529
6584
|
onError,
|
|
6530
6585
|
mode = "production",
|
|
6531
|
-
output
|
|
6586
|
+
output,
|
|
6587
|
+
testing
|
|
6532
6588
|
}) {
|
|
6533
6589
|
if (!components || typeof components !== "string") {
|
|
6534
6590
|
handleError({
|
|
@@ -6564,7 +6620,8 @@ async function createCoralite({
|
|
|
6564
6620
|
skipRenderByAttribute,
|
|
6565
6621
|
mode,
|
|
6566
6622
|
path: path2,
|
|
6567
|
-
output: output ? normalize(output) : void 0
|
|
6623
|
+
output: output ? normalize(output) : void 0,
|
|
6624
|
+
testing
|
|
6568
6625
|
};
|
|
6569
6626
|
const trackedOutputFiles = /* @__PURE__ */ new Set();
|
|
6570
6627
|
const app = {
|
|
@@ -6595,11 +6652,44 @@ async function createCoralite({
|
|
|
6595
6652
|
createComponentElement: null,
|
|
6596
6653
|
_dependencyGraph: {
|
|
6597
6654
|
pageCustomElements: {},
|
|
6598
|
-
|
|
6655
|
+
directPageComponents: {}
|
|
6656
|
+
},
|
|
6657
|
+
_refreshDependencyGraph: () => {
|
|
6658
|
+
const { pageCustomElements, directPageComponents } = app._dependencyGraph;
|
|
6659
|
+
for (const tag in pageCustomElements) {
|
|
6660
|
+
delete pageCustomElements[tag];
|
|
6661
|
+
}
|
|
6662
|
+
const resolveDependencies = (pagePath, directComponents) => {
|
|
6663
|
+
const visited = /* @__PURE__ */ new Set();
|
|
6664
|
+
const allDependencies = /* @__PURE__ */ new Set();
|
|
6665
|
+
const walk = (tags) => {
|
|
6666
|
+
for (const tag of tags) {
|
|
6667
|
+
if (visited.has(tag)) {
|
|
6668
|
+
continue;
|
|
6669
|
+
}
|
|
6670
|
+
visited.add(tag);
|
|
6671
|
+
allDependencies.add(tag);
|
|
6672
|
+
const sharedFn = scriptManager.sharedFunctions[tag];
|
|
6673
|
+
if (sharedFn && sharedFn.components?.length) {
|
|
6674
|
+
walk(sharedFn.components);
|
|
6675
|
+
}
|
|
6676
|
+
}
|
|
6677
|
+
};
|
|
6678
|
+
walk(directComponents);
|
|
6679
|
+
for (const tag of allDependencies) {
|
|
6680
|
+
if (!pageCustomElements[tag]) {
|
|
6681
|
+
pageCustomElements[tag] = /* @__PURE__ */ new Set();
|
|
6682
|
+
}
|
|
6683
|
+
pageCustomElements[tag].add(pagePath);
|
|
6684
|
+
}
|
|
6685
|
+
};
|
|
6686
|
+
for (const [pagePath, directComponents] of Object.entries(directPageComponents)) {
|
|
6687
|
+
resolveDependencies(pagePath, directComponents);
|
|
6688
|
+
}
|
|
6599
6689
|
},
|
|
6600
6690
|
_clearDependencies: () => {
|
|
6601
6691
|
app._dependencyGraph.pageCustomElements = {};
|
|
6602
|
-
app._dependencyGraph.
|
|
6692
|
+
app._dependencyGraph.directPageComponents = {};
|
|
6603
6693
|
}
|
|
6604
6694
|
};
|
|
6605
6695
|
const plugins = {
|
|
@@ -6768,16 +6858,21 @@ async function createCoralite({
|
|
|
6768
6858
|
const item = app.components.getItem(targetPath);
|
|
6769
6859
|
const results = [];
|
|
6770
6860
|
if (item) {
|
|
6771
|
-
const id =
|
|
6861
|
+
const id = item.result.id;
|
|
6772
6862
|
const pce = app._dependencyGraph.pageCustomElements[id];
|
|
6773
6863
|
if (pce) {
|
|
6774
6864
|
pce.forEach((p) => results.push(p));
|
|
6775
6865
|
}
|
|
6866
|
+
} else {
|
|
6867
|
+
const pce = app._dependencyGraph.pageCustomElements[targetPath];
|
|
6868
|
+
if (pce) {
|
|
6869
|
+
pce.forEach((p) => results.push(p));
|
|
6870
|
+
}
|
|
6776
6871
|
}
|
|
6777
6872
|
return results;
|
|
6778
6873
|
}
|
|
6779
6874
|
});
|
|
6780
|
-
if (app.options.mode === "
|
|
6875
|
+
if (app.options.mode === "testing") {
|
|
6781
6876
|
app.options.plugins.unshift(testingPlugin);
|
|
6782
6877
|
}
|
|
6783
6878
|
app.options.plugins.unshift(metadataPlugin);
|
|
@@ -6835,7 +6930,7 @@ async function createCoralite({
|
|
|
6835
6930
|
onUpdate: handlers.onPageUpdate,
|
|
6836
6931
|
onDelete: handlers.onPageDelete
|
|
6837
6932
|
});
|
|
6838
|
-
if (app.options.mode === "production") {
|
|
6933
|
+
if (app.options.mode === "production" || app.options.mode === "testing") {
|
|
6839
6934
|
for await (const file of discoverHtmlFiles({
|
|
6840
6935
|
path: app.options.pages,
|
|
6841
6936
|
recursive: true,
|
|
@@ -6876,6 +6971,30 @@ function defineConfig(options) {
|
|
|
6876
6971
|
throw new CoraliteError(`Config property "${prop}" cannot be empty`);
|
|
6877
6972
|
}
|
|
6878
6973
|
}
|
|
6974
|
+
if (options.mode !== void 0) {
|
|
6975
|
+
const validModes = ["production", "development", "testing"];
|
|
6976
|
+
if (!validModes.includes(options.mode)) {
|
|
6977
|
+
throw new CoraliteError(`Invalid mode: "${options.mode}". Valid modes are: ${validModes.join(", ")}`);
|
|
6978
|
+
}
|
|
6979
|
+
}
|
|
6980
|
+
if (options.testing !== void 0) {
|
|
6981
|
+
if (typeof options.testing !== "object" || options.testing === null) {
|
|
6982
|
+
throw new CoraliteError('Config property "testing" must be an object');
|
|
6983
|
+
}
|
|
6984
|
+
if (options.testing.mocks !== void 0) {
|
|
6985
|
+
if (typeof options.testing.mocks !== "object" || options.testing.mocks === null) {
|
|
6986
|
+
throw new CoraliteError('Config property "testing.mocks" must be an object');
|
|
6987
|
+
}
|
|
6988
|
+
for (const [key, mock] of Object.entries(options.testing.mocks)) {
|
|
6989
|
+
if (typeof mock !== "object" || mock === null) {
|
|
6990
|
+
throw new CoraliteError(`Mock for component "${key}" must be an object`);
|
|
6991
|
+
}
|
|
6992
|
+
if (mock.server !== void 0 && typeof mock.server !== "function") {
|
|
6993
|
+
throw new CoraliteError(`Mock server for component "${key}" must be a function`);
|
|
6994
|
+
}
|
|
6995
|
+
}
|
|
6996
|
+
}
|
|
6997
|
+
}
|
|
6879
6998
|
if ("plugins" in options && options.plugins !== void 0) {
|
|
6880
6999
|
if (!Array.isArray(options.plugins)) {
|
|
6881
7000
|
throw new CoraliteError(
|