@ptengine/lp-editor-core 1.0.0-alpha.2 → 1.0.0-alpha.3
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/README.md +28 -3
- package/dist/golden/fixtures/popup/README.md +9 -4
- package/dist/golden/manifest.json +114 -0
- package/dist/golden/verify.mjs +24 -2
- package/dist/index.d.ts +196 -206
- package/dist/index.js +244 -73
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -251,6 +251,9 @@ var THEME_PT_ID = "theme";
|
|
|
251
251
|
var ROOT_PT_ID = "root";
|
|
252
252
|
var FORMAT_META_NAME = "lpx-format";
|
|
253
253
|
var FORMAT_VERSION = "4";
|
|
254
|
+
var WRAP_ATTR = "data-pt-wrap";
|
|
255
|
+
var WRAP_SECTION_PT_ID = "ptwrap-section";
|
|
256
|
+
var WRAP_CONTAINER_PT_ID = "ptwrap-container";
|
|
254
257
|
var SWITCHES = [
|
|
255
258
|
{
|
|
256
259
|
key: "hide",
|
|
@@ -352,6 +355,9 @@ var rules = {
|
|
|
352
355
|
rootPtId: ROOT_PT_ID,
|
|
353
356
|
formatMetaName: FORMAT_META_NAME,
|
|
354
357
|
formatVersion: FORMAT_VERSION,
|
|
358
|
+
wrapAttr: WRAP_ATTR,
|
|
359
|
+
wrapSectionPtId: WRAP_SECTION_PT_ID,
|
|
360
|
+
wrapContainerPtId: WRAP_CONTAINER_PT_ID,
|
|
355
361
|
switches: SWITCHES,
|
|
356
362
|
crossDeviceConsistentProperties: CROSS_DEVICE_CONSISTENT_PROPERTIES,
|
|
357
363
|
opaqueModes: OPAQUE_MODES,
|
|
@@ -362,43 +368,8 @@ var rules = {
|
|
|
362
368
|
arbitraryValueAllowedProperties: ARBITRARY_VALUE_ALLOWED_PROPERTIES
|
|
363
369
|
};
|
|
364
370
|
|
|
365
|
-
// src/kinds.ts
|
|
366
|
-
var KIND_PROFILES = {
|
|
367
|
-
page: {
|
|
368
|
-
root: "document",
|
|
369
|
-
layers: ["section", "container", "leaf"],
|
|
370
|
-
compile: "document",
|
|
371
|
-
leafTypes: ["text", "media", "button", "shape"],
|
|
372
|
-
components: {
|
|
373
|
-
carousel: "self",
|
|
374
|
-
faq: "self",
|
|
375
|
-
tabs: "self",
|
|
376
|
-
"sticky-cta": "self",
|
|
377
|
-
form: "self"
|
|
378
|
-
},
|
|
379
|
-
units: { vh: true },
|
|
380
|
-
customCode: true
|
|
381
|
-
},
|
|
382
|
-
popup: {
|
|
383
|
-
root: "fragment",
|
|
384
|
-
// 弹窗无 section 层:root › children。
|
|
385
|
-
layers: ["container", "leaf"],
|
|
386
|
-
compile: "shadow-px",
|
|
387
|
-
leafTypes: ["text", "media", "button", "shape"],
|
|
388
|
-
components: {
|
|
389
|
-
form: "engage-sdk",
|
|
390
|
-
countdown: "engage-sdk",
|
|
391
|
-
carousel: "self",
|
|
392
|
-
faq: "self",
|
|
393
|
-
tabs: "self"
|
|
394
|
-
},
|
|
395
|
-
units: { vh: false },
|
|
396
|
-
customCode: false
|
|
397
|
-
}
|
|
398
|
-
};
|
|
399
|
-
|
|
400
371
|
// src/version.ts
|
|
401
|
-
var VERSION = "1.0.0-alpha.
|
|
372
|
+
var VERSION = "1.0.0-alpha.3";
|
|
402
373
|
var COMPILER_VERSION = "1";
|
|
403
374
|
|
|
404
375
|
// src/validate/tree.ts
|
|
@@ -564,6 +535,163 @@ function* walkElements(root) {
|
|
|
564
535
|
for (let i = 0; i < list.length; i++) yield list[i];
|
|
565
536
|
}
|
|
566
537
|
|
|
538
|
+
// src/wrap.ts
|
|
539
|
+
function isWrapLayer(el) {
|
|
540
|
+
return el.hasAttribute(WRAP_ATTR);
|
|
541
|
+
}
|
|
542
|
+
var SKELETON = `<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="${FORMAT_META_NAME}" content="${FORMAT_VERSION}"></head><body></body></html>`;
|
|
543
|
+
function createWrap(parse) {
|
|
544
|
+
return function wrap(fragmentHtml) {
|
|
545
|
+
if (typeof fragmentHtml !== "string") {
|
|
546
|
+
throw new TypeError("wrap(): fragmentHtml \u5FC5\u987B\u662F\u5B57\u7B26\u4E32");
|
|
547
|
+
}
|
|
548
|
+
const doc = parse(SKELETON);
|
|
549
|
+
const frag = parseFragment(doc, fragmentHtml);
|
|
550
|
+
const { theme, root, before, after } = checkFragmentShape(frag);
|
|
551
|
+
checkReservedLiterals(frag, root, theme);
|
|
552
|
+
const body = doc.body;
|
|
553
|
+
const attrs = root.attributes;
|
|
554
|
+
for (let i = 0; i < attrs.length; i++) {
|
|
555
|
+
body.setAttribute(attrs[i].name, attrs[i].value);
|
|
556
|
+
}
|
|
557
|
+
if (theme) doc.head.appendChild(theme);
|
|
558
|
+
const section = doc.createElement("section");
|
|
559
|
+
section.setAttribute(WRAP_ATTR, "");
|
|
560
|
+
section.setAttribute("data-pt-id", WRAP_SECTION_PT_ID);
|
|
561
|
+
const container = doc.createElement("div");
|
|
562
|
+
container.setAttribute(WRAP_ATTR, "");
|
|
563
|
+
container.setAttribute("data-pt-id", WRAP_CONTAINER_PT_ID);
|
|
564
|
+
while (root.firstChild) container.appendChild(root.firstChild);
|
|
565
|
+
section.appendChild(container);
|
|
566
|
+
for (const node of before) body.appendChild(node);
|
|
567
|
+
body.appendChild(section);
|
|
568
|
+
for (const node of after) body.appendChild(node);
|
|
569
|
+
return doc;
|
|
570
|
+
};
|
|
571
|
+
}
|
|
572
|
+
function checkFragmentShape(frag) {
|
|
573
|
+
const elements = [];
|
|
574
|
+
const nonElements = [];
|
|
575
|
+
let child = frag.firstChild;
|
|
576
|
+
while (child) {
|
|
577
|
+
const next = child.nextSibling;
|
|
578
|
+
if (child.nodeType === 1) {
|
|
579
|
+
elements.push(child);
|
|
580
|
+
} else if (child.nodeType === 3 && child.data.trim() === "") {
|
|
581
|
+
nonElements.push({ node: child, afterElements: elements.length });
|
|
582
|
+
} else {
|
|
583
|
+
throw new TypeError(
|
|
584
|
+
`wrap(): \u7247\u6BB5\u9876\u5C42\u53EA\u5141\u8BB8 theme \u5757\u3001\u5355\u4E00\u6839\u5143\u7D20\u4E0E\u7A7A\u767D \u2014\u2014 \u51FA\u73B0\u4E86 ${describeNode(child)}\u3002\u91CE\u751F\u5F62\u72B6\u8BF7\u5728\u8C03\u7528\u65B9\u7684 adapter \u91CC\u5148\u89C4\u6574\u3002`
|
|
585
|
+
);
|
|
586
|
+
}
|
|
587
|
+
child = next;
|
|
588
|
+
}
|
|
589
|
+
let theme = null;
|
|
590
|
+
let root;
|
|
591
|
+
if (elements.length === 2) {
|
|
592
|
+
if (!isThemeStyle(elements[0])) {
|
|
593
|
+
throw new TypeError(
|
|
594
|
+
'wrap(): \u7247\u6BB5\u9876\u5C42\u6709\u4E24\u4E2A\u5143\u7D20\u65F6\uFF0C\u7B2C\u4E00\u4E2A\u5FC5\u987B\u662F\u4E3B\u9898\u5757 <style type="text/tailwindcss">'
|
|
595
|
+
);
|
|
596
|
+
}
|
|
597
|
+
theme = elements[0];
|
|
598
|
+
root = elements[1];
|
|
599
|
+
} else if (elements.length === 1) {
|
|
600
|
+
if (isThemeStyle(elements[0])) {
|
|
601
|
+
throw new TypeError("wrap(): \u7247\u6BB5\u53EA\u6709\u4E3B\u9898\u5757\u3001\u6CA1\u6709\u6839\u5143\u7D20");
|
|
602
|
+
}
|
|
603
|
+
root = elements[0];
|
|
604
|
+
} else {
|
|
605
|
+
throw new TypeError(
|
|
606
|
+
`wrap(): \u7247\u6BB5\u9876\u5C42\u5FC5\u987B\u6070\u6709\u4E00\u4E2A\u6839\u5143\u7D20\uFF08\u53EF\u9009\u4E00\u4E2A\u4E3B\u9898\u5757\uFF09\uFF0C\u5B9E\u9645\u6709 ${elements.length} \u4E2A\u5143\u7D20`
|
|
607
|
+
);
|
|
608
|
+
}
|
|
609
|
+
if (tag(root) !== "div") {
|
|
610
|
+
throw new TypeError(`wrap(): \u7247\u6BB5\u6839\u5143\u7D20\u5FC5\u987B\u662F <div>\uFF0C\u5B9E\u9645\u662F <${tag(root)}>`);
|
|
611
|
+
}
|
|
612
|
+
if (root.getAttribute("data-pt-id") !== ROOT_PT_ID) {
|
|
613
|
+
throw new TypeError(
|
|
614
|
+
`wrap(): \u7247\u6BB5\u6839\u5143\u7D20\u7684 data-pt-id \u5FC5\u987B\u662F ${ROOT_PT_ID}\uFF0C\u5B9E\u9645\u662F ${JSON.stringify(root.getAttribute("data-pt-id"))}\u3002\u5B83\u4F1A\u88AB\u8BA4\u9886\u6210\u6587\u6863\u7684 <body>\uFF0C\u6539\u540D\u4F1A\u8BA9\u57CB\u70B9\u951A\u70B9\u65AD\u94FE\u3002`
|
|
615
|
+
);
|
|
616
|
+
}
|
|
617
|
+
const rootIndex = elements.indexOf(root);
|
|
618
|
+
const before = [];
|
|
619
|
+
const after = [];
|
|
620
|
+
for (const { node, afterElements } of nonElements) {
|
|
621
|
+
if (afterElements <= rootIndex) before.push(node);
|
|
622
|
+
else after.push(node);
|
|
623
|
+
}
|
|
624
|
+
return { theme, root, before, after };
|
|
625
|
+
}
|
|
626
|
+
function checkReservedLiterals(frag, root, theme) {
|
|
627
|
+
const all = frag.querySelectorAll("*");
|
|
628
|
+
for (let i = 0; i < all.length; i++) {
|
|
629
|
+
const el = all[i];
|
|
630
|
+
if (el.hasAttribute(WRAP_ATTR)) {
|
|
631
|
+
throw new TypeError(
|
|
632
|
+
`wrap(): \u7247\u6BB5\u91CC\u5DF2\u7ECF\u5E26\u7740\u5408\u6210\u5C42\u6807\u8BB0 ${WRAP_ATTR} \u2014\u2014 \u591A\u534A\u662F\u4E0A\u4E00\u8F6E\u6F0F\u5265\u6216\u56DE\u704C\uFF0C\u5148\u67E5\u4E0A\u6E38\uFF0C\u4E0D\u8981\u91CD\u590D\u5305\u88F9\u3002`
|
|
633
|
+
);
|
|
634
|
+
}
|
|
635
|
+
const id = el.getAttribute("data-pt-id");
|
|
636
|
+
if (id === null) continue;
|
|
637
|
+
if (id === WRAP_SECTION_PT_ID || id === WRAP_CONTAINER_PT_ID) {
|
|
638
|
+
throw new TypeError(`wrap(): \u7247\u6BB5\u91CC\u5DF2\u7ECF\u5360\u7528\u4E86\u5408\u6210\u5C42\u7684\u4FDD\u7559 id ${id}`);
|
|
639
|
+
}
|
|
640
|
+
if (id === ROOT_PT_ID && el !== root) {
|
|
641
|
+
throw new TypeError(
|
|
642
|
+
`wrap(): \u4FDD\u7559 id ${ROOT_PT_ID} \u53EA\u8BB8\u51FA\u73B0\u5728\u7247\u6BB5\u6839\u5143\u7D20\u4E0A\uFF0C\u8FD9\u91CC\u51FA\u73B0\u5728 <${tag(el)}> \u4E0A \u2014\u2014 \u5305\u88F9\u540E\u4F1A\u53D8\u6210\u91CD\u590D id`
|
|
643
|
+
);
|
|
644
|
+
}
|
|
645
|
+
if (id === THEME_PT_ID && el !== theme) {
|
|
646
|
+
throw new TypeError(
|
|
647
|
+
`wrap(): \u4FDD\u7559 id ${THEME_PT_ID} \u53EA\u8BB8\u51FA\u73B0\u5728\u4E3B\u9898\u5757\u4E0A\uFF0C\u8FD9\u91CC\u51FA\u73B0\u5728 <${tag(el)}> \u4E0A`
|
|
648
|
+
);
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
function unwrap(doc) {
|
|
653
|
+
if (!doc || doc.nodeType !== 9) {
|
|
654
|
+
throw new TypeError("unwrap(): \u5165\u53C2\u5FC5\u987B\u662F Document");
|
|
655
|
+
}
|
|
656
|
+
const clone = doc.cloneNode(true);
|
|
657
|
+
const body = clone.body;
|
|
658
|
+
if (!body) throw new TypeError("unwrap(): \u6587\u6863\u6CA1\u6709 <body>");
|
|
659
|
+
const section = onlyWrapChild(body, "body");
|
|
660
|
+
const container = onlyWrapChild(section, `<${tag(section)} ${WRAP_ATTR}>`);
|
|
661
|
+
const div = clone.createElement("div");
|
|
662
|
+
const attrs = body.attributes;
|
|
663
|
+
for (let i = 0; i < attrs.length; i++) div.setAttribute(attrs[i].name, attrs[i].value);
|
|
664
|
+
while (container.firstChild) div.appendChild(container.firstChild);
|
|
665
|
+
const out = clone.createDocumentFragment();
|
|
666
|
+
const theme = clone.head?.querySelector('style[type="text/tailwindcss"]') ?? null;
|
|
667
|
+
if (theme) out.appendChild(theme);
|
|
668
|
+
const children = Array.from(body.childNodes);
|
|
669
|
+
for (const node of children) {
|
|
670
|
+
out.appendChild(node === section ? div : node);
|
|
671
|
+
}
|
|
672
|
+
return out;
|
|
673
|
+
}
|
|
674
|
+
function onlyWrapChild(parent, label) {
|
|
675
|
+
const kids = parent.children;
|
|
676
|
+
if (kids.length !== 1) {
|
|
677
|
+
throw new TypeError(
|
|
678
|
+
`unwrap(): ${label} \u4E0B\u5FC5\u987B\u6070\u6709\u4E00\u4E2A\u5408\u6210\u5C42\u5B50\u5143\u7D20\uFF0C\u5B9E\u9645\u6709 ${kids.length} \u4E2A \u2014\u2014 \u4E0D\u731C\u4E00\u4E2A\u51FA\u6765\u3002\u8FD9\u4EFD\u6587\u6863\u4E0D\u662F wrap() \u7684\u4EA7\u7269\uFF0C\u6216\u8005\u88AB\u6539\u6210\u4E86\u522B\u7684\u7ED3\u6784\u3002`
|
|
679
|
+
);
|
|
680
|
+
}
|
|
681
|
+
const only = kids[0];
|
|
682
|
+
if (!only.hasAttribute(WRAP_ATTR)) {
|
|
683
|
+
throw new TypeError(
|
|
684
|
+
`unwrap(): ${label} \u4E0B\u552F\u4E00\u7684\u5B50\u5143\u7D20\u6CA1\u6709 ${WRAP_ATTR} \u6807\u8BB0 \u2014\u2014 \u8FD9\u4EFD\u6587\u6863\u6CA1\u6709\u88AB wrap() \u5305\u88F9\u8FC7\u3002`
|
|
685
|
+
);
|
|
686
|
+
}
|
|
687
|
+
return only;
|
|
688
|
+
}
|
|
689
|
+
function describeNode(node) {
|
|
690
|
+
if (node.nodeType === 8) return "\u6CE8\u91CA\u8282\u70B9";
|
|
691
|
+
if (node.nodeType === 3) return `\u975E\u7A7A\u767D\u6587\u672C ${JSON.stringify(node.data.trim())}`;
|
|
692
|
+
return `nodeType ${node.nodeType}`;
|
|
693
|
+
}
|
|
694
|
+
|
|
567
695
|
// src/validate/variants.ts
|
|
568
696
|
var DEVICE = new Set(DEVICE_VARIANTS);
|
|
569
697
|
var STATE = new Set(STATE_VARIANTS);
|
|
@@ -631,14 +759,25 @@ function isNativePaletteClass(className) {
|
|
|
631
759
|
|
|
632
760
|
// src/validate/index.ts
|
|
633
761
|
var EVENT_ATTR = /^on[a-z]/i;
|
|
634
|
-
function validate(root, options) {
|
|
762
|
+
function validate(root, options = {}) {
|
|
635
763
|
const issues = [];
|
|
636
|
-
|
|
637
|
-
if (isDocument) checkFormatMeta(root, issues);
|
|
764
|
+
if (isDoc(root)) checkFormatMeta(root, issues);
|
|
638
765
|
checkIds(root, issues);
|
|
639
766
|
checkElements(root, options, issues);
|
|
767
|
+
if (options.singleSection) checkSingleSection(root, issues);
|
|
640
768
|
return { ok: issues.length === 0, issues };
|
|
641
769
|
}
|
|
770
|
+
function checkSingleSection(root, issues) {
|
|
771
|
+
const sections = root.querySelectorAll("section");
|
|
772
|
+
if (sections.length <= 1) return;
|
|
773
|
+
for (let i = 1; i < sections.length; i++) {
|
|
774
|
+
issues.push({
|
|
775
|
+
ptId: sections[i].getAttribute("data-pt-id") ?? void 0,
|
|
776
|
+
rule: "STRUCTURE",
|
|
777
|
+
params: { reason: "multiple-sections", count: sections.length }
|
|
778
|
+
});
|
|
779
|
+
}
|
|
780
|
+
}
|
|
642
781
|
function isDoc(root) {
|
|
643
782
|
return root.nodeType === 9;
|
|
644
783
|
}
|
|
@@ -723,11 +862,27 @@ function checkClasses(el, ptId, options, issues) {
|
|
|
723
862
|
issues.push({ ptId, rule: "NATIVE_PALETTE", params: { className: cls } });
|
|
724
863
|
continue;
|
|
725
864
|
}
|
|
865
|
+
if (options.allowVhUnits === false) {
|
|
866
|
+
const unit = viewportUnitIn(cls);
|
|
867
|
+
if (unit) {
|
|
868
|
+
issues.push({ ptId, rule: "UNIT_FORBIDDEN", params: { className: cls, unit } });
|
|
869
|
+
continue;
|
|
870
|
+
}
|
|
871
|
+
}
|
|
726
872
|
if (options.canCompileClass && !options.canCompileClass(cls)) {
|
|
727
873
|
issues.push({ ptId, rule: "CLASS_UNCOMPILABLE", params: { className: cls } });
|
|
728
874
|
}
|
|
729
875
|
}
|
|
730
876
|
}
|
|
877
|
+
var ARBITRARY_VIEWPORT_UNIT = /\[[^\]]*?\d(?:\.\d+)?(l|s|d)?(vh|vw|vmin|vmax|vb|vi)\b/;
|
|
878
|
+
var SCREEN_SCALE = /(^|:)(min-|max-)?[hw]-(screen|[lsd]vh|[lsd]vw|dvh|dvw|svh|svw|lvh|lvw)$/;
|
|
879
|
+
function viewportUnitIn(cls) {
|
|
880
|
+
const arbitrary = ARBITRARY_VIEWPORT_UNIT.exec(cls);
|
|
881
|
+
if (arbitrary) return `${arbitrary[1] ?? ""}${arbitrary[2]}`;
|
|
882
|
+
const scale = SCREEN_SCALE.exec(cls);
|
|
883
|
+
if (scale) return scale[3];
|
|
884
|
+
return null;
|
|
885
|
+
}
|
|
731
886
|
function checkPlaceholder(el, ptId, issues) {
|
|
732
887
|
if (!el.hasAttribute("data-pt-placeholder")) return;
|
|
733
888
|
const cls = el.getAttribute("class") ?? "";
|
|
@@ -762,6 +917,12 @@ var ERROR_CODES = [
|
|
|
762
917
|
"INLINE_STYLE",
|
|
763
918
|
/** 使用了 Tailwind 内置色板。它本身可编译,所以必须由独立规则拦。 */
|
|
764
919
|
"NATIVE_PALETTE",
|
|
920
|
+
/**
|
|
921
|
+
* 用了视口相对单位(vh / dvh / h-screen…),而当前调用方关掉了它
|
|
922
|
+
* (`validate(doc, { allowVhUnits: false })`)。同 NATIVE_PALETTE:它可编译,
|
|
923
|
+
* 拒绝它是产品决定,所以「可编译」判定拦不住,必须独立一条。
|
|
924
|
+
*/
|
|
925
|
+
"UNIT_FORBIDDEN",
|
|
765
926
|
/** class 在当前 @theme 下编译不出 CSS。 */
|
|
766
927
|
"CLASS_UNCOMPILABLE",
|
|
767
928
|
/** 变体前缀不在允许集内,或组合顺序不是「设备在前、状态在后」。 */
|
|
@@ -795,13 +956,13 @@ function editorError(code, extra) {
|
|
|
795
956
|
|
|
796
957
|
// src/validate/structure.ts
|
|
797
958
|
var NOT_A_LAYER = /* @__PURE__ */ new Set(["html", "head", "body"]);
|
|
798
|
-
|
|
959
|
+
var LEAF_TYPE_SET = new Set(LEAF_TYPES);
|
|
960
|
+
function layerOf(el) {
|
|
799
961
|
const name = tag(el);
|
|
800
962
|
if (NOT_A_LAYER.has(name)) return null;
|
|
801
|
-
|
|
802
|
-
if (hasSectionLayer && name === "section") return "section";
|
|
963
|
+
if (name === "section") return "section";
|
|
803
964
|
const ptType = el.getAttribute("data-pt-type");
|
|
804
|
-
if (ptType &&
|
|
965
|
+
if (ptType && LEAF_TYPE_SET.has(ptType)) return "leaf";
|
|
805
966
|
if (el.hasAttribute("data-pt-component")) return "leaf";
|
|
806
967
|
const opaque = closestOpaque(el);
|
|
807
968
|
if (opaque && opaque.host === el) return "leaf";
|
|
@@ -809,19 +970,19 @@ function layerOf(el, profile) {
|
|
|
809
970
|
return null;
|
|
810
971
|
}
|
|
811
972
|
var MAX_CONTAINER_DEPTH = 2;
|
|
812
|
-
function containerDepth(el
|
|
973
|
+
function containerDepth(el) {
|
|
813
974
|
let depth = 0;
|
|
814
975
|
let cur = el;
|
|
815
976
|
while (cur) {
|
|
816
|
-
if (layerOf(cur
|
|
977
|
+
if (layerOf(cur) === "container" && !isWrapLayer(cur)) depth += 1;
|
|
817
978
|
cur = cur.parentElement;
|
|
818
979
|
}
|
|
819
980
|
return depth;
|
|
820
981
|
}
|
|
821
|
-
function canContain(parent, childLayer
|
|
982
|
+
function canContain(parent, childLayer) {
|
|
822
983
|
const opaque = closestOpaque(parent);
|
|
823
984
|
if (opaque) return "opaque-subtree";
|
|
824
|
-
const parentLayer = layerOf(parent
|
|
985
|
+
const parentLayer = layerOf(parent);
|
|
825
986
|
if (childLayer === "section") {
|
|
826
987
|
const isBody = tag(parent) === "body";
|
|
827
988
|
return isBody ? null : "section-not-body-child";
|
|
@@ -829,23 +990,21 @@ function canContain(parent, childLayer, profile) {
|
|
|
829
990
|
if (childLayer === "container") {
|
|
830
991
|
if (parentLayer === "section") return null;
|
|
831
992
|
if (parentLayer === "container") {
|
|
832
|
-
return containerDepth(parent
|
|
993
|
+
return containerDepth(parent) + 1 > MAX_CONTAINER_DEPTH ? "container-too-deep" : null;
|
|
833
994
|
}
|
|
834
|
-
if (!profile.layers.includes("section") && parentLayer === null) return null;
|
|
835
995
|
return parentLayer === "leaf" ? "leaf-cannot-contain" : "unknown-layer";
|
|
836
996
|
}
|
|
837
997
|
if (parentLayer === "container") return null;
|
|
838
998
|
if (parentLayer === "leaf") return "leaf-cannot-contain";
|
|
839
|
-
if (!profile.layers.includes("section") && parentLayer === null) return null;
|
|
840
999
|
return "unknown-layer";
|
|
841
1000
|
}
|
|
842
|
-
function deleteTarget(el
|
|
843
|
-
const layer = layerOf(el
|
|
1001
|
+
function deleteTarget(el) {
|
|
1002
|
+
const layer = layerOf(el);
|
|
844
1003
|
if (layer !== "container") return el;
|
|
845
1004
|
const parent = el.parentElement;
|
|
846
|
-
if (!parent || layerOf(parent
|
|
1005
|
+
if (!parent || layerOf(parent) !== "section") return el;
|
|
847
1006
|
const siblingContainers = Array.from(parent.children).filter(
|
|
848
|
-
(c) => c !== el && layerOf(c
|
|
1007
|
+
(c) => c !== el && layerOf(c) === "container"
|
|
849
1008
|
);
|
|
850
1009
|
return siblingContainers.length === 0 ? parent : el;
|
|
851
1010
|
}
|
|
@@ -931,33 +1090,33 @@ function requireCanonicalFragment(doc, html) {
|
|
|
931
1090
|
|
|
932
1091
|
// src/ops/apply.ts
|
|
933
1092
|
var RAW_TEXT = /* @__PURE__ */ new Set(["style", "script", "xmp", "iframe", "noembed", "noframes", "plaintext"]);
|
|
934
|
-
function apply(doc, ops
|
|
1093
|
+
function apply(doc, ops) {
|
|
935
1094
|
if (!Array.isArray(ops)) throw new TypeError("apply(): ops \u5FC5\u987B\u662F\u6570\u7EC4");
|
|
936
1095
|
if (ops.length === 0) return { ok: true, inverse: [] };
|
|
937
1096
|
const rehearsal = doc.cloneNode(true);
|
|
938
|
-
const dry = run(rehearsal, ops
|
|
1097
|
+
const dry = run(rehearsal, ops);
|
|
939
1098
|
if (!dry.ok) return dry;
|
|
940
|
-
return run(doc, ops
|
|
1099
|
+
return run(doc, ops);
|
|
941
1100
|
}
|
|
942
|
-
function run(doc, ops
|
|
1101
|
+
function run(doc, ops) {
|
|
943
1102
|
const inverse = [];
|
|
944
1103
|
for (let i = 0; i < ops.length; i++) {
|
|
945
|
-
const result = applyOne(doc, ops[i]
|
|
1104
|
+
const result = applyOne(doc, ops[i]);
|
|
946
1105
|
if (!result.ok) return { ok: false, error: result.error, failedIndex: i };
|
|
947
1106
|
inverse.unshift(result.inverse);
|
|
948
1107
|
}
|
|
949
1108
|
return { ok: true, inverse };
|
|
950
1109
|
}
|
|
951
|
-
function applyOne(doc, op
|
|
1110
|
+
function applyOne(doc, op) {
|
|
952
1111
|
switch (op.op) {
|
|
953
1112
|
case "set":
|
|
954
1113
|
return applySet(doc, op);
|
|
955
1114
|
case "insert":
|
|
956
|
-
return applyInsert(doc, op
|
|
1115
|
+
return applyInsert(doc, op);
|
|
957
1116
|
case "delete":
|
|
958
|
-
return applyDelete(doc, op
|
|
1117
|
+
return applyDelete(doc, op);
|
|
959
1118
|
case "move":
|
|
960
|
-
return applyMove(doc, op
|
|
1119
|
+
return applyMove(doc, op);
|
|
961
1120
|
case "replace":
|
|
962
1121
|
return applyReplace(doc, op);
|
|
963
1122
|
default:
|
|
@@ -969,10 +1128,15 @@ function applyOne(doc, op, options) {
|
|
|
969
1128
|
};
|
|
970
1129
|
}
|
|
971
1130
|
}
|
|
1131
|
+
function rejectWrapTarget(el, ptId) {
|
|
1132
|
+
return isWrapLayer(el) ? editorError("STRUCTURE", { ptId, params: { reason: "wrap-layer-immutable" } }) : null;
|
|
1133
|
+
}
|
|
972
1134
|
function applySet(doc, op) {
|
|
973
1135
|
const miss = requireIdHit(doc, op.id);
|
|
974
1136
|
if (miss) return { ok: false, error: miss };
|
|
975
1137
|
const el = findById(doc, op.id);
|
|
1138
|
+
const wrapped = rejectWrapTarget(el, op.id);
|
|
1139
|
+
if (wrapped) return { ok: false, error: wrapped };
|
|
976
1140
|
const opaque = closestOpaque(el);
|
|
977
1141
|
if (opaque && opaque.host !== el && opaque.mode !== "text") {
|
|
978
1142
|
return { ok: false, error: editorError("STRUCTURE", { ptId: op.id, params: { reason: "opaque-subtree" } }) };
|
|
@@ -1065,7 +1229,7 @@ function setChildren(doc, el, text) {
|
|
|
1065
1229
|
}
|
|
1066
1230
|
el.appendChild(parseFragment(doc, text));
|
|
1067
1231
|
}
|
|
1068
|
-
function applyInsert(doc, op
|
|
1232
|
+
function applyInsert(doc, op) {
|
|
1069
1233
|
const miss = requireIdHit(doc, op.parentId);
|
|
1070
1234
|
if (miss) return { ok: false, error: miss };
|
|
1071
1235
|
const parent = findById(doc, op.parentId);
|
|
@@ -1079,11 +1243,11 @@ function applyInsert(doc, op, options) {
|
|
|
1079
1243
|
const idErr = requireFragmentIds(frag, collectDocIds(doc));
|
|
1080
1244
|
if (idErr) return { ok: false, error: idErr };
|
|
1081
1245
|
const root = fragmentElementRoots(frag)[0];
|
|
1082
|
-
const childLayer = layerOf(root
|
|
1246
|
+
const childLayer = layerOf(root);
|
|
1083
1247
|
if (!childLayer) {
|
|
1084
1248
|
return { ok: false, error: editorError("STRUCTURE", { params: { reason: "unknown-layer" } }) };
|
|
1085
1249
|
}
|
|
1086
|
-
const rejection = canContain(parent, childLayer
|
|
1250
|
+
const rejection = canContain(parent, childLayer);
|
|
1087
1251
|
if (rejection) {
|
|
1088
1252
|
return { ok: false, error: editorError("STRUCTURE", { ptId: op.parentId, params: { reason: rejection } }) };
|
|
1089
1253
|
}
|
|
@@ -1092,15 +1256,17 @@ function applyInsert(doc, op, options) {
|
|
|
1092
1256
|
parent.insertBefore(frag, parent.childNodes[at] ?? null);
|
|
1093
1257
|
return { ok: true, inverse: { op: "delete", id: newId } };
|
|
1094
1258
|
}
|
|
1095
|
-
function applyDelete(doc, op
|
|
1259
|
+
function applyDelete(doc, op) {
|
|
1096
1260
|
const miss = requireIdHit(doc, op.id);
|
|
1097
1261
|
if (miss) return { ok: false, error: miss };
|
|
1098
1262
|
const el = findById(doc, op.id);
|
|
1263
|
+
const wrapped = rejectWrapTarget(el, op.id);
|
|
1264
|
+
if (wrapped) return { ok: false, error: wrapped };
|
|
1099
1265
|
const opaque = closestOpaque(el);
|
|
1100
1266
|
if (opaque && opaque.host !== el) {
|
|
1101
1267
|
return { ok: false, error: editorError("STRUCTURE", { ptId: op.id, params: { reason: "opaque-subtree" } }) };
|
|
1102
1268
|
}
|
|
1103
|
-
const target = deleteTarget(el
|
|
1269
|
+
const target = deleteTarget(el);
|
|
1104
1270
|
const parent = target.parentElement;
|
|
1105
1271
|
if (!parent) {
|
|
1106
1272
|
return { ok: false, error: editorError("STRUCTURE", { ptId: op.id, params: { reason: "no-parent" } }) };
|
|
@@ -1118,21 +1284,23 @@ function applyDelete(doc, op, options) {
|
|
|
1118
1284
|
inverse: { op: "insert", parentId, index: 0, html, nodeIndex }
|
|
1119
1285
|
};
|
|
1120
1286
|
}
|
|
1121
|
-
function applyMove(doc, op
|
|
1287
|
+
function applyMove(doc, op) {
|
|
1122
1288
|
const missSelf = requireIdHit(doc, op.id);
|
|
1123
1289
|
if (missSelf) return { ok: false, error: missSelf };
|
|
1124
1290
|
const missParent = requireIdHit(doc, op.parentId);
|
|
1125
1291
|
if (missParent) return { ok: false, error: missParent };
|
|
1126
1292
|
const el = findById(doc, op.id);
|
|
1127
1293
|
const parent = findById(doc, op.parentId);
|
|
1294
|
+
const wrapped = rejectWrapTarget(el, op.id);
|
|
1295
|
+
if (wrapped) return { ok: false, error: wrapped };
|
|
1128
1296
|
if (el === parent || el.contains(parent)) {
|
|
1129
1297
|
return { ok: false, error: editorError("STRUCTURE", { ptId: op.id, params: { reason: "move-into-self" } }) };
|
|
1130
1298
|
}
|
|
1131
|
-
const layer = layerOf(el
|
|
1299
|
+
const layer = layerOf(el);
|
|
1132
1300
|
if (!layer) {
|
|
1133
1301
|
return { ok: false, error: editorError("STRUCTURE", { ptId: op.id, params: { reason: "unknown-layer" } }) };
|
|
1134
1302
|
}
|
|
1135
|
-
const rejection = canContain(parent, layer
|
|
1303
|
+
const rejection = canContain(parent, layer);
|
|
1136
1304
|
if (rejection) {
|
|
1137
1305
|
return { ok: false, error: editorError("STRUCTURE", { ptId: op.parentId, params: { reason: rejection } }) };
|
|
1138
1306
|
}
|
|
@@ -1153,6 +1321,8 @@ function applyReplace(doc, op) {
|
|
|
1153
1321
|
const miss = requireIdHit(doc, op.id);
|
|
1154
1322
|
if (miss) return { ok: false, error: miss };
|
|
1155
1323
|
const el = findById(doc, op.id);
|
|
1324
|
+
const wrapped = rejectWrapTarget(el, op.id);
|
|
1325
|
+
if (wrapped) return { ok: false, error: wrapped };
|
|
1156
1326
|
const canonical = requireCanonicalFragment(doc, op.html);
|
|
1157
1327
|
if (canonical) return { ok: false, error: canonical };
|
|
1158
1328
|
const frag = parseFragment(doc, op.html);
|
|
@@ -1407,6 +1577,8 @@ function createCore(options) {
|
|
|
1407
1577
|
return {
|
|
1408
1578
|
parse,
|
|
1409
1579
|
parseFragment,
|
|
1580
|
+
wrap: createWrap(parse),
|
|
1581
|
+
unwrap,
|
|
1410
1582
|
serialize,
|
|
1411
1583
|
normalize,
|
|
1412
1584
|
validate,
|
|
@@ -1415,12 +1587,11 @@ function createCore(options) {
|
|
|
1415
1587
|
compile: compile_exports,
|
|
1416
1588
|
collectClasses,
|
|
1417
1589
|
rules,
|
|
1418
|
-
KIND_PROFILES,
|
|
1419
1590
|
VERSION,
|
|
1420
1591
|
COMPILER_VERSION
|
|
1421
1592
|
};
|
|
1422
1593
|
}
|
|
1423
1594
|
|
|
1424
|
-
export { COMPILER_VERSION, EMPTY_THEME, ERROR_CODES,
|
|
1595
|
+
export { COMPILER_VERSION, EMPTY_THEME, ERROR_CODES, MAX_CONTAINER_DEPTH, PUBLISH_BLOCKING_RULES, VERSION, apply, canContain, checkVariants, collectClasses, compile_exports as compile, containerDepth, createCore, deleteTarget, editorError, fragmentElementRoots, guards_exports as guards, isErrorCode, isNativePaletteClass, isPublishBlocking, isWrapLayer, layerOf, normalize, normalizeClassValue, parseFragment, rules, serialize, themeFromSource, themeOf, themeTokens, unwrap, validate };
|
|
1425
1596
|
//# sourceMappingURL=index.js.map
|
|
1426
1597
|
//# sourceMappingURL=index.js.map
|