@rebuy/rebuy 3.10.0 → 3.11.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/server/composeOffer.d.ts +2 -2
- package/dist/server/index.cjs +25 -12
- package/dist/server/index.mjs +25 -12
- package/dist/transforms/htmlToTiptap/decodeEntities.d.ts +19 -1
- package/dist/transforms/index.cjs +18 -9
- package/dist/transforms/index.mjs +18 -9
- package/dist/transforms/normalizeTextContent.d.ts +33 -6
- package/package.json +1 -1
|
@@ -3,8 +3,8 @@ import { type AdsEngineOffer } from '../server/adsEngine';
|
|
|
3
3
|
import { type MonetizeInput } from '../server/shared';
|
|
4
4
|
/**
|
|
5
5
|
* Compose one ads-engine offer into a renderable CAB card: a bordered `layout` whose `viewUrl` is the
|
|
6
|
-
* impression pixel, holding the header chrome, the copy (headline + HTML body,
|
|
7
|
-
*
|
|
6
|
+
* impression pixel, holding the header chrome, the copy (headline + HTML body, pre-converted to a
|
|
7
|
+
* small-sized Tiptap doc by {@link smallText}) beside the optional image (75%/fill — the React desktop split),
|
|
8
8
|
* the two CTAs in a 50/50 row, and the right-aligned Privacy Policy footer. `acceptOffer` links out
|
|
9
9
|
* to the advertiser (`destinationUrl` = `click_url`, which self-tracks); `declineOffer` fires the
|
|
10
10
|
* decline pixel (`trackingUrl`) and advances. Parsing through the schema fills defaults and validates
|
package/dist/server/index.cjs
CHANGED
|
@@ -2386,12 +2386,21 @@ var NAMED_ENTITIES = {
|
|
|
2386
2386
|
rsquo: "\u2019",
|
|
2387
2387
|
trade: "\u2122"
|
|
2388
2388
|
};
|
|
2389
|
-
var decodeEntities = (input = "") => input.replace(/&(#x[\da-f]+|#\d+|[a-z][a-z\d]*);/gi, (match, code) => {
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2389
|
+
var decodeEntities = (input = "", { keepAngles = false } = {}) => input.replace(/&(#x[\da-f]+|#\d+|[a-z][a-z\d]*);/gi, (match, code) => {
|
|
2390
|
+
let decoded;
|
|
2391
|
+
if (code[0] !== "#") {
|
|
2392
|
+
decoded = NAMED_ENTITIES[code.toLowerCase()] ?? match;
|
|
2393
|
+
} else {
|
|
2394
|
+
const isHex = /^#x/i.test(code);
|
|
2395
|
+
const cp = parseInt(code.slice(isHex ? 2 : 1), isHex ? 16 : 10);
|
|
2396
|
+
decoded = Number.isInteger(cp) && cp >= 0 && cp <= 1114111 ? String.fromCodePoint(cp) : match;
|
|
2397
|
+
}
|
|
2398
|
+
return keepAngles && (decoded === "<" || decoded === ">") ? match : decoded;
|
|
2394
2399
|
});
|
|
2400
|
+
var decodeTextEntities = (input = "") => {
|
|
2401
|
+
const decoded = decodeEntities(input);
|
|
2402
|
+
return isHTML(decoded) ? decodeEntities(input, { keepAngles: true }) : decoded;
|
|
2403
|
+
};
|
|
2395
2404
|
|
|
2396
2405
|
// src/transforms/htmlToTiptap/parseAttribs.ts
|
|
2397
2406
|
var ATTRIB_RE = /([a-zA-Z_:][\w:.-]*)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s"'`=<>]+)))?/g;
|
|
@@ -2446,7 +2455,7 @@ var openTag = (stack, name, attrs) => {
|
|
|
2446
2455
|
// src/transforms/htmlToTiptap/pushText.ts
|
|
2447
2456
|
var pushText = (state, rawText) => {
|
|
2448
2457
|
if (!rawText || isSkipping(state.stack)) return;
|
|
2449
|
-
|
|
2458
|
+
decodeTextEntities(rawText).split("\n").forEach((segment, index) => {
|
|
2450
2459
|
if (index > 0) flushParagraph(state);
|
|
2451
2460
|
if (!segment) return;
|
|
2452
2461
|
const marks = state.stack.flatMap((entry) => entry.marks);
|
|
@@ -2718,11 +2727,11 @@ var isMonetizeV1 = isWidgetV1(WidgetType.ui_extension_ad);
|
|
|
2718
2727
|
var HTML_TAG_RE2 = /<[a-zA-Z]/;
|
|
2719
2728
|
var containsHtml = (text2) => HTML_TAG_RE2.test(text2);
|
|
2720
2729
|
var isObject = (x) => x !== null && typeof x === "object" && !Array.isArray(x);
|
|
2721
|
-
var
|
|
2722
|
-
if (typeof value !== "string") return value;
|
|
2730
|
+
var normalizeTextValue = (value, options = {}) => {
|
|
2723
2731
|
const tokenized = normalizeTokens(value);
|
|
2724
|
-
return containsHtml(tokenized) ? htmlToTiptap(tokenized) : tokenized;
|
|
2732
|
+
return containsHtml(tokenized) || options.defaultTextStyle ? htmlToTiptap(tokenized, options) : decodeTextEntities(tokenized);
|
|
2725
2733
|
};
|
|
2734
|
+
var normalizeLangValue = (value) => typeof value === "string" ? normalizeTextValue(value) : value;
|
|
2726
2735
|
var normalizeTextContent = (node) => {
|
|
2727
2736
|
if (Array.isArray(node)) return node.map(normalizeTextContent);
|
|
2728
2737
|
if (!isObject(node)) return node;
|
|
@@ -3990,6 +3999,10 @@ var label = (text2) => ({
|
|
|
3990
3999
|
sectionType: SectionType.text
|
|
3991
4000
|
});
|
|
3992
4001
|
var text = (content) => ({ content: { en: content }, sectionType: SectionType.text });
|
|
4002
|
+
var smallText = (raw) => ({
|
|
4003
|
+
content: { en: normalizeTextValue(raw, { defaultTextStyle: { fontSize: "small" } }) },
|
|
4004
|
+
sectionType: SectionType.text
|
|
4005
|
+
});
|
|
3993
4006
|
var styled = (value, { align, bold, color, fontSize, href }) => ({
|
|
3994
4007
|
content: {
|
|
3995
4008
|
en: {
|
|
@@ -4019,8 +4032,8 @@ var shopName = (shop) => shop.replace(/\.myshopify\.com$/, "") || "store";
|
|
|
4019
4032
|
var headerSections = (input) => [
|
|
4020
4033
|
{
|
|
4021
4034
|
sections: [
|
|
4022
|
-
styled("Congratulations!", { bold: true, fontSize: "
|
|
4023
|
-
styled(`Your ${shopName(input.shop)} purchase unlocked a bonus:`, { bold: true, fontSize: "
|
|
4035
|
+
styled("Congratulations!", { bold: true, fontSize: "heading" }),
|
|
4036
|
+
styled(`Your ${shopName(input.shop)} purchase unlocked a bonus:`, { bold: true, fontSize: "heading" })
|
|
4024
4037
|
],
|
|
4025
4038
|
sectionType: SectionType.layout,
|
|
4026
4039
|
spacing: Spacing.none
|
|
@@ -4029,7 +4042,7 @@ var headerSections = (input) => [
|
|
|
4029
4042
|
];
|
|
4030
4043
|
var composeOfferCard = (offer, input) => {
|
|
4031
4044
|
const copy = {
|
|
4032
|
-
sections: [text(offer.headline),
|
|
4045
|
+
sections: [text(offer.headline), smallText(offer.description)],
|
|
4033
4046
|
sectionType: SectionType.layout,
|
|
4034
4047
|
spacing: Spacing.tight
|
|
4035
4048
|
};
|
package/dist/server/index.mjs
CHANGED
|
@@ -2338,12 +2338,21 @@ var NAMED_ENTITIES = {
|
|
|
2338
2338
|
rsquo: "\u2019",
|
|
2339
2339
|
trade: "\u2122"
|
|
2340
2340
|
};
|
|
2341
|
-
var decodeEntities = (input = "") => input.replace(/&(#x[\da-f]+|#\d+|[a-z][a-z\d]*);/gi, (match, code) => {
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2341
|
+
var decodeEntities = (input = "", { keepAngles = false } = {}) => input.replace(/&(#x[\da-f]+|#\d+|[a-z][a-z\d]*);/gi, (match, code) => {
|
|
2342
|
+
let decoded;
|
|
2343
|
+
if (code[0] !== "#") {
|
|
2344
|
+
decoded = NAMED_ENTITIES[code.toLowerCase()] ?? match;
|
|
2345
|
+
} else {
|
|
2346
|
+
const isHex = /^#x/i.test(code);
|
|
2347
|
+
const cp = parseInt(code.slice(isHex ? 2 : 1), isHex ? 16 : 10);
|
|
2348
|
+
decoded = Number.isInteger(cp) && cp >= 0 && cp <= 1114111 ? String.fromCodePoint(cp) : match;
|
|
2349
|
+
}
|
|
2350
|
+
return keepAngles && (decoded === "<" || decoded === ">") ? match : decoded;
|
|
2346
2351
|
});
|
|
2352
|
+
var decodeTextEntities = (input = "") => {
|
|
2353
|
+
const decoded = decodeEntities(input);
|
|
2354
|
+
return isHTML(decoded) ? decodeEntities(input, { keepAngles: true }) : decoded;
|
|
2355
|
+
};
|
|
2347
2356
|
|
|
2348
2357
|
// src/transforms/htmlToTiptap/parseAttribs.ts
|
|
2349
2358
|
var ATTRIB_RE = /([a-zA-Z_:][\w:.-]*)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s"'`=<>]+)))?/g;
|
|
@@ -2398,7 +2407,7 @@ var openTag = (stack, name, attrs) => {
|
|
|
2398
2407
|
// src/transforms/htmlToTiptap/pushText.ts
|
|
2399
2408
|
var pushText = (state, rawText) => {
|
|
2400
2409
|
if (!rawText || isSkipping(state.stack)) return;
|
|
2401
|
-
|
|
2410
|
+
decodeTextEntities(rawText).split("\n").forEach((segment, index) => {
|
|
2402
2411
|
if (index > 0) flushParagraph(state);
|
|
2403
2412
|
if (!segment) return;
|
|
2404
2413
|
const marks = state.stack.flatMap((entry) => entry.marks);
|
|
@@ -2670,11 +2679,11 @@ var isMonetizeV1 = isWidgetV1(WidgetType.ui_extension_ad);
|
|
|
2670
2679
|
var HTML_TAG_RE2 = /<[a-zA-Z]/;
|
|
2671
2680
|
var containsHtml = (text2) => HTML_TAG_RE2.test(text2);
|
|
2672
2681
|
var isObject = (x) => x !== null && typeof x === "object" && !Array.isArray(x);
|
|
2673
|
-
var
|
|
2674
|
-
if (typeof value !== "string") return value;
|
|
2682
|
+
var normalizeTextValue = (value, options = {}) => {
|
|
2675
2683
|
const tokenized = normalizeTokens(value);
|
|
2676
|
-
return containsHtml(tokenized) ? htmlToTiptap(tokenized) : tokenized;
|
|
2684
|
+
return containsHtml(tokenized) || options.defaultTextStyle ? htmlToTiptap(tokenized, options) : decodeTextEntities(tokenized);
|
|
2677
2685
|
};
|
|
2686
|
+
var normalizeLangValue = (value) => typeof value === "string" ? normalizeTextValue(value) : value;
|
|
2678
2687
|
var normalizeTextContent = (node) => {
|
|
2679
2688
|
if (Array.isArray(node)) return node.map(normalizeTextContent);
|
|
2680
2689
|
if (!isObject(node)) return node;
|
|
@@ -3942,6 +3951,10 @@ var label = (text2) => ({
|
|
|
3942
3951
|
sectionType: SectionType.text
|
|
3943
3952
|
});
|
|
3944
3953
|
var text = (content) => ({ content: { en: content }, sectionType: SectionType.text });
|
|
3954
|
+
var smallText = (raw) => ({
|
|
3955
|
+
content: { en: normalizeTextValue(raw, { defaultTextStyle: { fontSize: "small" } }) },
|
|
3956
|
+
sectionType: SectionType.text
|
|
3957
|
+
});
|
|
3945
3958
|
var styled = (value, { align, bold, color, fontSize, href }) => ({
|
|
3946
3959
|
content: {
|
|
3947
3960
|
en: {
|
|
@@ -3971,8 +3984,8 @@ var shopName = (shop) => shop.replace(/\.myshopify\.com$/, "") || "store";
|
|
|
3971
3984
|
var headerSections = (input) => [
|
|
3972
3985
|
{
|
|
3973
3986
|
sections: [
|
|
3974
|
-
styled("Congratulations!", { bold: true, fontSize: "
|
|
3975
|
-
styled(`Your ${shopName(input.shop)} purchase unlocked a bonus:`, { bold: true, fontSize: "
|
|
3987
|
+
styled("Congratulations!", { bold: true, fontSize: "heading" }),
|
|
3988
|
+
styled(`Your ${shopName(input.shop)} purchase unlocked a bonus:`, { bold: true, fontSize: "heading" })
|
|
3976
3989
|
],
|
|
3977
3990
|
sectionType: SectionType.layout,
|
|
3978
3991
|
spacing: Spacing.none
|
|
@@ -3981,7 +3994,7 @@ var headerSections = (input) => [
|
|
|
3981
3994
|
];
|
|
3982
3995
|
var composeOfferCard = (offer, input) => {
|
|
3983
3996
|
const copy = {
|
|
3984
|
-
sections: [text(offer.headline),
|
|
3997
|
+
sections: [text(offer.headline), smallText(offer.description)],
|
|
3985
3998
|
sectionType: SectionType.layout,
|
|
3986
3999
|
spacing: Spacing.tight
|
|
3987
4000
|
};
|
|
@@ -1 +1,19 @@
|
|
|
1
|
-
export
|
|
1
|
+
export type DecodeEntitiesOptions = {
|
|
2
|
+
/**
|
|
3
|
+
* Leave every entity that would decode to `<` or `>` (named, decimal or hex, any case) as its
|
|
4
|
+
* literal source text. Decided on the DECODED character, not the spelling, so `<`, `<`
|
|
5
|
+
* and `<` are one rule — there is no second list of angle spellings to keep in sync.
|
|
6
|
+
*/
|
|
7
|
+
keepAngles?: boolean;
|
|
8
|
+
};
|
|
9
|
+
export declare const decodeEntities: (input?: string, { keepAngles }?: DecodeEntitiesOptions) => string;
|
|
10
|
+
/**
|
|
11
|
+
* The entity decode for DISPLAY text — every text run and plain-string content value the CAB
|
|
12
|
+
* pipeline produces. Fully decodes ordinary entities (`&` → `&`, `5 < 10` → `5 < 10`), but
|
|
13
|
+
* when the fully-decoded result is tag-shaped (`<b>` → `<b>`) it re-decodes holding the
|
|
14
|
+
* angle entities, because `CABTextSection.content` carries a `NO_HTML` refine that rejects
|
|
15
|
+
* tag-shaped text and would otherwise drop the whole section — silent content loss, which is worse
|
|
16
|
+
* than showing the escaped literal. Uses the refine's own `isHTML` predicate so guard and gate can't
|
|
17
|
+
* drift. Single-pass by construction: a double-escaped `&lt;` resolves to literal `<` and stops.
|
|
18
|
+
*/
|
|
19
|
+
export declare const decodeTextEntities: (input?: string) => string;
|
|
@@ -1837,12 +1837,21 @@ var NAMED_ENTITIES = {
|
|
|
1837
1837
|
rsquo: "\u2019",
|
|
1838
1838
|
trade: "\u2122"
|
|
1839
1839
|
};
|
|
1840
|
-
var decodeEntities = (input = "") => input.replace(/&(#x[\da-f]+|#\d+|[a-z][a-z\d]*);/gi, (match, code) => {
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1840
|
+
var decodeEntities = (input = "", { keepAngles = false } = {}) => input.replace(/&(#x[\da-f]+|#\d+|[a-z][a-z\d]*);/gi, (match, code) => {
|
|
1841
|
+
let decoded;
|
|
1842
|
+
if (code[0] !== "#") {
|
|
1843
|
+
decoded = NAMED_ENTITIES[code.toLowerCase()] ?? match;
|
|
1844
|
+
} else {
|
|
1845
|
+
const isHex = /^#x/i.test(code);
|
|
1846
|
+
const cp = parseInt(code.slice(isHex ? 2 : 1), isHex ? 16 : 10);
|
|
1847
|
+
decoded = Number.isInteger(cp) && cp >= 0 && cp <= 1114111 ? String.fromCodePoint(cp) : match;
|
|
1848
|
+
}
|
|
1849
|
+
return keepAngles && (decoded === "<" || decoded === ">") ? match : decoded;
|
|
1845
1850
|
});
|
|
1851
|
+
var decodeTextEntities = (input = "") => {
|
|
1852
|
+
const decoded = decodeEntities(input);
|
|
1853
|
+
return isHTML(decoded) ? decodeEntities(input, { keepAngles: true }) : decoded;
|
|
1854
|
+
};
|
|
1846
1855
|
|
|
1847
1856
|
// src/transforms/htmlToTiptap/parseAttribs.ts
|
|
1848
1857
|
var ATTRIB_RE = /([a-zA-Z_:][\w:.-]*)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s"'`=<>]+)))?/g;
|
|
@@ -1897,7 +1906,7 @@ var openTag = (stack, name, attrs) => {
|
|
|
1897
1906
|
// src/transforms/htmlToTiptap/pushText.ts
|
|
1898
1907
|
var pushText = (state, rawText) => {
|
|
1899
1908
|
if (!rawText || isSkipping(state.stack)) return;
|
|
1900
|
-
|
|
1909
|
+
decodeTextEntities(rawText).split("\n").forEach((segment, index) => {
|
|
1901
1910
|
if (index > 0) flushParagraph(state);
|
|
1902
1911
|
if (!segment) return;
|
|
1903
1912
|
const marks = state.stack.flatMap((entry) => entry.marks);
|
|
@@ -2169,11 +2178,11 @@ var isMonetizeV1 = isWidgetV1(WidgetType.ui_extension_ad);
|
|
|
2169
2178
|
var HTML_TAG_RE2 = /<[a-zA-Z]/;
|
|
2170
2179
|
var containsHtml = (text) => HTML_TAG_RE2.test(text);
|
|
2171
2180
|
var isObject = (x) => x !== null && typeof x === "object" && !Array.isArray(x);
|
|
2172
|
-
var
|
|
2173
|
-
if (typeof value !== "string") return value;
|
|
2181
|
+
var normalizeTextValue = (value, options = {}) => {
|
|
2174
2182
|
const tokenized = normalizeTokens(value);
|
|
2175
|
-
return containsHtml(tokenized) ? htmlToTiptap(tokenized) : tokenized;
|
|
2183
|
+
return containsHtml(tokenized) || options.defaultTextStyle ? htmlToTiptap(tokenized, options) : decodeTextEntities(tokenized);
|
|
2176
2184
|
};
|
|
2185
|
+
var normalizeLangValue = (value) => typeof value === "string" ? normalizeTextValue(value) : value;
|
|
2177
2186
|
var normalizeTextContent = (node) => {
|
|
2178
2187
|
if (Array.isArray(node)) return node.map(normalizeTextContent);
|
|
2179
2188
|
if (!isObject(node)) return node;
|
|
@@ -1780,12 +1780,21 @@ var NAMED_ENTITIES = {
|
|
|
1780
1780
|
rsquo: "\u2019",
|
|
1781
1781
|
trade: "\u2122"
|
|
1782
1782
|
};
|
|
1783
|
-
var decodeEntities = (input = "") => input.replace(/&(#x[\da-f]+|#\d+|[a-z][a-z\d]*);/gi, (match, code) => {
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1783
|
+
var decodeEntities = (input = "", { keepAngles = false } = {}) => input.replace(/&(#x[\da-f]+|#\d+|[a-z][a-z\d]*);/gi, (match, code) => {
|
|
1784
|
+
let decoded;
|
|
1785
|
+
if (code[0] !== "#") {
|
|
1786
|
+
decoded = NAMED_ENTITIES[code.toLowerCase()] ?? match;
|
|
1787
|
+
} else {
|
|
1788
|
+
const isHex = /^#x/i.test(code);
|
|
1789
|
+
const cp = parseInt(code.slice(isHex ? 2 : 1), isHex ? 16 : 10);
|
|
1790
|
+
decoded = Number.isInteger(cp) && cp >= 0 && cp <= 1114111 ? String.fromCodePoint(cp) : match;
|
|
1791
|
+
}
|
|
1792
|
+
return keepAngles && (decoded === "<" || decoded === ">") ? match : decoded;
|
|
1788
1793
|
});
|
|
1794
|
+
var decodeTextEntities = (input = "") => {
|
|
1795
|
+
const decoded = decodeEntities(input);
|
|
1796
|
+
return isHTML(decoded) ? decodeEntities(input, { keepAngles: true }) : decoded;
|
|
1797
|
+
};
|
|
1789
1798
|
|
|
1790
1799
|
// src/transforms/htmlToTiptap/parseAttribs.ts
|
|
1791
1800
|
var ATTRIB_RE = /([a-zA-Z_:][\w:.-]*)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s"'`=<>]+)))?/g;
|
|
@@ -1840,7 +1849,7 @@ var openTag = (stack, name, attrs) => {
|
|
|
1840
1849
|
// src/transforms/htmlToTiptap/pushText.ts
|
|
1841
1850
|
var pushText = (state, rawText) => {
|
|
1842
1851
|
if (!rawText || isSkipping(state.stack)) return;
|
|
1843
|
-
|
|
1852
|
+
decodeTextEntities(rawText).split("\n").forEach((segment, index) => {
|
|
1844
1853
|
if (index > 0) flushParagraph(state);
|
|
1845
1854
|
if (!segment) return;
|
|
1846
1855
|
const marks = state.stack.flatMap((entry) => entry.marks);
|
|
@@ -2112,11 +2121,11 @@ var isMonetizeV1 = isWidgetV1(WidgetType.ui_extension_ad);
|
|
|
2112
2121
|
var HTML_TAG_RE2 = /<[a-zA-Z]/;
|
|
2113
2122
|
var containsHtml = (text) => HTML_TAG_RE2.test(text);
|
|
2114
2123
|
var isObject = (x) => x !== null && typeof x === "object" && !Array.isArray(x);
|
|
2115
|
-
var
|
|
2116
|
-
if (typeof value !== "string") return value;
|
|
2124
|
+
var normalizeTextValue = (value, options = {}) => {
|
|
2117
2125
|
const tokenized = normalizeTokens(value);
|
|
2118
|
-
return containsHtml(tokenized) ? htmlToTiptap(tokenized) : tokenized;
|
|
2126
|
+
return containsHtml(tokenized) || options.defaultTextStyle ? htmlToTiptap(tokenized, options) : decodeTextEntities(tokenized);
|
|
2119
2127
|
};
|
|
2128
|
+
var normalizeLangValue = (value) => typeof value === "string" ? normalizeTextValue(value) : value;
|
|
2120
2129
|
var normalizeTextContent = (node) => {
|
|
2121
2130
|
if (Array.isArray(node)) return node.map(normalizeTextContent);
|
|
2122
2131
|
if (!isObject(node)) return node;
|
|
@@ -1,11 +1,38 @@
|
|
|
1
|
+
import { type TiptapDocument } from '../schema/widgets/checkout-and-beyond/text';
|
|
2
|
+
import { type HtmlToTiptapOptions } from '../transforms/htmlToTiptap/htmlToTiptap';
|
|
3
|
+
export type NormalizeTextOptions = Pick<HtmlToTiptapOptions, 'defaultTextStyle'>;
|
|
1
4
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
5
|
+
* THE text pipeline for one content value — the single path every text a CAB tree renders takes,
|
|
6
|
+
* whether it is merchant-authored, converted from a legacy widget, or third-party ad creative:
|
|
7
|
+
*
|
|
8
|
+
* 1. `{firstName}` (single brace) becomes `{{firstName}}` (canonical).
|
|
9
|
+
* 2. HTML becomes a fully-formed `TiptapDocument` (entities decoded per run by `htmlToTiptap`).
|
|
10
|
+
* 3. Plain text is entity-decoded in place and stays a string, so `Sale & Save` never renders
|
|
11
|
+
* its `&` literally and URL-bearing values (`buttonField: destinationUrl`) keep the string
|
|
12
|
+
* shape their validation expects.
|
|
13
|
+
*
|
|
14
|
+
* Both decodes run through `decodeTextEntities`, which holds tag-shaped angle entities escaped so a
|
|
15
|
+
* decode can never manufacture the text the section's `NO_HTML` refine rejects.
|
|
16
|
+
*
|
|
17
|
+
* `defaultTextStyle` is the server-side analogue of React's `defaultTextStyle` prop: the doc's runs
|
|
18
|
+
* carry that `textStyle` unless the markup set their own. A default forces plain text through the
|
|
19
|
+
* converter too, since only a doc can carry a mark.
|
|
4
20
|
*
|
|
5
|
-
* -
|
|
6
|
-
*
|
|
21
|
+
* NOT idempotent for entity-bearing strings (`&amp;` → `&` → `&`), by nature of decoding.
|
|
22
|
+
* That is safe because this runs at SERVE time on the stored original and its output is returned,
|
|
23
|
+
* never written back — rebuy-api's `/cab/*` routes are read-only and admin-nextjs never invokes the
|
|
24
|
+
* walk. Keep it that way: a save path that persisted this output would degrade one entity level per
|
|
25
|
+
* cycle. (Docs are immune — the walk leaves them untouched.)
|
|
26
|
+
*/
|
|
27
|
+
export declare const normalizeTextValue: (value: string, options?: NormalizeTextOptions) => string | TiptapDocument;
|
|
28
|
+
/**
|
|
29
|
+
* Walks an untyped CABRootSection-shaped object (post deepCamelCase, pre schema
|
|
30
|
+
* parse) and runs every `text` section's `content[lang]` string through
|
|
31
|
+
* {@link normalizeTextValue}. Already-converted Tiptap docs pass through untouched,
|
|
32
|
+
* so a caller that needed {@link normalizeTextValue}'s options can convert first
|
|
33
|
+
* and hand the result to this walk without double-conversion.
|
|
7
34
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
35
|
+
* Non-text sections only recurse into their `sections` array; Tiptap docs and
|
|
36
|
+
* other nested objects are not walked.
|
|
10
37
|
*/
|
|
11
38
|
export declare const normalizeTextContent: (node: unknown) => unknown;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rebuy/rebuy",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.11.0",
|
|
4
4
|
"description": "Shared zod schemas, legacy-to-CAB widget transforms, and server orchestrators for Rebuy's Shopify consumers (rebuy-api, admin-nextjs, rebuy-shopify-extensions)",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Rebuy, Inc.",
|