UNPKG

6.4 kBJavaScriptView Raw
1"use strict";
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6exports.createMarkupForRoot = createMarkupForRoot;
7exports.isCustomComponent = isCustomComponent;
8exports.escapeHtml = escapeHtml;
9exports.normalizeNode = normalizeNode;
10exports.convertValueToNode = convertValueToNode;
11exports.createHtmlEscapeHelper = createHtmlEscapeHelper;
12exports.createArrayHelper = createArrayHelper;
13exports.getNonChildrenInnerMarkup = getNonChildrenInnerMarkup;
14exports.quoteAttributeValueForBrowser = quoteAttributeValueForBrowser;
15
16var _parser = require("@babel/parser");
17
18var _index = require("../../values/index.js");
19
20var _utils = require("../utils.js");
21
22var _invariant = _interopRequireDefault(require("../../invariant.js"));
23
24var _domConfig = require("./dom-config.js");
25
26function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
27
28/**
29 * Copyright (c) 2017-present, Facebook, Inc.
30 * All rights reserved.
31 *
32 * This source code is licensed under the BSD-style license found in the
33 * LICENSE file in the root directory of this source tree. An additional grant
34 * of patent rights can be found in the PATENTS file in the same directory.
35 */
36// Warning: This code is experimental and might not fully work. There is no guarantee
37// that is up-to-date with the curent react-dom/server logic and there may also be
38// security holes in the string escaping because of this.
39const matchHtmlRegExp = /["'&<>]/;
40
41function createMarkupForRoot() {
42 return _domConfig.ROOT_ATTRIBUTE_NAME + '=""';
43}
44
45function isCustomComponent(realm, tagName, propsValue) {
46 if (tagName.indexOf("-") === -1) {
47 let is = (0, _utils.getProperty)(realm, propsValue, "is");
48 return is instanceof _index.StringValue;
49 }
50
51 switch (tagName) {
52 case "annotation-xml":
53 case "color-profile":
54 case "font-face":
55 case "font-face-src":
56 case "font-face-uri":
57 case "font-face-format":
58 case "font-face-name":
59 case "missing-glyph":
60 return false;
61
62 default:
63 return true;
64 }
65} // $FlowFixMe: we don't want to provides types here as we inject this function into source
66
67
68function escapeHtml(string) {
69 if (typeof string === "boolean" || typeof string === "number") {
70 return "" + string;
71 }
72
73 let str = "" + string;
74 let match = matchHtmlRegExp.exec(str);
75
76 if (!match) {
77 return str;
78 }
79
80 let escape;
81 let html = "";
82 let index = 0;
83 let lastIndex = 0;
84
85 for (index = match.index; index < str.length; index++) {
86 switch (str.charCodeAt(index)) {
87 case 34:
88 escape = "&quot;";
89 break;
90
91 case 38:
92 escape = "&amp;";
93 break;
94
95 case 39:
96 escape = "&#x27;";
97 break;
98
99 case 60:
100 escape = "&lt;";
101 break;
102
103 case 62:
104 escape = "&gt;";
105 break;
106
107 default:
108 continue;
109 }
110
111 if (lastIndex !== index) {
112 html += str.substring(lastIndex, index);
113 }
114
115 lastIndex = index + 1;
116 html += escape;
117 }
118
119 return lastIndex !== index ? html + str.substring(lastIndex, index) : html;
120}
121
122function normalizeNode(realm, reactNode) {
123 if (Array.isArray(reactNode)) {
124 let newReactNode;
125
126 for (let element of reactNode) {
127 if (typeof element === "string") {
128 if (newReactNode === undefined) {
129 newReactNode = element;
130 } else if (typeof newReactNode === "string") {
131 newReactNode += element;
132 } else {
133 let lastNode = newReactNode[newReactNode.length - 1];
134
135 if (typeof lastNode === "string") {
136 newReactNode[newReactNode.length - 1] += element;
137 } else {
138 newReactNode.push(element);
139 }
140 }
141 } else if (newReactNode === undefined) {
142 newReactNode = [element];
143 } else if (typeof newReactNode === "string") {
144 newReactNode = [newReactNode, element];
145 } else {
146 newReactNode.push(element);
147 }
148 }
149
150 (0, _invariant.default)(newReactNode !== undefined);
151 return newReactNode;
152 } else if (typeof reactNode === "string" || reactNode instanceof _index.AbstractValue) {
153 return reactNode;
154 }
155
156 (0, _invariant.default)(false, "TODO");
157}
158
159function convertValueToNode(value) {
160 if (value instanceof _index.AbstractValue) {
161 return value;
162 } else if (value instanceof _index.StringValue || value instanceof _index.NumberValue) {
163 return value.value + "";
164 }
165
166 (0, _invariant.default)(false, "TODO");
167}
168
169function createHtmlEscapeHelper(realm) {
170 let escapeHelperAst = (0, _parser.parseExpression)(escapeHtml.toString(), {
171 plugins: ["flow"]
172 });
173 let helper = new _index.ECMAScriptSourceFunctionValue(realm);
174 let body = escapeHelperAst.body;
175 body.uniqueOrderedTag = realm.functionBodyUniqueTagSeed++;
176 helper.$ECMAScriptCode = body;
177 helper.$FormalParameters = escapeHelperAst.params;
178 return helper;
179}
180
181function createArrayHelper(realm) {
182 let arrayHelper = `
183 function arrayHelper(array) {
184 let length = array.length;
185 let i = 0;
186 let str = "";
187 let item;
188
189 while (i < length) {
190 item = array[i++];
191 if (previousWasTextNode === true) {
192 str += "<!-- -->" + item;
193 } else {
194 str += item;
195 }
196 previousWasTextNode = item[0] !== "<";
197 }
198 return str;
199 }
200 `;
201 let escapeHelperAst = (0, _parser.parseExpression)(arrayHelper, {
202 plugins: ["flow"]
203 });
204 let helper = new _index.ECMAScriptSourceFunctionValue(realm);
205 let body = escapeHelperAst.body;
206 body.uniqueOrderedTag = realm.functionBodyUniqueTagSeed++;
207 helper.$ECMAScriptCode = body;
208 helper.$FormalParameters = escapeHelperAst.params;
209 return helper;
210}
211
212function getNonChildrenInnerMarkup(realm, propsValue) {
213 let innerHTML = (0, _utils.getProperty)(realm, propsValue, "dangerouslySetInnerHTML");
214
215 if (innerHTML instanceof _index.ObjectValue) {
216 let _html = (0, _utils.getProperty)(realm, innerHTML, "dangerouslySetInnerHTML");
217
218 if (_html instanceof _index.StringValue) {
219 return _html.value;
220 }
221 } else {
222 let content = (0, _utils.getProperty)(realm, propsValue, "children");
223
224 if (content instanceof _index.StringValue || content instanceof _index.NumberValue) {
225 return escapeHtml(content.value);
226 }
227 }
228
229 return null;
230}
231
232function quoteAttributeValueForBrowser(value) {
233 return '"' + escapeHtml(value) + '"';
234}
235//# sourceMappingURL=utils.js.map
\No newline at end of file