1 | "use strict";
|
2 |
|
3 | Object.defineProperty(exports, "__esModule", {
|
4 | value: true
|
5 | });
|
6 | exports.createMarkupForCustomAttribute = createMarkupForCustomAttribute;
|
7 | exports.renderToString = renderToString;
|
8 |
|
9 | var _types = require("../../serializer/types.js");
|
10 |
|
11 | var _completions = require("../../completions.js");
|
12 |
|
13 | var _index = require("../../values/index.js");
|
14 |
|
15 | var _reconcilation = require("../reconcilation.js");
|
16 |
|
17 | var _utils = require("../utils.js");
|
18 |
|
19 | var t = _interopRequireWildcard(require("@babel/types"));
|
20 |
|
21 | var _invariant = _interopRequireDefault(require("../../invariant.js"));
|
22 |
|
23 | var _utils2 = require("./utils.js");
|
24 |
|
25 | var _domConfig = require("./dom-config.js");
|
26 |
|
27 | var _hyphenateStyleName = _interopRequireDefault(require("fbjs/lib/hyphenateStyleName"));
|
28 |
|
29 | var _singletons = require("../../singletons.js");
|
30 |
|
31 | var _generator = require("../../utils/generator.js");
|
32 |
|
33 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
34 |
|
35 | function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } }
|
36 |
|
37 |
|
38 |
|
39 |
|
40 |
|
41 |
|
42 |
|
43 |
|
44 |
|
45 |
|
46 |
|
47 |
|
48 |
|
49 | function renderValueWithHelper(realm, value, helper) {
|
50 |
|
51 | let val = _index.AbstractValue.createFromBuildFunction(realm, _index.Value, [helper, value], (0, _generator.createOperationDescriptor)("REACT_SSR_RENDER_VALUE_HELPER"));
|
52 |
|
53 | (0, _invariant.default)(val instanceof _index.AbstractValue);
|
54 | return val;
|
55 | }
|
56 |
|
57 | function dangerousStyleValue(realm, name, value, isCustomProperty) {
|
58 | let isEmpty = value === realm.intrinsics.null || value === realm.intrinsics.undefined || value instanceof _index.BooleanValue || value instanceof _index.StringValue && value.value === "";
|
59 |
|
60 | if (isEmpty) {
|
61 | return "";
|
62 | }
|
63 |
|
64 | if (!isCustomProperty && value instanceof _index.NumberValue && value.value !== 0 && !(_domConfig.isUnitlessNumber.hasOwnProperty(name) && _domConfig.isUnitlessNumber[name])) {
|
65 | return value.value + "px";
|
66 | }
|
67 |
|
68 | if (value instanceof _index.StringValue || value instanceof _index.NumberValue) {
|
69 | return ("" + value.value).trim();
|
70 | } else {
|
71 | (0, _invariant.default)(false, "TODO");
|
72 | }
|
73 | }
|
74 |
|
75 | function createMarkupForCustomAttribute(realm, name, value) {
|
76 | if (!(0, _domConfig.isAttributeNameSafe)(name) || value == null) {
|
77 | return "";
|
78 | }
|
79 |
|
80 | if (value instanceof _index.StringValue || value instanceof _index.NumberValue) {
|
81 | return name + "=" + (0, _utils2.quoteAttributeValueForBrowser)(value.value + "");
|
82 | } else {
|
83 | (0, _invariant.default)(false, "TODO");
|
84 | }
|
85 | }
|
86 |
|
87 | function createMarkupForProperty(realm, name, value, htmlEscapeHelper) {
|
88 | const propertyInfo = (0, _domConfig.getPropertyInfo)(name);
|
89 |
|
90 | if (name !== "style" && (0, _domConfig.shouldIgnoreAttribute)(name, propertyInfo, false)) {
|
91 | return "";
|
92 | }
|
93 |
|
94 | if ((0, _domConfig.shouldRemoveAttribute)(realm, name, value, propertyInfo, false)) {
|
95 | return "";
|
96 | }
|
97 |
|
98 | if (propertyInfo !== null) {
|
99 | const attributeName = propertyInfo.attributeName;
|
100 | const {
|
101 | type
|
102 | } = propertyInfo;
|
103 |
|
104 | if (type === _domConfig.BOOLEAN || type === _domConfig.OVERLOADED_BOOLEAN && value === true) {
|
105 | return attributeName + '=""';
|
106 | } else if (value instanceof _index.StringValue || value instanceof _index.NumberValue) {
|
107 | return attributeName + "=" + (0, _utils2.quoteAttributeValueForBrowser)(value.value + "");
|
108 | } else if (value instanceof _index.AbstractValue) {
|
109 | return [attributeName + "=", renderValueWithHelper(realm, value, htmlEscapeHelper)];
|
110 | }
|
111 | } else if (value instanceof _index.StringValue || value instanceof _index.NumberValue) {
|
112 | return name + "=" + (0, _utils2.quoteAttributeValueForBrowser)(value.value + "");
|
113 | } else if (value instanceof _index.AbstractValue) {
|
114 | return [name + '="', renderValueWithHelper(realm, value, htmlEscapeHelper), '"'];
|
115 | }
|
116 |
|
117 | (0, _invariant.default)(false, "TODO");
|
118 | }
|
119 |
|
120 | function createMarkupForStyles(realm, styles) {
|
121 | let serialized = [];
|
122 | let delimiter = "";
|
123 |
|
124 | if (styles instanceof _index.ObjectValue && !styles.isPartialObject()) {
|
125 | for (let [styleName, binding] of styles.properties) {
|
126 | if (binding.descriptor !== undefined) {
|
127 | let isCustomProperty = styleName.indexOf("--") === 0;
|
128 | let styleValue = (0, _utils.getProperty)(realm, styles, styleName);
|
129 |
|
130 | if (styleValue !== realm.intrinsics.null && styleValue !== realm.intrinsics.undefined) {
|
131 | serialized.push(delimiter + (0, _hyphenateStyleName.default)(styleName) + ":");
|
132 | serialized.push(dangerousStyleValue(realm, styleName, styleValue, isCustomProperty));
|
133 | delimiter = ";";
|
134 | }
|
135 | }
|
136 | }
|
137 | }
|
138 |
|
139 | if (serialized.length > 0) {
|
140 | return renderReactNode(realm, serialized);
|
141 | }
|
142 |
|
143 | return realm.intrinsics.null;
|
144 | }
|
145 |
|
146 | function createOpenTagMarkup(realm, tagVerbatim, tagLowercase, propsValue, namespace, makeStaticMarkup, isRootElement, htmlEscapeHelper) {
|
147 | let ret = ["<" + tagVerbatim];
|
148 |
|
149 | if (propsValue instanceof _index.ObjectValue && !propsValue.isPartialObject()) {
|
150 | for (let [propName, binding] of propsValue.properties) {
|
151 | if (binding.descriptor !== undefined) {
|
152 | let propValue = (0, _utils.getProperty)(realm, propsValue, propName);
|
153 |
|
154 | if (propValue === realm.intrinsics.null || propValue === realm.intrinsics.undefined) {
|
155 | continue;
|
156 | }
|
157 |
|
158 | if (propName === _domConfig.STYLE) {
|
159 | propValue = createMarkupForStyles(realm, propValue);
|
160 | }
|
161 |
|
162 | let markup;
|
163 |
|
164 | if ((0, _utils2.isCustomComponent)(realm, tagLowercase, propsValue)) {
|
165 | if (!_domConfig.RESERVED_PROPS.has(propName)) {
|
166 | markup = createMarkupForCustomAttribute(realm, propName, propValue);
|
167 | }
|
168 | } else {
|
169 | markup = createMarkupForProperty(realm, propName, propValue, htmlEscapeHelper);
|
170 | }
|
171 |
|
172 | if (Array.isArray(markup)) {
|
173 | ret.push(" ", ...markup);
|
174 | } else if (typeof markup === "string" && markup !== "") {
|
175 | ret.push(" " + markup);
|
176 | } else if (markup) {
|
177 | ret.push(" ", markup);
|
178 | }
|
179 | }
|
180 | }
|
181 | } else {
|
182 | (0, _invariant.default)(false, "TODO");
|
183 | }
|
184 |
|
185 |
|
186 |
|
187 | if (makeStaticMarkup) {
|
188 | return ret;
|
189 | }
|
190 |
|
191 | if (isRootElement) {
|
192 | ret.push(" " + (0, _utils2.createMarkupForRoot)());
|
193 | }
|
194 |
|
195 | return ret;
|
196 | }
|
197 |
|
198 | function renderReactNode(realm, reactNode) {
|
199 | let normalizedNode = (0, _utils2.normalizeNode)(realm, reactNode);
|
200 |
|
201 | if (typeof normalizedNode === "string") {
|
202 | return new _index.StringValue(realm, normalizedNode);
|
203 | } else if (normalizedNode instanceof _index.AbstractValue) {
|
204 | return normalizedNode;
|
205 | }
|
206 |
|
207 | (0, _invariant.default)(Array.isArray(normalizedNode));
|
208 | let args = [];
|
209 | let quasis = [];
|
210 | let lastWasAbstract = false;
|
211 |
|
212 | for (let element of normalizedNode) {
|
213 | if (typeof element === "string") {
|
214 | lastWasAbstract = false;
|
215 | quasis.push(t.templateElement({
|
216 | raw: element,
|
217 | cooked: element
|
218 | }));
|
219 | } else {
|
220 | if (lastWasAbstract) {
|
221 | quasis.push(t.templateElement({
|
222 | raw: "",
|
223 | cooked: ""
|
224 | }));
|
225 | }
|
226 |
|
227 | lastWasAbstract = true;
|
228 | (0, _invariant.default)(element instanceof _index.Value);
|
229 | args.push(element);
|
230 | }
|
231 | }
|
232 |
|
233 | let val = _index.AbstractValue.createFromBuildFunction(realm, _index.StringValue, args, (0, _generator.createOperationDescriptor)("REACT_SSR_TEMPLATE_LITERAL", {
|
234 | quasis
|
235 | }));
|
236 |
|
237 | (0, _invariant.default)(val instanceof _index.AbstractValue);
|
238 | return val;
|
239 | }
|
240 |
|
241 | class ReactDOMServerRenderer {
|
242 | constructor(realm, makeStaticMarkup) {
|
243 | this.realm = realm;
|
244 | this.makeStaticMarkup = makeStaticMarkup;
|
245 | this.previousWasTextNode = false;
|
246 | this.htmlEscapeHelper = (0, _utils2.createHtmlEscapeHelper)(realm);
|
247 | this.arrayHelper = (0, _utils2.createArrayHelper)(realm);
|
248 | }
|
249 |
|
250 | render(value, namespace = "html", depth = 0) {
|
251 | let rootReactNode = this._renderValue(value, namespace, depth);
|
252 |
|
253 | return renderReactNode(this.realm, rootReactNode);
|
254 | }
|
255 |
|
256 | _renderText(value) {
|
257 | let text = value.value + "";
|
258 |
|
259 | if (text === "") {
|
260 | return "";
|
261 | }
|
262 |
|
263 | if (this.makeStaticMarkup) {
|
264 | return (0, _utils2.escapeHtml)(text);
|
265 | }
|
266 |
|
267 | if (this.previousWasTextNode) {
|
268 | return "<!-- -->" + (0, _utils2.escapeHtml)(text);
|
269 | }
|
270 |
|
271 | this.previousWasTextNode = true;
|
272 | return (0, _utils2.escapeHtml)(text);
|
273 | }
|
274 |
|
275 | _renderAbstractConditionalValue(condValue, consequentVal, alternateVal, namespace, depth) {
|
276 | let val = this.realm.evaluateWithAbstractConditional(condValue, () => {
|
277 | return this.realm.evaluateForEffects(() => this.render(consequentVal, namespace, depth), null, "_renderAbstractConditionalValue consequent");
|
278 | }, () => {
|
279 | return this.realm.evaluateForEffects(() => this.render(alternateVal, namespace, depth), null, "_renderAbstractConditionalValue consequent");
|
280 | });
|
281 | return (0, _utils2.convertValueToNode)(val);
|
282 | }
|
283 |
|
284 | _renderAbstractValue(value, namespace, depth) {
|
285 | if (value.kind === "conditional") {
|
286 | let [condValue, consequentVal, alternateVal] = value.args;
|
287 | (0, _invariant.default)(condValue instanceof _index.AbstractValue);
|
288 | return this._renderAbstractConditionalValue(condValue, consequentVal, alternateVal, namespace, depth);
|
289 | } else {
|
290 | return renderValueWithHelper(this.realm, value, this.htmlEscapeHelper);
|
291 | }
|
292 | }
|
293 |
|
294 | _renderArrayValue(value, namespace, depth) {
|
295 | if (_index.ArrayValue.isIntrinsicAndHasWidenedNumericProperty(value)) {
|
296 | let arrayHint = this.realm.react.arrayHints.get(value);
|
297 |
|
298 | if (arrayHint !== undefined) {
|
299 | return renderValueWithHelper(this.realm, value, this.arrayHelper);
|
300 | }
|
301 | }
|
302 |
|
303 | let elements = [];
|
304 | (0, _utils.forEachArrayValue)(this.realm, value, elementValue => {
|
305 | let renderedElement = this._renderValue(elementValue, namespace, depth);
|
306 |
|
307 | if (Array.isArray(renderedElement)) {
|
308 | elements.push(...renderedElement);
|
309 | } else {
|
310 | elements.push(renderedElement);
|
311 | }
|
312 | });
|
313 |
|
314 | return elements;
|
315 | }
|
316 |
|
317 | _renderReactElement(reactElement, namespace, depth) {
|
318 | let typeValue = (0, _utils.getProperty)(this.realm, reactElement, "type");
|
319 | let propsValue = (0, _utils.getProperty)(this.realm, reactElement, "props");
|
320 | (0, _invariant.default)(propsValue instanceof _index.AbstractObjectValue || propsValue instanceof _index.ObjectValue);
|
321 |
|
322 | if (typeValue instanceof _index.StringValue) {
|
323 | let type = typeValue.value;
|
324 | let tag = type.toLowerCase();
|
325 |
|
326 | if (tag === "input") {
|
327 | (0, _invariant.default)(false, "TODO");
|
328 | } else if (tag === "textarea") {
|
329 | (0, _invariant.default)(false, "TODO");
|
330 | } else if (tag === "select") {
|
331 | (0, _invariant.default)(false, "TODO");
|
332 | } else if (tag === "option") {
|
333 | (0, _invariant.default)(false, "TODO");
|
334 | }
|
335 |
|
336 | let out = createOpenTagMarkup(this.realm, type, tag, propsValue, namespace, this.makeStaticMarkup, depth === 0, this.htmlEscapeHelper);
|
337 | let footer = "";
|
338 |
|
339 | if (_domConfig.omittedCloseTags.has(tag)) {
|
340 | out.push("/>");
|
341 | } else {
|
342 | out.push(">");
|
343 | footer = "</" + type + ">";
|
344 | }
|
345 |
|
346 | let innerMarkup = (0, _utils2.getNonChildrenInnerMarkup)(this.realm, propsValue);
|
347 |
|
348 | if (innerMarkup instanceof _index.StringValue) {
|
349 | if (_domConfig.newlineEatingTags[tag] && innerMarkup.value.charAt(0) === "\n") {
|
350 | out.push("\n");
|
351 | }
|
352 |
|
353 | out.push(innerMarkup.value);
|
354 | } else if (innerMarkup instanceof _index.ObjectValue) {
|
355 | (0, _invariant.default)(false, "TODO");
|
356 | } else {
|
357 | this.previousWasTextNode = false;
|
358 | let childrenValue = (0, _utils.getProperty)(this.realm, propsValue, "children");
|
359 |
|
360 | let childrenOut = this._renderValue(childrenValue, namespace, depth + 1);
|
361 |
|
362 | if (Array.isArray(childrenOut)) {
|
363 | out.push(...childrenOut);
|
364 | } else {
|
365 | out.push(childrenOut);
|
366 | }
|
367 | }
|
368 |
|
369 | out.push(footer);
|
370 | this.previousWasTextNode = false;
|
371 | return out;
|
372 | } else if (typeValue instanceof _index.SymbolValue && typeValue === (0, _utils.getReactSymbol)("react.fragment", this.realm)) {
|
373 | let childrenValue = (0, _utils.getProperty)(this.realm, propsValue, "children");
|
374 |
|
375 | let childrenOut = this._renderValue(childrenValue, namespace, depth + 1);
|
376 |
|
377 | let out = [];
|
378 |
|
379 | if (Array.isArray(childrenOut)) {
|
380 | out.push(...childrenOut);
|
381 | } else {
|
382 | out.push(childrenOut);
|
383 | }
|
384 |
|
385 | this.previousWasTextNode = false;
|
386 | return out;
|
387 | } else {
|
388 | (0, _invariant.default)(false, "TODO");
|
389 | }
|
390 | }
|
391 |
|
392 | _renderValue(value, namespace, depth) {
|
393 | if (value instanceof _index.StringValue || value instanceof _index.NumberValue) {
|
394 | return this._renderText(value);
|
395 | } else if (value instanceof _index.ObjectValue && (0, _utils.isReactElement)(value)) {
|
396 | return this._renderReactElement(value, namespace, depth);
|
397 | } else if (value instanceof _index.AbstractValue) {
|
398 | return this._renderAbstractValue(value, namespace, depth);
|
399 | } else if (value instanceof _index.ArrayValue) {
|
400 | return this._renderArrayValue(value, namespace, depth);
|
401 | } else if (value instanceof _index.BooleanValue || value instanceof _index.UndefinedValue || value instanceof _index.NullValue) {
|
402 | return "";
|
403 | }
|
404 |
|
405 | (0, _invariant.default)(false, "TODO");
|
406 | }
|
407 |
|
408 | }
|
409 |
|
410 | function handleNestedOptimizedFunctions(realm, reconciler, staticMarkup) {
|
411 | for (let _ref of reconciler.nestedOptimizedClosures) {
|
412 | let {
|
413 | func,
|
414 | evaluatedNode,
|
415 | componentType,
|
416 | context
|
417 | } = _ref;
|
418 |
|
419 | if (reconciler.hasEvaluatedNestedClosure(func)) {
|
420 | continue;
|
421 | }
|
422 |
|
423 | if (func instanceof _index.ECMAScriptSourceFunctionValue && reconciler.hasEvaluatedRootNode(func, evaluatedNode)) {
|
424 | continue;
|
425 | }
|
426 |
|
427 | let closureEffects = reconciler.resolveNestedOptimizedClosure(func, [], componentType, context, evaluatedNode);
|
428 | let closureEffectsRenderedToString = realm.evaluateForEffectsWithPriorEffects([closureEffects], () => {
|
429 | let serverRenderer = new ReactDOMServerRenderer(realm, staticMarkup);
|
430 | (0, _invariant.default)(closureEffects.result instanceof _completions.SimpleNormalCompletion);
|
431 | return serverRenderer.render(closureEffects.result.value);
|
432 | }, "handleNestedOptimizedFunctions");
|
433 | realm.react.optimizedNestedClosuresToWrite.push({
|
434 | effects: closureEffectsRenderedToString,
|
435 | func
|
436 | });
|
437 | }
|
438 | }
|
439 |
|
440 | function renderToString(realm, reactElement, staticMarkup) {
|
441 | let reactStatistics = new _types.ReactStatistics();
|
442 | let reconciler = new _reconcilation.Reconciler(realm, {
|
443 | firstRenderOnly: true,
|
444 | isRoot: true,
|
445 | modelString: undefined
|
446 | }, reactStatistics);
|
447 | let typeValue = (0, _utils.getProperty)(realm, reactElement, "type");
|
448 | let propsValue = (0, _utils.getProperty)(realm, reactElement, "props");
|
449 | let evaluatedRootNode = (0, _utils.createReactEvaluatedNode)("ROOT", (0, _utils.getComponentName)(realm, typeValue));
|
450 | (0, _invariant.default)(typeValue instanceof _index.ECMAScriptSourceFunctionValue);
|
451 |
|
452 | if (propsValue instanceof _index.AbstractValue && !(propsValue instanceof _index.AbstractObjectValue)) {
|
453 | propsValue = _singletons.To.ToObject(realm, propsValue);
|
454 | }
|
455 |
|
456 | (0, _invariant.default)(propsValue instanceof _index.ObjectValue || propsValue instanceof _index.AbstractObjectValue);
|
457 | let effects = reconciler.resolveReactComponentTree(typeValue, propsValue, null, evaluatedRootNode);
|
458 | (0, _invariant.default)(realm.generator);
|
459 |
|
460 |
|
461 | realm.generator.emitStatement([], (0, _generator.createOperationDescriptor)("REACT_SSR_REGEX_CONSTANT"));
|
462 | (0, _invariant.default)(realm.generator);
|
463 | realm.generator.emitStatement([], (0, _generator.createOperationDescriptor)("REACT_SSR_PREV_TEXT_NODE"));
|
464 | (0, _invariant.default)(effects);
|
465 | realm.applyEffects(effects);
|
466 | (0, _invariant.default)(effects.result instanceof _completions.SimpleNormalCompletion);
|
467 | let serverRenderer = new ReactDOMServerRenderer(realm, staticMarkup);
|
468 | let renderValue = serverRenderer.render(effects.result.value);
|
469 | handleNestedOptimizedFunctions(realm, reconciler, staticMarkup);
|
470 | return renderValue;
|
471 | }
|
472 |
|
\ | No newline at end of file |