@teleporthq/teleport-plugin-common 0.43.22 → 0.43.30
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/__tests__/node-handlers/node-to-jsx/index.ts +139 -2
- package/__tests__/utils/style-utils.ts +59 -0
- package/dist/cjs/node-handlers/node-to-jsx/index.d.ts.map +1 -1
- package/dist/cjs/node-handlers/node-to-jsx/index.js +84 -30
- package/dist/cjs/node-handlers/node-to-jsx/index.js.map +1 -1
- package/dist/cjs/tsconfig.tsbuildinfo +1 -1
- package/dist/cjs/utils/style-utils.d.ts.map +1 -1
- package/dist/cjs/utils/style-utils.js +29 -3
- package/dist/cjs/utils/style-utils.js.map +1 -1
- package/dist/esm/node-handlers/node-to-jsx/index.d.ts.map +1 -1
- package/dist/esm/node-handlers/node-to-jsx/index.js +84 -30
- package/dist/esm/node-handlers/node-to-jsx/index.js.map +1 -1
- package/dist/esm/tsconfig.tsbuildinfo +1 -1
- package/dist/esm/utils/style-utils.d.ts.map +1 -1
- package/dist/esm/utils/style-utils.js +29 -3
- package/dist/esm/utils/style-utils.js.map +1 -1
- package/package.json +2 -2
- package/src/node-handlers/node-to-jsx/index.ts +97 -43
- package/src/utils/style-utils.ts +29 -3
|
@@ -2,12 +2,12 @@ import * as types from '@babel/types'
|
|
|
2
2
|
import componentUIDLSample from '../../../../../examples/test-samples/component-sample.json'
|
|
3
3
|
import generateJSXSyntax from '../../../src/node-handlers/node-to-jsx'
|
|
4
4
|
|
|
5
|
-
import { slotNode, elementNode, staticNode } from '@teleporthq/teleport-uidl-builders'
|
|
5
|
+
import { slotNode, elementNode, staticNode, dynamicNode } from '@teleporthq/teleport-uidl-builders'
|
|
6
6
|
import {
|
|
7
7
|
JSXGenerationParams,
|
|
8
8
|
JSXGenerationOptions,
|
|
9
9
|
} from '../../../src/node-handlers/node-to-jsx/types'
|
|
10
|
-
import { ComponentUIDL } from '@teleporthq/teleport-types'
|
|
10
|
+
import { ComponentUIDL, UIDLNode } from '@teleporthq/teleport-types'
|
|
11
11
|
|
|
12
12
|
const uidl = componentUIDLSample as ComponentUIDL
|
|
13
13
|
|
|
@@ -110,6 +110,73 @@ describe('generateJSXSyntax', () => {
|
|
|
110
110
|
})
|
|
111
111
|
})
|
|
112
112
|
|
|
113
|
+
describe('markdown-node with dynamic/expr children (CMS rich text)', () => {
|
|
114
|
+
const buildParams = (): JSXGenerationParams => ({
|
|
115
|
+
dependencies: {},
|
|
116
|
+
propDefinitions: {},
|
|
117
|
+
stateDefinitions: {},
|
|
118
|
+
globalStateDefinitions: {},
|
|
119
|
+
nodesLookup: {},
|
|
120
|
+
windowImports: {},
|
|
121
|
+
localeReferences: [],
|
|
122
|
+
globalReferences: [],
|
|
123
|
+
globalStateReferences: [],
|
|
124
|
+
hoistedConstants: [],
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
// Asserts the element is a <Markdown>{<expr> || ''}</Markdown> tag from markdown-to-jsx,
|
|
128
|
+
// which renders both markdown syntax and embedded HTML.
|
|
129
|
+
const expectMarkdownTag = (result: types.JSXElement, localParams: JSXGenerationParams) => {
|
|
130
|
+
expect((result.openingElement.name as types.JSXIdentifier).name).toBe('Markdown')
|
|
131
|
+
|
|
132
|
+
const container = result.children[0] as types.JSXExpressionContainer
|
|
133
|
+
expect(container.type).toBe('JSXExpressionContainer')
|
|
134
|
+
// dynamic content is guarded with `<expr> || ''` so a nullish value renders empty
|
|
135
|
+
expect((container.expression as types.LogicalExpression).operator).toBe('||')
|
|
136
|
+
|
|
137
|
+
expect(localParams.dependencies.Markdown).toEqual({
|
|
138
|
+
type: 'package',
|
|
139
|
+
path: 'markdown-to-jsx',
|
|
140
|
+
version: '7.7.12',
|
|
141
|
+
})
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
it('renders an expr child through the markdown-to-jsx <Markdown> component', () => {
|
|
145
|
+
const localParams = buildParams()
|
|
146
|
+
const node = elementNode('markdown-node', {}, [
|
|
147
|
+
{ type: 'expr', content: 'props.cmsRichtext' } as UIDLNode,
|
|
148
|
+
])
|
|
149
|
+
|
|
150
|
+
const result = generateJSXSyntax(node, localParams, options) as types.JSXElement
|
|
151
|
+
|
|
152
|
+
expectMarkdownTag(result, localParams)
|
|
153
|
+
})
|
|
154
|
+
|
|
155
|
+
it('renders a dynamic child through the markdown-to-jsx <Markdown> component', () => {
|
|
156
|
+
const localParams = buildParams()
|
|
157
|
+
const node = elementNode('markdown-node', {}, [dynamicNode('prop', 'cmsRichtext')])
|
|
158
|
+
|
|
159
|
+
const result = generateJSXSyntax(node, localParams, options) as types.JSXElement
|
|
160
|
+
|
|
161
|
+
expectMarkdownTag(result, localParams)
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
it('leaves a non-markdown div with an expr child as a plain value', () => {
|
|
165
|
+
const localParams = buildParams()
|
|
166
|
+
const node = elementNode('container', {}, [
|
|
167
|
+
{ type: 'expr', content: 'props.cmsRichtext' } as UIDLNode,
|
|
168
|
+
])
|
|
169
|
+
|
|
170
|
+
const result = generateJSXSyntax(node, localParams, options) as types.JSXElement
|
|
171
|
+
|
|
172
|
+
// generic expression handling wraps in a typeof/JSON.stringify guard, no markdown render
|
|
173
|
+
const container = result.children[0] as types.JSXExpressionContainer
|
|
174
|
+
expect(container.expression.type).toBe('ConditionalExpression')
|
|
175
|
+
expect((result.openingElement.name as types.JSXIdentifier).name).not.toBe('Markdown')
|
|
176
|
+
expect(localParams.dependencies.Markdown).toBeUndefined()
|
|
177
|
+
})
|
|
178
|
+
})
|
|
179
|
+
|
|
113
180
|
describe('renderingConditions on elements', () => {
|
|
114
181
|
it('wraps the element with a logical `&&` when renderingConditions are set', () => {
|
|
115
182
|
const ownerContainer = elementNode('container', {}, [])
|
|
@@ -182,6 +249,76 @@ describe('generateJSXSyntax', () => {
|
|
|
182
249
|
})
|
|
183
250
|
})
|
|
184
251
|
|
|
252
|
+
describe('controlled <textarea> must not render children (React SSR contract)', () => {
|
|
253
|
+
const buildParams = (): JSXGenerationParams => ({
|
|
254
|
+
dependencies: {},
|
|
255
|
+
propDefinitions: {},
|
|
256
|
+
stateDefinitions: {},
|
|
257
|
+
globalStateDefinitions: {},
|
|
258
|
+
nodesLookup: {},
|
|
259
|
+
windowImports: {},
|
|
260
|
+
localeReferences: [],
|
|
261
|
+
globalReferences: [],
|
|
262
|
+
globalStateReferences: [],
|
|
263
|
+
hoistedConstants: [],
|
|
264
|
+
})
|
|
265
|
+
|
|
266
|
+
it('drops the children of a textarea that has a value attribute', () => {
|
|
267
|
+
// The details/entity binder can add value={{ ctx.field }} to a <textarea>
|
|
268
|
+
// while leaving its original text child in place. React's server renderer
|
|
269
|
+
// throws "If you supply value on a <textarea> you must not supply children",
|
|
270
|
+
// aborting static export — so the children must not be attached.
|
|
271
|
+
const localParams = buildParams()
|
|
272
|
+
const node = elementNode('textarea', { value: dynamicNode('prop', 'description') }, [
|
|
273
|
+
elementNode('span', {}, [dynamicNode('prop', 'description')]),
|
|
274
|
+
])
|
|
275
|
+
const result = generateJSXSyntax(node, localParams, options) as types.JSXElement
|
|
276
|
+
|
|
277
|
+
expect((result.openingElement.name as types.JSXIdentifier).name).toBe('textarea')
|
|
278
|
+
expect(result.children.length).toBe(0)
|
|
279
|
+
// The child <span> is still generated into nodesLookup so the later
|
|
280
|
+
// styled-jsx traversal doesn't fail with "missing from the template chunk".
|
|
281
|
+
expect(Object.keys(localParams.nodesLookup).length).toBeGreaterThanOrEqual(2)
|
|
282
|
+
})
|
|
283
|
+
|
|
284
|
+
it('drops the children of a textarea that has a defaultValue attribute', () => {
|
|
285
|
+
const localParams = buildParams()
|
|
286
|
+
const node = elementNode('textarea', { defaultValue: dynamicNode('prop', 'description') }, [
|
|
287
|
+
elementNode('span', {}, [staticNode('initial')]),
|
|
288
|
+
])
|
|
289
|
+
const result = generateJSXSyntax(node, localParams, options) as types.JSXElement
|
|
290
|
+
expect(result.children.length).toBe(0)
|
|
291
|
+
})
|
|
292
|
+
|
|
293
|
+
it('keeps the children of an uncontrolled textarea (no value/defaultValue)', () => {
|
|
294
|
+
const localParams = buildParams()
|
|
295
|
+
const node = elementNode('textarea', {}, [staticNode('initial content')])
|
|
296
|
+
const result = generateJSXSyntax(node, localParams, options) as types.JSXElement
|
|
297
|
+
expect(result.children.length).toBeGreaterThan(0)
|
|
298
|
+
})
|
|
299
|
+
|
|
300
|
+
it('drops the children of a named textarea controlled by the form-store binding', () => {
|
|
301
|
+
// maybeAddFormStoreFieldBinding injects value={formState['field'] ?? ''}
|
|
302
|
+
// onto named inputs inside a data-store-values-state form AFTER the UIDL
|
|
303
|
+
// attrs are processed — the textarea has NO value in its UIDL attrs but
|
|
304
|
+
// ends up controlled all the same, so its children must also be skipped.
|
|
305
|
+
const localParams = { ...buildParams(), formStoreStateName: 'formValues' }
|
|
306
|
+
const node = elementNode('textarea', { name: staticNode('description') }, [
|
|
307
|
+
staticNode('initial content'),
|
|
308
|
+
])
|
|
309
|
+
const result = generateJSXSyntax(node, localParams, options) as types.JSXElement
|
|
310
|
+
|
|
311
|
+
const hasInjectedValue = result.openingElement.attributes.some(
|
|
312
|
+
(attr) =>
|
|
313
|
+
attr.type === 'JSXAttribute' &&
|
|
314
|
+
attr.name.type === 'JSXIdentifier' &&
|
|
315
|
+
attr.name.name === 'value'
|
|
316
|
+
)
|
|
317
|
+
expect(hasInjectedValue).toBe(true)
|
|
318
|
+
expect(result.children.length).toBe(0)
|
|
319
|
+
})
|
|
320
|
+
})
|
|
321
|
+
|
|
185
322
|
describe('plan v15 Layer 4 — codegen safety net for junk attrs and corrupt values', () => {
|
|
186
323
|
// Suppress the console.warn that fires when junk attrs are dropped so
|
|
187
324
|
// the test runner output stays clean. Reset between tests.
|
|
@@ -36,6 +36,65 @@ describe('JSS Utils ', () => {
|
|
|
36
36
|
})
|
|
37
37
|
})
|
|
38
38
|
|
|
39
|
+
it('drops a value with unbalanced parentheses (truncated color-mix)', () => {
|
|
40
|
+
const styleValue: UIDLStyleDefinitions = {
|
|
41
|
+
color: {
|
|
42
|
+
type: 'static',
|
|
43
|
+
content: 'color-mix(in srgb, var(--color-surface) 50%,',
|
|
44
|
+
},
|
|
45
|
+
display: {
|
|
46
|
+
type: 'static',
|
|
47
|
+
content: 'flex',
|
|
48
|
+
},
|
|
49
|
+
}
|
|
50
|
+
// The corrupted `color` is dropped; the surrounding rule stays parseable.
|
|
51
|
+
expect(getContentOfStyleObject(styleValue)).toEqual({ display: 'flex' })
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
it('drops a value with a stray closing parenthesis', () => {
|
|
55
|
+
const styleValue: UIDLStyleDefinitions = {
|
|
56
|
+
width: {
|
|
57
|
+
type: 'static',
|
|
58
|
+
content: 'calc(100% - 10px))',
|
|
59
|
+
},
|
|
60
|
+
}
|
|
61
|
+
expect(getContentOfStyleObject(styleValue)).toEqual({})
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
it('keeps valid values with balanced nested parentheses', () => {
|
|
65
|
+
const styleValue: UIDLStyleDefinitions = {
|
|
66
|
+
color: {
|
|
67
|
+
type: 'static',
|
|
68
|
+
content: 'color-mix(in srgb, var(--color-surface) 50%, transparent)',
|
|
69
|
+
},
|
|
70
|
+
background: {
|
|
71
|
+
type: 'static',
|
|
72
|
+
content: 'linear-gradient(90deg, rgba(0,0,0,0.5), #fff)',
|
|
73
|
+
},
|
|
74
|
+
}
|
|
75
|
+
expect(getContentOfStyleObject(styleValue)).toEqual({
|
|
76
|
+
color: 'color-mix(in srgb, var(--color-surface) 50%, transparent)',
|
|
77
|
+
background: 'linear-gradient(90deg, rgba(0,0,0,0.5), #fff)',
|
|
78
|
+
})
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
it('keeps values whose parentheses/colons live inside a quoted string', () => {
|
|
82
|
+
const styleValue: UIDLStyleDefinitions = {
|
|
83
|
+
background: {
|
|
84
|
+
type: 'static',
|
|
85
|
+
content: 'url("data:image/svg+xml;utf8,<svg viewBox=\'0 0 (1)\'></svg>")',
|
|
86
|
+
},
|
|
87
|
+
fontFamily: {
|
|
88
|
+
type: 'static',
|
|
89
|
+
content: '"Foo (Bold)", sans-serif',
|
|
90
|
+
},
|
|
91
|
+
}
|
|
92
|
+
expect(getContentOfStyleObject(styleValue)).toEqual({
|
|
93
|
+
background: 'url("data:image/svg+xml;utf8,<svg viewBox=\'0 0 (1)\'></svg>")',
|
|
94
|
+
fontFamily: '"Foo (Bold)", sans-serif',
|
|
95
|
+
})
|
|
96
|
+
})
|
|
97
|
+
|
|
39
98
|
it('fails with other type than static or nested-style', () => {
|
|
40
99
|
const styleValue: UIDLStyleDefinitions = {
|
|
41
100
|
content: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/node-handlers/node-to-jsx/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AACrC,OAAO,EACL,eAAe,EAiBhB,MAAM,4BAA4B,CAAA;AAEnC,OAAO,EAA+D,SAAS,EAAE,MAAM,SAAS,CAAA;AA4fhG,QAAA,MAAM,mBAAmB,EAAE,SAAS,CAAC,eAAe,EAAE,KAAK,CAAC,UAAU,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/node-handlers/node-to-jsx/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AACrC,OAAO,EACL,eAAe,EAiBhB,MAAM,4BAA4B,CAAA;AAEnC,OAAO,EAA+D,SAAS,EAAE,MAAM,SAAS,CAAA;AA4fhG,QAAA,MAAM,mBAAmB,EAAE,SAAS,CAAC,eAAe,EAAE,KAAK,CAAC,UAAU,CA2QrE,CAAA;AAED,eAAe,mBAAmB,CAAA"}
|
|
@@ -532,11 +532,62 @@ var generateElementNode = function (node, params, jsxOptions) {
|
|
|
532
532
|
var handler = (0, ast_utils_1.parseJSExpressionAsAST)(handlerCode);
|
|
533
533
|
elementTag.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('onClick'), types.jsxExpressionContainer(handler)));
|
|
534
534
|
}
|
|
535
|
-
|
|
535
|
+
// A markdown-node can carry its rich-text content as a dynamic/expr child
|
|
536
|
+
// (e.g. CMS-bound rich text) rather than as a `raw` attribute. The raw-attribute
|
|
537
|
+
// path is handled in addAttributesToJSXTag; here we handle the children path so
|
|
538
|
+
// the content is injected as HTML (dangerouslySetInnerHTML) instead of being
|
|
539
|
+
// printed as an escaped raw value by the generic expression handler.
|
|
540
|
+
var isMarkdownNode = node.content.semanticType === 'markdown-node' || originalElementName === 'markdown-node';
|
|
541
|
+
var hasRawAttr = attrs
|
|
542
|
+
? Object.keys(attrs).some(function (attrKey) { var _a; return ((_a = attrs[attrKey]) === null || _a === void 0 ? void 0 : _a.type) === 'raw'; })
|
|
543
|
+
: false;
|
|
544
|
+
var markdownChildrenHandled = false;
|
|
545
|
+
if (isMarkdownNode && !selfClosing && !hasRawAttr && children && children.length > 0) {
|
|
546
|
+
var markdownChild = children.find(function (child) { return child.type === 'expr' || child.type === 'dynamic'; });
|
|
547
|
+
var markdownExpr = void 0;
|
|
548
|
+
if ((markdownChild === null || markdownChild === void 0 ? void 0 : markdownChild.type) === 'expr') {
|
|
549
|
+
markdownExpr = __1.ASTUtils.getExpressionFromUIDLExpressionNode(markdownChild);
|
|
550
|
+
}
|
|
551
|
+
else if ((markdownChild === null || markdownChild === void 0 ? void 0 : markdownChild.type) === 'dynamic') {
|
|
552
|
+
markdownExpr = resolveDynamicReferenceExpression(markdownChild, childParams, options);
|
|
553
|
+
}
|
|
554
|
+
if (markdownExpr) {
|
|
555
|
+
injectMarkdownExpression(elementTag, markdownExpr, '', childParams);
|
|
556
|
+
markdownChildrenHandled = true;
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
// A controlled <textarea> — one carrying a `value` (or `defaultValue`) prop —
|
|
560
|
+
// must NOT also render children. React's server renderer throws
|
|
561
|
+
// "If you supply `value` on a <textarea> you must not supply children.", which
|
|
562
|
+
// aborts static export of the whole page. The details-page / entity binder can
|
|
563
|
+
// leave the original text content in place when it adds a `value` binding to a
|
|
564
|
+
// textarea (harmless for <input>, fatal for <textarea>). We still GENERATE the
|
|
565
|
+
// children below so every UIDL node lands in `nodesLookup` (the styled-jsx pass
|
|
566
|
+
// requires it), but we do not attach them to the textarea — the value prop is
|
|
567
|
+
// the single source of truth.
|
|
568
|
+
var isTextArea = originalElementName.toLowerCase() === 'textarea' || node.content.semanticType === 'textarea';
|
|
569
|
+
// The check must run against the JSX opening element (not just UIDL attrs):
|
|
570
|
+
// maybeAddFormStoreFieldBinding injects a `value` attr onto named textareas
|
|
571
|
+
// inside a data-store-values-state form AFTER UIDL attrs are processed, and
|
|
572
|
+
// that injected binding makes the textarea controlled all the same.
|
|
573
|
+
var jsxTagHasControlledValue = elementTag.openingElement.attributes.some(function (attr) {
|
|
574
|
+
return attr.type === 'JSXAttribute' &&
|
|
575
|
+
attr.name.type === 'JSXIdentifier' &&
|
|
576
|
+
(attr.name.name === 'value' || attr.name.name === 'defaultValue');
|
|
577
|
+
});
|
|
578
|
+
var skipAttachingChildren = isTextArea &&
|
|
579
|
+
(jsxTagHasControlledValue ||
|
|
580
|
+
(!!attrs &&
|
|
581
|
+
(Object.prototype.hasOwnProperty.call(attrs, 'value') ||
|
|
582
|
+
Object.prototype.hasOwnProperty.call(attrs, 'defaultValue'))));
|
|
583
|
+
if (!markdownChildrenHandled && !selfClosing && children) {
|
|
536
584
|
// Reorder children to ensure search nodes appear before DataProvider nodes
|
|
537
585
|
var reorderedChildren = reorderChildrenForSearch(children);
|
|
538
586
|
reorderedChildren.forEach(function (child) {
|
|
539
587
|
var childTags = generateNode(child, childParams, options);
|
|
588
|
+
if (skipAttachingChildren) {
|
|
589
|
+
return;
|
|
590
|
+
}
|
|
540
591
|
childTags.forEach(function (childTag) {
|
|
541
592
|
if (typeof childTag === 'string') {
|
|
542
593
|
(0, ast_utils_1.addChildJSXText)(elementTag, childTag);
|
|
@@ -1249,48 +1300,51 @@ var applyDynamicHtmlInjection = function (elementTag, rawValue, params, options)
|
|
|
1249
1300
|
});
|
|
1250
1301
|
};
|
|
1251
1302
|
var applyStaticMarkdownInjection = function (elementTag, rawValue, params) {
|
|
1252
|
-
|
|
1253
|
-
elementTag.openingElement.name.name = 'div';
|
|
1254
|
-
elementTag.openingElement.selfClosing = true;
|
|
1255
|
-
elementTag.closingElement = null;
|
|
1256
|
-
elementTag.children = [];
|
|
1257
|
-
elementTag.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('dangerouslySetInnerHTML'), types.jsxExpressionContainer(types.objectExpression([
|
|
1258
|
-
types.objectProperty(types.identifier('__html'), types.stringLiteral(content)),
|
|
1259
|
-
]))));
|
|
1260
|
-
cleanupMarkdownMappingDependencies(params);
|
|
1303
|
+
injectMarkdownExpression(elementTag, types.stringLiteral(rawValue.content || ''), '', params);
|
|
1261
1304
|
};
|
|
1262
1305
|
var applyDynamicMarkdownInjection = function (elementTag, rawValue, params, options) {
|
|
1263
1306
|
var dynamicExpr = resolveDynamicReferenceExpression(rawValue.dynamic, params, options);
|
|
1264
1307
|
var fallbackContent = rawValue.fallback || rawValue.content;
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1308
|
+
injectMarkdownExpression(elementTag, dynamicExpr, fallbackContent, params);
|
|
1309
|
+
};
|
|
1310
|
+
/**
|
|
1311
|
+
* Renders a markdown-node's rich-text content through the `markdown-to-jsx` <Markdown>
|
|
1312
|
+
* component (the React generator's mapping for markdown-node).
|
|
1313
|
+
*
|
|
1314
|
+
* markdown-to-jsx parses BOTH markdown syntax AND embedded HTML, so it renders correctly
|
|
1315
|
+
* whether the CMS field returns markdown (`# Heading`) or HTML markup (`<p>…</p>`). A raw
|
|
1316
|
+
* HTML approach (dangerouslySetInnerHTML) would ignore markdown, and a markdown-only
|
|
1317
|
+
* renderer (react-markdown) escapes HTML — markdown-to-jsx covers both at once.
|
|
1318
|
+
*
|
|
1319
|
+
* Shared by every way a markdown-node can carry its content:
|
|
1320
|
+
* - a static `raw` attribute (see applyStaticMarkdownInjection)
|
|
1321
|
+
* - a `raw` attribute holding a dynamic reference (see applyDynamicMarkdownInjection)
|
|
1322
|
+
* - a dynamic/expr child, e.g. CMS-bound rich text (see generateElementNode)
|
|
1323
|
+
*
|
|
1324
|
+
* Produces: <Markdown>{expr || fallback}</Markdown>
|
|
1325
|
+
*/
|
|
1326
|
+
var injectMarkdownExpression = function (elementTag, expression, fallbackContent, params) {
|
|
1327
|
+
// markdown-to-jsx requires a string child; guard dynamic expressions with a fallback so
|
|
1328
|
+
// a nullish CMS value renders as empty rather than throwing. Static literals need no guard.
|
|
1329
|
+
var childExpr = types.isStringLiteral(expression)
|
|
1330
|
+
? expression
|
|
1331
|
+
: types.logicalExpression('||', expression, types.stringLiteral(fallbackContent || ''));
|
|
1332
|
+
elementTag.openingElement.name.name = 'Markdown';
|
|
1270
1333
|
elementTag.openingElement.selfClosing = false;
|
|
1271
1334
|
if (!elementTag.closingElement) {
|
|
1272
|
-
elementTag.closingElement = types.jsxClosingElement(types.jsxIdentifier('
|
|
1335
|
+
elementTag.closingElement = types.jsxClosingElement(types.jsxIdentifier('Markdown'));
|
|
1273
1336
|
}
|
|
1274
1337
|
else {
|
|
1275
1338
|
;
|
|
1276
|
-
elementTag.closingElement.name.name = '
|
|
1339
|
+
elementTag.closingElement.name.name = 'Markdown';
|
|
1277
1340
|
}
|
|
1278
|
-
elementTag.children = [types.jsxExpressionContainer(
|
|
1279
|
-
|
|
1280
|
-
params.dependencies.ReactMarkdown = {
|
|
1341
|
+
elementTag.children = [types.jsxExpressionContainer(childExpr)];
|
|
1342
|
+
params.dependencies.Markdown = {
|
|
1281
1343
|
type: 'package',
|
|
1282
|
-
path: '
|
|
1283
|
-
version: '
|
|
1344
|
+
path: 'markdown-to-jsx',
|
|
1345
|
+
version: '7.7.12',
|
|
1284
1346
|
};
|
|
1285
1347
|
};
|
|
1286
|
-
var cleanupMarkdownMappingDependencies = function (params) {
|
|
1287
|
-
Object.keys(params.dependencies).forEach(function (key) {
|
|
1288
|
-
var _a, _b;
|
|
1289
|
-
if ((_b = (_a = params.dependencies[key]) === null || _a === void 0 ? void 0 : _a.path) === null || _b === void 0 ? void 0 : _b.includes('markdown-to-jsx')) {
|
|
1290
|
-
delete params.dependencies[key];
|
|
1291
|
-
}
|
|
1292
|
-
});
|
|
1293
|
-
};
|
|
1294
1348
|
/**
|
|
1295
1349
|
* Handles raw attributes on a rich-text-editor-node element.
|
|
1296
1350
|
*
|