coralite 0.40.2 → 0.42.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/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 +38 -4
- 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 +357 -139
- package/dist/lib/index.js.map +2 -2
- package/dist/lib/renderer.d.ts.map +1 -1
- package/dist/lib/utils/client/inject.d.ts +2 -1
- package/dist/lib/utils/client/inject.d.ts.map +1 -1
- package/dist/lib/utils/client/inject.js +2 -2
- package/dist/lib/utils/client/inject.js.map +2 -2
- package/dist/lib/utils/client/runtime.d.ts +4 -4
- package/dist/lib/utils/client/runtime.d.ts.map +1 -1
- package/dist/lib/utils/server/render.d.ts +3 -2
- package/dist/lib/utils/server/render.d.ts.map +1 -1
- package/dist/lib/utils/server/server.d.ts.map +1 -1
- package/dist/plugins/testing.d.ts.map +1 -1
- package/dist/types/core.d.ts +57 -3
- 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/package.json +5 -3
- package/llms.txt +0 -419
package/dist/lib/index.js
CHANGED
|
@@ -2248,6 +2248,22 @@ function findAndExtractScript(code) {
|
|
|
2248
2248
|
let startLine = value.loc.start.line - 1;
|
|
2249
2249
|
let prefix = "";
|
|
2250
2250
|
let content = "";
|
|
2251
|
+
let instanceIdVar;
|
|
2252
|
+
if (value.params && value.params[0]) {
|
|
2253
|
+
const param = value.params[0];
|
|
2254
|
+
if (param.type === "Identifier") {
|
|
2255
|
+
instanceIdVar = param.name + ".instanceId";
|
|
2256
|
+
} else if (param.type === "ObjectPattern") {
|
|
2257
|
+
const idProp = param.properties.find((p) => p.key?.type === "Identifier" && p.key?.name === "instanceId");
|
|
2258
|
+
if (idProp) {
|
|
2259
|
+
if (idProp.value.type === "Identifier") {
|
|
2260
|
+
instanceIdVar = idProp.value.name;
|
|
2261
|
+
}
|
|
2262
|
+
}
|
|
2263
|
+
}
|
|
2264
|
+
} else if (method) {
|
|
2265
|
+
instanceIdVar = "this._instanceId";
|
|
2266
|
+
}
|
|
2251
2267
|
let source = code.slice(value.start, value.end);
|
|
2252
2268
|
const replacements = [];
|
|
2253
2269
|
walkJS(value, {
|
|
@@ -2262,7 +2278,7 @@ function findAndExtractScript(code) {
|
|
|
2262
2278
|
replacements.push({
|
|
2263
2279
|
start: node2.right.end - value.start,
|
|
2264
2280
|
end: node2.right.end - value.start,
|
|
2265
|
-
replacement:
|
|
2281
|
+
replacement: `, ${instanceIdVar})`
|
|
2266
2282
|
});
|
|
2267
2283
|
}
|
|
2268
2284
|
},
|
|
@@ -2292,7 +2308,7 @@ function findAndExtractScript(code) {
|
|
|
2292
2308
|
replacements.push({
|
|
2293
2309
|
start: arg.end - value.start,
|
|
2294
2310
|
end: arg.end - value.start,
|
|
2295
|
-
replacement:
|
|
2311
|
+
replacement: `, ${instanceIdVar})`
|
|
2296
2312
|
});
|
|
2297
2313
|
}
|
|
2298
2314
|
}
|
|
@@ -3460,62 +3476,131 @@ var staticAssetPlugin = (assets = []) => {
|
|
|
3460
3476
|
};
|
|
3461
3477
|
|
|
3462
3478
|
// plugins/testing.js
|
|
3463
|
-
function traverseAndAddTestId(children) {
|
|
3479
|
+
function traverseAndAddTestId(children, instanceId, { autoTestId = false, counters = {}, mode = "production" } = {}) {
|
|
3464
3480
|
if (!Array.isArray(children)) {
|
|
3465
3481
|
return;
|
|
3466
3482
|
}
|
|
3483
|
+
const isProduction = mode === "production";
|
|
3484
|
+
const isDevOrTest = mode === "development" || mode === "testing";
|
|
3485
|
+
let prefix = "";
|
|
3486
|
+
if (instanceId === "page") {
|
|
3487
|
+
prefix = "page__";
|
|
3488
|
+
} else if (instanceId) {
|
|
3489
|
+
prefix = `${instanceId}__`;
|
|
3490
|
+
}
|
|
3467
3491
|
for (let i = 0; i < children.length; i++) {
|
|
3468
3492
|
const node = children[i];
|
|
3469
|
-
if (node.type === "tag"
|
|
3470
|
-
if (
|
|
3471
|
-
node.attribs
|
|
3493
|
+
if (node.type === "tag") {
|
|
3494
|
+
if (node.attribs) {
|
|
3495
|
+
if (node.attribs.test !== void 0) {
|
|
3496
|
+
delete node.attribs.test;
|
|
3497
|
+
}
|
|
3498
|
+
if (node.attribs["data-testid"] !== void 0) {
|
|
3499
|
+
if (isProduction) {
|
|
3500
|
+
delete node.attribs["data-testid"];
|
|
3501
|
+
} else if (isDevOrTest) {
|
|
3502
|
+
const val = node.attribs["data-testid"];
|
|
3503
|
+
if (prefix && !val.startsWith(prefix)) {
|
|
3504
|
+
node.attribs["data-testid"] = `${prefix}${val}`;
|
|
3505
|
+
}
|
|
3506
|
+
}
|
|
3507
|
+
}
|
|
3508
|
+
}
|
|
3509
|
+
if (autoTestId && isDevOrTest) {
|
|
3510
|
+
const tagName = node.name.toLowerCase();
|
|
3511
|
+
const isInteractive = [
|
|
3512
|
+
"button",
|
|
3513
|
+
"a",
|
|
3514
|
+
"input",
|
|
3515
|
+
"form",
|
|
3516
|
+
"select",
|
|
3517
|
+
"textarea"
|
|
3518
|
+
].includes(tagName) || node.attribs && (node.attribs.tabindex !== void 0 || node.attribs.role && ["button", "link", "checkbox"].includes(node.attribs.role)) || node.slots;
|
|
3519
|
+
if (isInteractive) {
|
|
3520
|
+
if (!counters[tagName]) {
|
|
3521
|
+
counters[tagName] = 0;
|
|
3522
|
+
}
|
|
3523
|
+
const index = counters[tagName]++;
|
|
3524
|
+
if (!node.attribs) {
|
|
3525
|
+
node.attribs = {};
|
|
3526
|
+
}
|
|
3527
|
+
if (!node.attribs["data-testid"]) {
|
|
3528
|
+
node.attribs["data-testid"] = `${prefix}${tagName}-${index}`;
|
|
3529
|
+
}
|
|
3530
|
+
}
|
|
3472
3531
|
}
|
|
3473
3532
|
}
|
|
3474
3533
|
if (node.children?.length > 0) {
|
|
3475
|
-
traverseAndAddTestId(node.children
|
|
3534
|
+
traverseAndAddTestId(node.children, instanceId, {
|
|
3535
|
+
autoTestId,
|
|
3536
|
+
counters,
|
|
3537
|
+
mode
|
|
3538
|
+
});
|
|
3476
3539
|
}
|
|
3477
3540
|
}
|
|
3478
3541
|
}
|
|
3479
3542
|
var testingPlugin = definePlugin({
|
|
3480
3543
|
name: "testing",
|
|
3481
3544
|
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
|
-
}
|
|
3545
|
+
onBeforeBuild: ({ app }) => {
|
|
3546
|
+
if (app.options.mode !== "testing") {
|
|
3547
|
+
return;
|
|
3492
3548
|
}
|
|
3549
|
+
app.options.externalStyles = app.options.externalStyles || [];
|
|
3550
|
+
const velocityStyle = `
|
|
3551
|
+
*, *::before, *::after {
|
|
3552
|
+
transition: none !important;
|
|
3553
|
+
animation: none !important;
|
|
3554
|
+
scroll-behavior: auto !important;
|
|
3555
|
+
}
|
|
3556
|
+
`.trim();
|
|
3557
|
+
app.options.externalStyles.push(`data:text/css;base64,${Buffer.from(velocityStyle).toString("base64")}`);
|
|
3493
3558
|
},
|
|
3494
|
-
|
|
3495
|
-
const
|
|
3496
|
-
|
|
3497
|
-
|
|
3559
|
+
onBeforeComponentRender: ({ instanceId, template, app }) => {
|
|
3560
|
+
const mode = app.options.mode;
|
|
3561
|
+
const isDevOrTest = mode === "development" || mode === "testing";
|
|
3562
|
+
const counters = {};
|
|
3563
|
+
const templateNode = template;
|
|
3564
|
+
if (templateNode && templateNode.children) {
|
|
3565
|
+
traverseAndAddTestId(templateNode.children, instanceId, {
|
|
3566
|
+
autoTestId: isDevOrTest,
|
|
3567
|
+
counters,
|
|
3568
|
+
mode
|
|
3569
|
+
});
|
|
3498
3570
|
}
|
|
3499
3571
|
},
|
|
3500
|
-
|
|
3501
|
-
const
|
|
3502
|
-
if (
|
|
3503
|
-
|
|
3572
|
+
onAfterComponentRender: ({ result, app }) => {
|
|
3573
|
+
const mode = app.options.mode;
|
|
3574
|
+
if (mode !== "production") {
|
|
3575
|
+
return;
|
|
3504
3576
|
}
|
|
3505
|
-
|
|
3506
|
-
|
|
3507
|
-
|
|
3508
|
-
|
|
3509
|
-
|
|
3510
|
-
|
|
3511
|
-
|
|
3512
|
-
|
|
3513
|
-
|
|
3514
|
-
if (
|
|
3515
|
-
|
|
3577
|
+
const traverse = (children) => {
|
|
3578
|
+
if (!Array.isArray(children)) {
|
|
3579
|
+
return;
|
|
3580
|
+
}
|
|
3581
|
+
for (const node of children) {
|
|
3582
|
+
if (node.type === "tag" && node.attribs) {
|
|
3583
|
+
delete node.attribs["data-testid"];
|
|
3584
|
+
delete node.attribs.test;
|
|
3585
|
+
}
|
|
3586
|
+
if (node.children) {
|
|
3587
|
+
traverse(node.children);
|
|
3516
3588
|
}
|
|
3517
3589
|
}
|
|
3590
|
+
};
|
|
3591
|
+
if (result && result.children) {
|
|
3592
|
+
traverse(result.children);
|
|
3518
3593
|
}
|
|
3594
|
+
},
|
|
3595
|
+
onPageSet: ({ elements, app }) => {
|
|
3596
|
+
const mode = app.options.mode;
|
|
3597
|
+
const isDevOrTest = mode === "development" || mode === "testing";
|
|
3598
|
+
const counters = {};
|
|
3599
|
+
traverseAndAddTestId(elements?.root?.children, "page", {
|
|
3600
|
+
autoTestId: isDevOrTest,
|
|
3601
|
+
counters,
|
|
3602
|
+
mode
|
|
3603
|
+
});
|
|
3519
3604
|
}
|
|
3520
3605
|
}
|
|
3521
3606
|
});
|
|
@@ -4190,8 +4275,15 @@ function createComponentDefinition({ app }) {
|
|
|
4190
4275
|
}
|
|
4191
4276
|
}
|
|
4192
4277
|
}
|
|
4193
|
-
|
|
4194
|
-
|
|
4278
|
+
let serverToExecute = server;
|
|
4279
|
+
if (app.options.mode === "testing" && app.options.testing?.mocks) {
|
|
4280
|
+
const mock = app.options.testing.mocks[module.id];
|
|
4281
|
+
if (mock && typeof mock.server === "function") {
|
|
4282
|
+
serverToExecute = mock.server;
|
|
4283
|
+
}
|
|
4284
|
+
}
|
|
4285
|
+
if (typeof serverToExecute === "function") {
|
|
4286
|
+
const serverResult = await serverToExecute({
|
|
4195
4287
|
...context2,
|
|
4196
4288
|
...initialState
|
|
4197
4289
|
});
|
|
@@ -4609,8 +4701,8 @@ function createPageHandlers({
|
|
|
4609
4701
|
data,
|
|
4610
4702
|
app
|
|
4611
4703
|
});
|
|
4612
|
-
const
|
|
4613
|
-
if (
|
|
4704
|
+
const isStatic = app.options.mode === "production" || app.options.mode === "testing";
|
|
4705
|
+
if (isStatic && !data.virtual) {
|
|
4614
4706
|
delete data.content;
|
|
4615
4707
|
}
|
|
4616
4708
|
return {
|
|
@@ -4619,16 +4711,16 @@ function createPageHandlers({
|
|
|
4619
4711
|
state: mappedContext.state,
|
|
4620
4712
|
page: mappedContext.page,
|
|
4621
4713
|
path: mappedContext.data.path,
|
|
4622
|
-
root:
|
|
4623
|
-
customElements:
|
|
4624
|
-
tempElements:
|
|
4625
|
-
skipRenderElements:
|
|
4714
|
+
root: isStatic ? null : mappedContext.elements.root,
|
|
4715
|
+
customElements: isStatic ? null : mappedContext.elements.customElements,
|
|
4716
|
+
tempElements: isStatic ? null : mappedContext.elements.tempElements,
|
|
4717
|
+
skipRenderElements: isStatic ? null : mappedContext.elements.skipRenderElements
|
|
4626
4718
|
},
|
|
4627
4719
|
state: mappedContext.state
|
|
4628
4720
|
};
|
|
4629
4721
|
};
|
|
4630
4722
|
const onPageUpdateLocal = async (newValue, oldValue) => {
|
|
4631
|
-
if (app.options.mode === "production") {
|
|
4723
|
+
if (app.options.mode === "production" || app.options.mode === "testing") {
|
|
4632
4724
|
if (!newValue.result) {
|
|
4633
4725
|
await onFileSetLocal(newValue);
|
|
4634
4726
|
}
|
|
@@ -4869,7 +4961,7 @@ ${css}
|
|
|
4869
4961
|
root.children.unshift(styleElement);
|
|
4870
4962
|
}
|
|
4871
4963
|
}
|
|
4872
|
-
function injectReadinessScript(root, head, hasScripts) {
|
|
4964
|
+
function injectReadinessScript(root, head, hasScripts, mode) {
|
|
4873
4965
|
const readinessScriptElement = createCoraliteElement({
|
|
4874
4966
|
type: "tag",
|
|
4875
4967
|
name: "script",
|
|
@@ -4878,6 +4970,12 @@ function injectReadinessScript(root, head, hasScripts) {
|
|
|
4878
4970
|
children: []
|
|
4879
4971
|
});
|
|
4880
4972
|
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() };";
|
|
4973
|
+
if (mode) {
|
|
4974
|
+
data += ` window.__coralite__.mode = '${mode}';`;
|
|
4975
|
+
}
|
|
4976
|
+
if (mode === "testing") {
|
|
4977
|
+
data += " window.__coralite__.components = {}; window.__coralite__.events = [];";
|
|
4978
|
+
}
|
|
4881
4979
|
if (!hasScripts) {
|
|
4882
4980
|
data += " window.__coralite__.lifecycle._start(0, 0);";
|
|
4883
4981
|
}
|
|
@@ -4892,8 +4990,12 @@ function injectReadinessScript(root, head, hasScripts) {
|
|
|
4892
4990
|
root.children.unshift(readinessScriptElement);
|
|
4893
4991
|
}
|
|
4894
4992
|
}
|
|
4895
|
-
function injectImportMap(root, head, importMap) {
|
|
4896
|
-
|
|
4993
|
+
function injectImportMap(root, head, importMap, base) {
|
|
4994
|
+
const finalImportMap = { ...importMap };
|
|
4995
|
+
if (base) {
|
|
4996
|
+
finalImportMap["assets/js/manifest.js"] = `${base}assets/js/manifest.js`;
|
|
4997
|
+
}
|
|
4998
|
+
if (Object.keys(finalImportMap).length === 0) {
|
|
4897
4999
|
return;
|
|
4898
5000
|
}
|
|
4899
5001
|
const importMapElement = createCoraliteElement({
|
|
@@ -4907,7 +5009,7 @@ function injectImportMap(root, head, importMap) {
|
|
|
4907
5009
|
});
|
|
4908
5010
|
importMapElement.children.push(createCoraliteTextNode({
|
|
4909
5011
|
type: "text",
|
|
4910
|
-
data: JSON.stringify({ imports:
|
|
5012
|
+
data: JSON.stringify({ imports: finalImportMap }),
|
|
4911
5013
|
parent: importMapElement
|
|
4912
5014
|
}));
|
|
4913
5015
|
if (head) {
|
|
@@ -4974,25 +5076,50 @@ function resolvePageQueue(pagesCollection, path2) {
|
|
|
4974
5076
|
function generateClientRuntime({
|
|
4975
5077
|
base,
|
|
4976
5078
|
sharedChunkPath,
|
|
4977
|
-
chunkManifest,
|
|
4978
5079
|
declarativeTags = [],
|
|
4979
|
-
hydrationData = "{}"
|
|
5080
|
+
hydrationData = "{}",
|
|
5081
|
+
mode = "production"
|
|
4980
5082
|
}) {
|
|
4981
5083
|
return `
|
|
4982
5084
|
import { getClientContext, createCoraliteClass, globalClientHooks } from '${base}assets/js/${sharedChunkPath}';
|
|
5085
|
+
import componentManifest from '${base}assets/js/manifest.js';
|
|
4983
5086
|
|
|
4984
5087
|
(async () => {
|
|
4985
5088
|
const hydrationData = ${hydrationData};
|
|
4986
5089
|
const declarativeTags = ${JSON.stringify(declarativeTags)};
|
|
4987
|
-
|
|
4988
|
-
|
|
5090
|
+
window.__coralite_mode__ = '${mode}';
|
|
5091
|
+
|
|
5092
|
+
const initialElements = Array.from(document.querySelectorAll('[data-cid]'))
|
|
5093
|
+
.filter(el => {
|
|
5094
|
+
const tagName = el.tagName.toLowerCase();
|
|
5095
|
+
const isDeclarative = declarativeTags.includes(tagName);
|
|
5096
|
+
const isInitial = el.hasAttribute('data-coralite-initial');
|
|
5097
|
+
|
|
5098
|
+
if (window['__coralite__'] && window['__coralite__'].components && isInitial) {
|
|
5099
|
+
const cid = el.getAttribute('data-cid');
|
|
5100
|
+
if (cid && !hydrationData[cid]) {
|
|
5101
|
+
const error = new Error('Coralite Hydration Mismatch: Component with data-cid "' + cid + '" (' + tagName + ') has no matching server hydration data.');
|
|
5102
|
+
if (typeof window['showCoraliteError'] === 'function') {
|
|
5103
|
+
window['showCoraliteError'](error);
|
|
5104
|
+
} else {
|
|
5105
|
+
console.error(error);
|
|
5106
|
+
const overlay = document.createElement('div');
|
|
5107
|
+
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;';
|
|
5108
|
+
overlay.innerHTML = '<h1>Coralite Hydration Mismatch</h1><p>' + error.message + '</p>';
|
|
5109
|
+
document.body.appendChild(overlay);
|
|
5110
|
+
}
|
|
5111
|
+
throw error;
|
|
5112
|
+
}
|
|
5113
|
+
}
|
|
5114
|
+
|
|
5115
|
+
return isDeclarative && isInitial;
|
|
5116
|
+
});
|
|
4989
5117
|
if (window.__coralite__ && window.__coralite__.lifecycle) {
|
|
4990
5118
|
window.__coralite__.lifecycle._start(initialElements.length, declarativeTags.length);
|
|
4991
5119
|
}
|
|
4992
5120
|
globalThis.executableScripts = [];
|
|
4993
5121
|
globalThis.globalAbortController = new AbortController();
|
|
4994
5122
|
|
|
4995
|
-
const componentManifest = ${JSON.stringify(chunkManifest)};
|
|
4996
5123
|
const loadCache = {};
|
|
4997
5124
|
|
|
4998
5125
|
const loadComponent = (componentId) => {
|
|
@@ -5007,7 +5134,10 @@ import { getClientContext, createCoraliteClass, globalClientHooks } from '${base
|
|
|
5007
5134
|
|
|
5008
5135
|
if (cssPath) {
|
|
5009
5136
|
const fullCssPath = '${base}assets/css/' + cssPath;
|
|
5010
|
-
|
|
5137
|
+
const inlineStyles = document.getElementById('coralite-inline-styles');
|
|
5138
|
+
const hasStyleInInline = inlineStyles && inlineStyles.textContent.includes('[data-style-selector="' + componentId + '"]');
|
|
5139
|
+
|
|
5140
|
+
if (!document.querySelector('link[href="' + fullCssPath + '"]') && !hasStyleInInline) {
|
|
5011
5141
|
const link = document.createElement('link');
|
|
5012
5142
|
link.rel = 'stylesheet';
|
|
5013
5143
|
link.href = fullCssPath;
|
|
@@ -5072,8 +5202,38 @@ import { getClientContext, createCoraliteClass, globalClientHooks } from '${base
|
|
|
5072
5202
|
return element;
|
|
5073
5203
|
};
|
|
5074
5204
|
|
|
5075
|
-
window.processHTML = (html) => {
|
|
5205
|
+
window.processHTML = (html, instanceId) => {
|
|
5076
5206
|
if (typeof html !== 'string') return html;
|
|
5207
|
+
|
|
5208
|
+
const mode = window.__coralite_mode__;
|
|
5209
|
+
const isDevOrTest = mode === 'development' || mode === 'testing';
|
|
5210
|
+
const isProduction = mode === 'production';
|
|
5211
|
+
|
|
5212
|
+
if (isDevOrTest || isProduction) {
|
|
5213
|
+
html = html.replace(/<([a-zA-Z0-9-]+)([^>]*)>/g, (match, tagName, attrs) => {
|
|
5214
|
+
let newAttrs = attrs;
|
|
5215
|
+
|
|
5216
|
+
// Strip deprecated 'test' attribute
|
|
5217
|
+
newAttrs = newAttrs.replace(/\\s+test\\s*=\\s*(['"]).*?\\1/g, '');
|
|
5218
|
+
|
|
5219
|
+
// Handle data-testid
|
|
5220
|
+
const testIdRegex = /\\s+data-testid\\s*=\\s*(['"])(.*?)\\1/g;
|
|
5221
|
+
if (isProduction) {
|
|
5222
|
+
newAttrs = newAttrs.replace(testIdRegex, '');
|
|
5223
|
+
} else if (isDevOrTest) {
|
|
5224
|
+
const prefix = instanceId ? instanceId + '__' : '';
|
|
5225
|
+
if (prefix) {
|
|
5226
|
+
newAttrs = newAttrs.replace(testIdRegex, (attrMatch, quote, testValue) => {
|
|
5227
|
+
if (testValue.startsWith(prefix)) return attrMatch;
|
|
5228
|
+
return ' data-testid="' + prefix + testValue + '"';
|
|
5229
|
+
});
|
|
5230
|
+
}
|
|
5231
|
+
}
|
|
5232
|
+
|
|
5233
|
+
return '<' + tagName + newAttrs + '>';
|
|
5234
|
+
});
|
|
5235
|
+
}
|
|
5236
|
+
|
|
5077
5237
|
const matches = html.matchAll(/<([a-zA-Z0-9-]+)/g);
|
|
5078
5238
|
for (const match of matches) {
|
|
5079
5239
|
const tag = match[1].toLowerCase();
|
|
@@ -5424,20 +5584,11 @@ function createRenderer({
|
|
|
5424
5584
|
componentState = cleanKeys(componentState);
|
|
5425
5585
|
}
|
|
5426
5586
|
const module = cloneModuleInstance(moduleComponent.result);
|
|
5427
|
-
if (module.values && module.values.refs) {
|
|
5428
|
-
for (let i = 0; i < module.values.refs.length; i++) {
|
|
5429
|
-
const ref = module.values.refs[i];
|
|
5430
|
-
const uniqueRefValue = `${instanceId}__${ref.name}`;
|
|
5431
|
-
if (ref.element && ref.element.attribs) {
|
|
5432
|
-
ref.element.attribs.ref = uniqueRefValue;
|
|
5433
|
-
}
|
|
5434
|
-
componentState[`ref_${ref.name}`] = uniqueRefValue;
|
|
5435
|
-
}
|
|
5436
|
-
}
|
|
5437
5587
|
const mappedComponentContext = await hooks.trigger("onBeforeComponentRender", {
|
|
5438
5588
|
state: componentState,
|
|
5439
5589
|
componentId: module.id,
|
|
5440
5590
|
instanceId,
|
|
5591
|
+
template: module.template,
|
|
5441
5592
|
refs: module.values.refs,
|
|
5442
5593
|
textNodes: module.values.textNodes,
|
|
5443
5594
|
attributes: module.values.attributes,
|
|
@@ -5447,6 +5598,16 @@ function createRenderer({
|
|
|
5447
5598
|
app
|
|
5448
5599
|
});
|
|
5449
5600
|
componentState = mappedComponentContext.state;
|
|
5601
|
+
if (module.values && module.values.refs) {
|
|
5602
|
+
for (let i = 0; i < module.values.refs.length; i++) {
|
|
5603
|
+
const ref = module.values.refs[i];
|
|
5604
|
+
const uniqueRefValue = `${instanceId}__${ref.name}`;
|
|
5605
|
+
if (ref.element && ref.element.attribs) {
|
|
5606
|
+
ref.element.attribs.ref = uniqueRefValue;
|
|
5607
|
+
}
|
|
5608
|
+
componentState[`ref_${ref.name}`] = uniqueRefValue;
|
|
5609
|
+
}
|
|
5610
|
+
}
|
|
5450
5611
|
const result = module.template;
|
|
5451
5612
|
if (module.styles.length) {
|
|
5452
5613
|
const selector = module.id;
|
|
@@ -5947,27 +6108,7 @@ function createRenderer({
|
|
|
5947
6108
|
injectExternalStyles(mappedComponent.root, headElement, normalizedOptions.externalStyles);
|
|
5948
6109
|
}
|
|
5949
6110
|
if (mappedSessionObject.styles.size > 0) {
|
|
5950
|
-
|
|
5951
|
-
const cssPaths = [];
|
|
5952
|
-
const remainingStyles = /* @__PURE__ */ new Map();
|
|
5953
|
-
for (const [selector, css] of mappedSessionObject.styles) {
|
|
5954
|
-
const entry = globalScriptResult.manifest[selector];
|
|
5955
|
-
if (entry && entry.css) {
|
|
5956
|
-
cssPaths.push(entry.css);
|
|
5957
|
-
} else {
|
|
5958
|
-
remainingStyles.set(selector, css);
|
|
5959
|
-
}
|
|
5960
|
-
}
|
|
5961
|
-
if (cssPaths.length > 0) {
|
|
5962
|
-
const base = normalizedOptions.baseURL.endsWith("/") ? normalizedOptions.baseURL : normalizedOptions.baseURL + "/";
|
|
5963
|
-
injectExternalStyleLinks(mappedComponent.root, headElement, cssPaths, base);
|
|
5964
|
-
}
|
|
5965
|
-
if (remainingStyles.size > 0) {
|
|
5966
|
-
injectStyles(mappedComponent.root, headElement, remainingStyles);
|
|
5967
|
-
}
|
|
5968
|
-
} else {
|
|
5969
|
-
injectStyles(mappedComponent.root, headElement, mappedSessionObject.styles);
|
|
5970
|
-
}
|
|
6111
|
+
injectStyles(mappedComponent.root, headElement, mappedSessionObject.styles);
|
|
5971
6112
|
}
|
|
5972
6113
|
if (componentsToInclude.size > 0) {
|
|
5973
6114
|
const targetElement = headElement || bodyElement || mappedComponent.root;
|
|
@@ -6013,20 +6154,9 @@ function createRenderer({
|
|
|
6013
6154
|
error: new Error(JSON.stringify(scriptResult.manifest))
|
|
6014
6155
|
});
|
|
6015
6156
|
}
|
|
6016
|
-
|
|
6017
|
-
for (const tag of componentsToInclude) {
|
|
6018
|
-
if (scriptResult.manifest[tag]) {
|
|
6019
|
-
chunkManifest[tag] = scriptResult.manifest[tag];
|
|
6020
|
-
}
|
|
6021
|
-
}
|
|
6022
|
-
for (const tag in scriptResult.manifest) {
|
|
6023
|
-
if (tag !== "coralite-runtime" && !chunkManifest[tag]) {
|
|
6024
|
-
chunkManifest[tag] = scriptResult.manifest[tag];
|
|
6025
|
-
}
|
|
6026
|
-
}
|
|
6027
|
-
injectReadinessScript(mappedComponent.root, headElement, true);
|
|
6028
|
-
injectImportMap(mappedComponent.root, headElement, scriptResult.importMap);
|
|
6157
|
+
injectReadinessScript(mappedComponent.root, headElement, true, normalizedOptions.mode);
|
|
6029
6158
|
const base = normalizedOptions.baseURL.endsWith("/") ? normalizedOptions.baseURL : normalizedOptions.baseURL + "/";
|
|
6159
|
+
injectImportMap(mappedComponent.root, headElement, scriptResult.importMap, base);
|
|
6030
6160
|
const hydrationData = {};
|
|
6031
6161
|
for (const [id, instance] of Object.entries(instances)) {
|
|
6032
6162
|
if (instance.state && Object.keys(instance.state).length > 0) {
|
|
@@ -6037,9 +6167,9 @@ function createRenderer({
|
|
|
6037
6167
|
const scriptContent = generateClientRuntime({
|
|
6038
6168
|
base,
|
|
6039
6169
|
sharedChunkPath: scriptResult.manifest["coralite-runtime"],
|
|
6040
|
-
chunkManifest,
|
|
6041
6170
|
declarativeTags: Array.from(declarativeTags),
|
|
6042
|
-
hydrationData: serialize2(hydrationData)
|
|
6171
|
+
hydrationData: serialize2(hydrationData),
|
|
6172
|
+
mode: normalizedOptions.mode
|
|
6043
6173
|
});
|
|
6044
6174
|
const scriptElement = createCoraliteElement({
|
|
6045
6175
|
type: "tag",
|
|
@@ -6057,7 +6187,7 @@ function createRenderer({
|
|
|
6057
6187
|
}
|
|
6058
6188
|
removeElements(mappedComponent.skipRenderElements, true);
|
|
6059
6189
|
if (!mappedSessionObject.scripts.content[mappedComponent.path.pathname]) {
|
|
6060
|
-
injectReadinessScript(mappedComponent.root, headElement, false);
|
|
6190
|
+
injectReadinessScript(mappedComponent.root, headElement, false, normalizedOptions.mode);
|
|
6061
6191
|
}
|
|
6062
6192
|
const rawHTML = transformNode(mappedComponent.root);
|
|
6063
6193
|
const result = {
|
|
@@ -6158,10 +6288,74 @@ function createRenderer({
|
|
|
6158
6288
|
if (!buildOptions) {
|
|
6159
6289
|
buildOptions = {};
|
|
6160
6290
|
}
|
|
6161
|
-
|
|
6291
|
+
const projectRoot = app.options.projectRoot || process.cwd();
|
|
6292
|
+
const cacheDir = join4(projectRoot, ".coralite");
|
|
6293
|
+
const manifestPath = join4(cacheDir, "manifest.json");
|
|
6294
|
+
let manifest = {
|
|
6295
|
+
physical: {},
|
|
6296
|
+
virtual: {},
|
|
6297
|
+
dependencies: {},
|
|
6298
|
+
components: {}
|
|
6299
|
+
};
|
|
6300
|
+
try {
|
|
6301
|
+
const content = await readFile3(manifestPath, "utf8");
|
|
6302
|
+
manifest = JSON.parse(content);
|
|
6303
|
+
if (!manifest.components) {
|
|
6304
|
+
manifest.components = {};
|
|
6305
|
+
}
|
|
6306
|
+
} catch (e) {
|
|
6307
|
+
if (e.code !== "ENOENT") {
|
|
6308
|
+
handleError2({
|
|
6309
|
+
level: "WARN",
|
|
6310
|
+
message: `Could not parse manifest at ${manifestPath}: ${e.message}. Starting with fresh manifest.`
|
|
6311
|
+
});
|
|
6312
|
+
}
|
|
6313
|
+
}
|
|
6314
|
+
let componentBuildInfo = {
|
|
6315
|
+
completed: 0,
|
|
6316
|
+
skipped: 0,
|
|
6317
|
+
details: []
|
|
6318
|
+
};
|
|
6319
|
+
if (normalizedOptions.mode === "production" || normalizedOptions.mode === "testing") {
|
|
6162
6320
|
const allComponentIds = app.components.list.map((c) => c.result.id);
|
|
6163
6321
|
globalScriptResult = await scriptManager.compileAllInstances(allComponentIds, normalizedOptions.mode);
|
|
6164
6322
|
Object.assign(outputFiles, globalScriptResult.outputFiles);
|
|
6323
|
+
if (globalScriptResult.manifest) {
|
|
6324
|
+
const manifestJS = `export default ${JSON.stringify(globalScriptResult.manifest)};`;
|
|
6325
|
+
outputFiles["manifest.js"] = {
|
|
6326
|
+
path: "assets/js/manifest.js",
|
|
6327
|
+
hashedPath: "manifest.js",
|
|
6328
|
+
text: manifestJS
|
|
6329
|
+
};
|
|
6330
|
+
const newComponentManifest = globalScriptResult.manifest;
|
|
6331
|
+
const oldComponentManifest = manifest.components;
|
|
6332
|
+
for (const [id, value] of Object.entries(newComponentManifest)) {
|
|
6333
|
+
if (id === "coralite-runtime") {
|
|
6334
|
+
continue;
|
|
6335
|
+
}
|
|
6336
|
+
const isNew = !oldComponentManifest[id];
|
|
6337
|
+
const hasChanged = !isNew && (value.js !== oldComponentManifest[id].js || value.css !== oldComponentManifest[id].css);
|
|
6338
|
+
if (isNew || hasChanged) {
|
|
6339
|
+
componentBuildInfo.completed++;
|
|
6340
|
+
componentBuildInfo.details.push({
|
|
6341
|
+
id,
|
|
6342
|
+
status: "built",
|
|
6343
|
+
reason: isNew ? "New component" : "Source changed"
|
|
6344
|
+
});
|
|
6345
|
+
} else {
|
|
6346
|
+
componentBuildInfo.skipped++;
|
|
6347
|
+
componentBuildInfo.details.push({
|
|
6348
|
+
id,
|
|
6349
|
+
status: "skipped"
|
|
6350
|
+
});
|
|
6351
|
+
}
|
|
6352
|
+
}
|
|
6353
|
+
if (typeof buildOptions.onComponentBuild === "function") {
|
|
6354
|
+
await buildOptions.onComponentBuild(componentBuildInfo);
|
|
6355
|
+
} else if (typeof normalizedOptions.onComponentBuild === "function") {
|
|
6356
|
+
await normalizedOptions.onComponentBuild(componentBuildInfo);
|
|
6357
|
+
}
|
|
6358
|
+
}
|
|
6165
6359
|
} else if (normalizedOptions.mode === "development") {
|
|
6166
6360
|
if (!siteWideBundlePromise) {
|
|
6167
6361
|
const bundlePromise = (async () => {
|
|
@@ -6173,6 +6367,14 @@ function createRenderer({
|
|
|
6173
6367
|
delete outputFiles[key];
|
|
6174
6368
|
}
|
|
6175
6369
|
Object.assign(outputFiles, result.outputFiles);
|
|
6370
|
+
if (result.manifest) {
|
|
6371
|
+
const manifestJS = `export default ${JSON.stringify(result.manifest)};`;
|
|
6372
|
+
outputFiles["manifest.js"] = {
|
|
6373
|
+
path: "assets/js/manifest.js",
|
|
6374
|
+
hashedPath: "manifest.js",
|
|
6375
|
+
text: manifestJS
|
|
6376
|
+
};
|
|
6377
|
+
}
|
|
6176
6378
|
}
|
|
6177
6379
|
return result;
|
|
6178
6380
|
})();
|
|
@@ -6219,42 +6421,28 @@ function createRenderer({
|
|
|
6219
6421
|
}
|
|
6220
6422
|
}
|
|
6221
6423
|
sealedQueues.add(buildId);
|
|
6222
|
-
const
|
|
6223
|
-
|
|
6224
|
-
|
|
6225
|
-
let manifest = {
|
|
6226
|
-
physical: {},
|
|
6227
|
-
virtual: {},
|
|
6228
|
-
dependencies: {}
|
|
6229
|
-
};
|
|
6230
|
-
try {
|
|
6231
|
-
const content = await readFile3(manifestPath, "utf8");
|
|
6232
|
-
manifest = JSON.parse(content);
|
|
6233
|
-
for (const [path2, metadata] of Object.entries(manifest.physical || {})) {
|
|
6234
|
-
if (metadata.dependencies) {
|
|
6235
|
-
app._dependencyGraph.directPageComponents[path2] = metadata.dependencies;
|
|
6236
|
-
}
|
|
6424
|
+
for (const [path2, metadata] of Object.entries(manifest.physical || {})) {
|
|
6425
|
+
if (metadata.dependencies) {
|
|
6426
|
+
app._dependencyGraph.directPageComponents[path2] = metadata.dependencies;
|
|
6237
6427
|
}
|
|
6238
|
-
|
|
6239
|
-
|
|
6240
|
-
|
|
6241
|
-
|
|
6242
|
-
}
|
|
6243
|
-
app._refreshDependencyGraph();
|
|
6244
|
-
} catch (e) {
|
|
6245
|
-
if (e.code !== "ENOENT") {
|
|
6246
|
-
handleError2({
|
|
6247
|
-
level: "WARN",
|
|
6248
|
-
message: `Could not parse manifest at ${manifestPath}: ${e.message}. Starting with fresh manifest.`
|
|
6249
|
-
});
|
|
6428
|
+
}
|
|
6429
|
+
for (const [path2, metadata] of Object.entries(manifest.virtual || {})) {
|
|
6430
|
+
if (metadata.dependencies) {
|
|
6431
|
+
app._dependencyGraph.directPageComponents[path2] = metadata.dependencies;
|
|
6250
6432
|
}
|
|
6251
6433
|
}
|
|
6434
|
+
app._refreshDependencyGraph();
|
|
6435
|
+
const mocksStr = app.options.testing?.mocks ? serialize2(app.options.testing.mocks) : "";
|
|
6436
|
+
const mocksHash = hash(mocksStr);
|
|
6437
|
+
const mocksChanged = manifest.testingMocksHash !== mocksHash;
|
|
6252
6438
|
const pagesToRender = [];
|
|
6253
6439
|
const skippedPages = [];
|
|
6254
6440
|
const newManifest = {
|
|
6255
6441
|
physical: {},
|
|
6256
6442
|
virtual: {},
|
|
6257
|
-
dependencies: {}
|
|
6443
|
+
dependencies: {},
|
|
6444
|
+
components: {},
|
|
6445
|
+
testingMocksHash: mocksHash
|
|
6258
6446
|
};
|
|
6259
6447
|
const componentChanges = /* @__PURE__ */ new Map();
|
|
6260
6448
|
const allComponents = app.components.list;
|
|
@@ -6277,7 +6465,7 @@ function createRenderer({
|
|
|
6277
6465
|
};
|
|
6278
6466
|
for (const pageItem of queue) {
|
|
6279
6467
|
let shouldRebuild = false;
|
|
6280
|
-
if (normalizedOptions.output && normalizedOptions.mode === "production") {
|
|
6468
|
+
if (normalizedOptions.output && (normalizedOptions.mode === "production" || normalizedOptions.mode === "testing")) {
|
|
6281
6469
|
const relativeDir = relative3(normalizedOptions.path.pages, pageItem.path.dirname);
|
|
6282
6470
|
const outFile = join4(normalizedOptions.output, relativeDir, pageItem.path.filename);
|
|
6283
6471
|
try {
|
|
@@ -6296,6 +6484,9 @@ function createRenderer({
|
|
|
6296
6484
|
if (componentIds.some((id) => componentChanges.get(id))) {
|
|
6297
6485
|
shouldRebuild = true;
|
|
6298
6486
|
}
|
|
6487
|
+
if (mocksChanged) {
|
|
6488
|
+
shouldRebuild = true;
|
|
6489
|
+
}
|
|
6299
6490
|
if (pageItem.virtual) {
|
|
6300
6491
|
if (shouldRebuild || pageItem.volatile || !manifest.virtual || !manifest.virtual[pageItem.path.pathname] || String(manifest.virtual[pageItem.path.pathname].cacheKey) !== String(pageItem.cacheKey) || normalizedOptions.mode === "development") {
|
|
6301
6492
|
shouldRebuild = true;
|
|
@@ -6427,6 +6618,7 @@ function createRenderer({
|
|
|
6427
6618
|
}
|
|
6428
6619
|
try {
|
|
6429
6620
|
await mkdir2(cacheDir, { recursive: true });
|
|
6621
|
+
newManifest.components = globalScriptResult?.manifest || {};
|
|
6430
6622
|
const tempManifestPath = `${manifestPath}.tmp`;
|
|
6431
6623
|
await writeFile(tempManifestPath, JSON.stringify(newManifest, null, 2));
|
|
6432
6624
|
await rename(tempManifestPath, manifestPath);
|
|
@@ -6493,8 +6685,10 @@ async function createCoralite({
|
|
|
6493
6685
|
ignoreByAttribute,
|
|
6494
6686
|
skipRenderByAttribute,
|
|
6495
6687
|
onError,
|
|
6688
|
+
onComponentBuild,
|
|
6496
6689
|
mode = "production",
|
|
6497
|
-
output
|
|
6690
|
+
output,
|
|
6691
|
+
testing
|
|
6498
6692
|
}) {
|
|
6499
6693
|
if (!components || typeof components !== "string") {
|
|
6500
6694
|
handleError({
|
|
@@ -6530,7 +6724,9 @@ async function createCoralite({
|
|
|
6530
6724
|
skipRenderByAttribute,
|
|
6531
6725
|
mode,
|
|
6532
6726
|
path: path2,
|
|
6533
|
-
output: output ? normalize(output) : void 0
|
|
6727
|
+
output: output ? normalize(output) : void 0,
|
|
6728
|
+
onComponentBuild,
|
|
6729
|
+
testing
|
|
6534
6730
|
};
|
|
6535
6731
|
const trackedOutputFiles = /* @__PURE__ */ new Set();
|
|
6536
6732
|
const app = {
|
|
@@ -6781,9 +6977,7 @@ async function createCoralite({
|
|
|
6781
6977
|
return results;
|
|
6782
6978
|
}
|
|
6783
6979
|
});
|
|
6784
|
-
|
|
6785
|
-
app.options.plugins.unshift(testingPlugin);
|
|
6786
|
-
}
|
|
6980
|
+
app.options.plugins.unshift(testingPlugin);
|
|
6787
6981
|
app.options.plugins.unshift(metadataPlugin);
|
|
6788
6982
|
if (assets) {
|
|
6789
6983
|
app.options.plugins.unshift(staticAssetPlugin(assets));
|
|
@@ -6839,7 +7033,7 @@ async function createCoralite({
|
|
|
6839
7033
|
onUpdate: handlers.onPageUpdate,
|
|
6840
7034
|
onDelete: handlers.onPageDelete
|
|
6841
7035
|
});
|
|
6842
|
-
if (app.options.mode === "production") {
|
|
7036
|
+
if (app.options.mode === "production" || app.options.mode === "testing") {
|
|
6843
7037
|
for await (const file of discoverHtmlFiles({
|
|
6844
7038
|
path: app.options.pages,
|
|
6845
7039
|
recursive: true,
|
|
@@ -6880,6 +7074,30 @@ function defineConfig(options) {
|
|
|
6880
7074
|
throw new CoraliteError(`Config property "${prop}" cannot be empty`);
|
|
6881
7075
|
}
|
|
6882
7076
|
}
|
|
7077
|
+
if (options.mode !== void 0) {
|
|
7078
|
+
const validModes = ["production", "development", "testing"];
|
|
7079
|
+
if (!validModes.includes(options.mode)) {
|
|
7080
|
+
throw new CoraliteError(`Invalid mode: "${options.mode}". Valid modes are: ${validModes.join(", ")}`);
|
|
7081
|
+
}
|
|
7082
|
+
}
|
|
7083
|
+
if (options.testing !== void 0) {
|
|
7084
|
+
if (typeof options.testing !== "object" || options.testing === null) {
|
|
7085
|
+
throw new CoraliteError('Config property "testing" must be an object');
|
|
7086
|
+
}
|
|
7087
|
+
if (options.testing.mocks !== void 0) {
|
|
7088
|
+
if (typeof options.testing.mocks !== "object" || options.testing.mocks === null) {
|
|
7089
|
+
throw new CoraliteError('Config property "testing.mocks" must be an object');
|
|
7090
|
+
}
|
|
7091
|
+
for (const [key, mock] of Object.entries(options.testing.mocks)) {
|
|
7092
|
+
if (typeof mock !== "object" || mock === null) {
|
|
7093
|
+
throw new CoraliteError(`Mock for component "${key}" must be an object`);
|
|
7094
|
+
}
|
|
7095
|
+
if (mock.server !== void 0 && typeof mock.server !== "function") {
|
|
7096
|
+
throw new CoraliteError(`Mock server for component "${key}" must be a function`);
|
|
7097
|
+
}
|
|
7098
|
+
}
|
|
7099
|
+
}
|
|
7100
|
+
}
|
|
6883
7101
|
if ("plugins" in options && options.plugins !== void 0) {
|
|
6884
7102
|
if (!Array.isArray(options.plugins)) {
|
|
6885
7103
|
throw new CoraliteError(
|