UNPKG

17.3 kBJavaScriptView Raw
1"use strict";
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6exports.getInitialProps = getInitialProps;
7exports.getInitialContext = getInitialContext;
8exports.createSimpleClassInstance = createSimpleClassInstance;
9exports.createClassInstanceForFirstRenderOnly = createClassInstanceForFirstRenderOnly;
10exports.createClassInstance = createClassInstance;
11exports.evaluateClassConstructor = evaluateClassConstructor;
12exports.applyGetDerivedStateFromProps = applyGetDerivedStateFromProps;
13
14var _realm = require("../realm.js");
15
16var _index = require("../values/index.js");
17
18var t = _interopRequireWildcard(require("@babel/types"));
19
20var _utils = require("./utils.js");
21
22var _errors = require("./errors.js");
23
24var _index2 = require("../methods/index.js");
25
26var _singletons = require("../singletons.js");
27
28var _invariant = _interopRequireDefault(require("../invariant.js"));
29
30var _traverse = _interopRequireDefault(require("@babel/traverse"));
31
32var _errors2 = require("../errors.js");
33
34var _ShapeInformation = require("../utils/ShapeInformation.js");
35
36function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
37
38function _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; } }
39
40/**
41 * Copyright (c) 2017-present, Facebook, Inc.
42 * All rights reserved.
43 *
44 * This source code is licensed under the BSD-style license found in the
45 * LICENSE file in the root directory of this source tree. An additional grant
46 * of patent rights can be found in the PATENTS file in the same directory.
47 */
48const lifecycleMethods = new Set(["componentWillUnmount", "componentDidMount", "componentWillMount", "componentDidUpdate", "componentWillUpdate", "componentDidCatch", "componentWillReceiveProps"]);
49const whitelistedProperties = new Set(["props", "context", "refs", "setState"]);
50
51function getInitialProps(realm, componentType, {
52 modelString
53}) {
54 let componentModel = modelString !== undefined ? JSON.parse(modelString) : undefined;
55
56 let shape = _ShapeInformation.ShapeInformation.createForReactComponentProps(componentModel);
57
58 let propsName = null;
59
60 if (componentType !== null) {
61 if ((0, _utils.valueIsClassComponent)(realm, componentType)) {
62 propsName = "this.props";
63 } else {
64 // otherwise it's a functional component, where the first paramater of the function is "props" (if it exists)
65 if (componentType.$FormalParameters.length > 0) {
66 let firstParam = componentType.$FormalParameters[0];
67
68 if (t.isIdentifier(firstParam)) {
69 propsName = firstParam.name;
70 }
71 }
72 }
73 }
74
75 let abstractPropsObject = _index.AbstractValue.createAbstractObject(realm, propsName || "props", shape);
76
77 (0, _invariant.default)(abstractPropsObject instanceof _index.AbstractObjectValue);
78 (0, _utils.flagPropsWithNoPartialKeyOrRef)(realm, abstractPropsObject);
79 abstractPropsObject.makeFinal();
80 return abstractPropsObject;
81}
82
83function getInitialContext(realm, componentType) {
84 let contextName = null;
85
86 if ((0, _utils.valueIsClassComponent)(realm, componentType)) {
87 // it's a class component, so we need to check the type on for context of the component prototype
88 let superTypeParameters = componentType.$SuperTypeParameters;
89 contextName = "this.context";
90
91 if (superTypeParameters !== undefined) {
92 throw new _errors.ExpectedBailOut("context on class components not yet supported");
93 }
94 } else {
95 // otherwise it's a functional component, where the second paramater of the function is "context" (if it exists)
96 if (componentType.$FormalParameters.length > 1) {
97 let secondParam = componentType.$FormalParameters[1];
98
99 if (t.isIdentifier(secondParam)) {
100 contextName = secondParam.name;
101 }
102 }
103 }
104
105 let value = _index.AbstractValue.createAbstractObject(realm, contextName || "context");
106
107 return value;
108}
109
110function visitClassMethodAstForThisUsage(realm, method) {
111 let formalParameters = method.$FormalParameters;
112 let code = method.$ECMAScriptCode;
113 (0, _traverse.default)(t.file(t.program([t.expressionStatement(t.functionExpression(null, formalParameters, code))])), {
114 ThisExpression(path) {
115 let parentNode = path.parentPath.node;
116
117 if (!t.isMemberExpression(parentNode)) {
118 throw new _errors.SimpleClassBailOut(`possible leakage of independent "this" reference found`);
119 }
120 }
121
122 }, null, {});
123}
124
125function createSimpleClassInstance(realm, componentType, props, context) {
126 let componentPrototype = (0, _index2.Get)(realm, componentType, "prototype");
127 (0, _invariant.default)(componentPrototype instanceof _index.ObjectValue); // create an instance object and disable serialization as we don't want to output the internals we set below
128
129 let instance = new _index.ObjectValue(realm, componentPrototype, "this", true);
130 let allowedPropertyAccess = new Set(["props", "context"]);
131
132 for (let [name] of componentPrototype.properties) {
133 if (lifecycleMethods.has(name)) {
134 // this error will result in the simple class falling back to a complex class
135 throw new _errors.SimpleClassBailOut("lifecycle methods are not supported on simple classes");
136 } else if (name !== "constructor") {
137 allowedPropertyAccess.add(name);
138 let method = (0, _index2.Get)(realm, componentPrototype, name);
139
140 if (method instanceof _index.ECMAScriptSourceFunctionValue) {
141 visitClassMethodAstForThisUsage(realm, method);
142 }
143
144 _singletons.Properties.Set(realm, instance, name, method, true);
145 }
146 } // assign props
147
148
149 _singletons.Properties.Set(realm, instance, "props", props, true); // assign context
150
151
152 _singletons.Properties.Set(realm, instance, "context", context, true); // as this object is simple, we want to check if any access to anything other than
153 // "this.props" or "this.context" or methods on the class occur
154
155
156 let $GetOwnProperty = instance.$GetOwnProperty;
157
158 instance.$GetOwnProperty = P => {
159 if (!allowedPropertyAccess.has(P)) {
160 // this error will result in the simple class falling back to a complex class
161 throw new _errors.SimpleClassBailOut("access to basic class instance properties is not supported on simple classes");
162 }
163
164 return $GetOwnProperty.call(instance, P);
165 }; // enable serialization to support simple instance variables properties
166
167
168 instance.refuseSerialization = false; // return the instance
169
170 return instance;
171}
172
173function deeplyApplyInstancePrototypeProperties(realm, instance, componentPrototype, classMetadata) {
174 let {
175 instanceProperties,
176 instanceSymbols
177 } = classMetadata;
178 let proto = componentPrototype.$Prototype;
179
180 if (proto instanceof _index.ObjectValue && proto !== realm.intrinsics.ObjectPrototype) {
181 deeplyApplyInstancePrototypeProperties(realm, instance, proto, classMetadata);
182 }
183
184 for (let [name] of componentPrototype.properties) {
185 // ensure we don't set properties that were defined on the instance
186 if (name !== "constructor" && !instanceProperties.has(name)) {
187 _singletons.Properties.Set(realm, instance, name, (0, _index2.Get)(realm, componentPrototype, name), true);
188 }
189 }
190
191 for (let [symbol] of componentPrototype.symbols) {
192 // ensure we don't set symbols that were defined on the instance
193 if (!instanceSymbols.has(symbol)) {
194 _singletons.Properties.Set(realm, instance, symbol, (0, _index2.Get)(realm, componentPrototype, symbol), true);
195 }
196 }
197}
198
199function createClassInstanceForFirstRenderOnly(realm, componentType, props, context, evaluatedNode) {
200 let instance = (0, _utils.getValueFromFunctionCall)(realm, componentType, realm.intrinsics.undefined, [props, context], true);
201 let objectAssign = (0, _index2.Get)(realm, realm.intrinsics.Object, "assign");
202 (0, _invariant.default)(objectAssign instanceof _index.ECMAScriptFunctionValue);
203 let objectAssignCall = objectAssign.$Call;
204 (0, _invariant.default)(objectAssignCall !== undefined);
205 (0, _invariant.default)(instance instanceof _index.ObjectValue);
206 instance.refuseSerialization = true; // assign props
207
208 _singletons.Properties.Set(realm, instance, "props", props, true); // assign context
209
210
211 _singletons.Properties.Set(realm, instance, "context", context, true);
212
213 let state = (0, _index2.Get)(realm, instance, "state");
214
215 if (state instanceof _index.AbstractObjectValue || state instanceof _index.ObjectValue) {
216 state.makeFinal();
217 } // assign a mocked setState
218
219
220 let setState = new _index.NativeFunctionValue(realm, undefined, `setState`, 1, (_context, [stateToUpdate, callback]) => {
221 (0, _invariant.default)(instance instanceof _index.ObjectValue);
222 let prevState = (0, _index2.Get)(realm, instance, "state");
223 (0, _invariant.default)(prevState instanceof _index.ObjectValue);
224
225 if (stateToUpdate instanceof _index.ECMAScriptSourceFunctionValue && stateToUpdate.$Call) {
226 stateToUpdate = stateToUpdate.$Call(instance, [prevState]);
227 }
228
229 if (stateToUpdate instanceof _index.ObjectValue) {
230 let newState = new _index.ObjectValue(realm, realm.intrinsics.ObjectPrototype);
231 objectAssignCall(realm.intrinsics.undefined, [newState, prevState]);
232 newState.makeFinal();
233
234 for (let [key, binding] of stateToUpdate.properties) {
235 if (binding && binding.descriptor && binding.descriptor.enumerable) {
236 let value = (0, _utils.getProperty)(realm, stateToUpdate, key);
237 (0, _utils.hardModifyReactObjectPropertyBinding)(realm, newState, key, value);
238 }
239 }
240
241 _singletons.Properties.Set(realm, instance, "state", newState, true);
242 }
243
244 if (callback instanceof _index.ECMAScriptSourceFunctionValue && callback.$Call) {
245 callback.$Call(instance, []);
246 }
247
248 return realm.intrinsics.undefined;
249 });
250 setState.intrinsicName = "(function() {})";
251
252 _singletons.Properties.Set(realm, instance, "setState", setState, true);
253
254 instance.refuseSerialization = false;
255 return instance;
256}
257
258function createClassInstance(realm, componentType, props, context, classMetadata) {
259 let componentPrototype = (0, _index2.Get)(realm, componentType, "prototype");
260 (0, _invariant.default)(componentPrototype instanceof _index.ObjectValue); // create an instance object and disable serialization as we don't want to output the internals we set below
261
262 let instance = new _index.ObjectValue(realm, componentPrototype, "this", true);
263 deeplyApplyInstancePrototypeProperties(realm, instance, componentPrototype, classMetadata); // assign refs
264
265 _singletons.Properties.Set(realm, instance, "refs", _index.AbstractValue.createAbstractObject(realm, "this.refs"), true); // assign props
266
267
268 _singletons.Properties.Set(realm, instance, "props", props, true); // assign context
269
270
271 _singletons.Properties.Set(realm, instance, "context", context, true); // enable serialization to support simple instance variables properties
272
273
274 instance.refuseSerialization = false; // return the instance in an abstract object
275
276 let value = _index.AbstractValue.createAbstractObject(realm, "this", instance);
277
278 (0, _invariant.default)(value instanceof _index.AbstractObjectValue);
279 return value;
280}
281
282function evaluateClassConstructor(realm, constructorFunc, props, context) {
283 let instanceProperties = new Set();
284 let instanceSymbols = new Set();
285 realm.evaluatePure(() => realm.evaluateForEffects(() => {
286 let instance = (0, _index2.Construct)(realm, constructorFunc, [props, context]);
287 (0, _invariant.default)(instance instanceof _index.ObjectValue);
288
289 for (let [propertyName] of instance.properties) {
290 if (!whitelistedProperties.has(propertyName)) {
291 instanceProperties.add(propertyName);
292 }
293 }
294
295 for (let [symbol] of instance.symbols) {
296 instanceSymbols.add(symbol);
297 }
298
299 return instance;
300 },
301 /*state*/
302 null, `react component constructor: ${constructorFunc.getName()}`),
303 /*reportSideEffectFunc*/
304 null);
305 return {
306 instanceProperties,
307 instanceSymbols
308 };
309}
310
311function applyGetDerivedStateFromProps(realm, getDerivedStateFromProps, instance, props) {
312 let prevState = (0, _index2.Get)(realm, instance, "state");
313 let getDerivedStateFromPropsCall = getDerivedStateFromProps.$Call;
314 (0, _invariant.default)(getDerivedStateFromPropsCall !== undefined);
315 let partialState = getDerivedStateFromPropsCall(realm.intrinsics.null, [props, prevState]);
316
317 const deriveState = state => {
318 let objectAssign = (0, _index2.Get)(realm, realm.intrinsics.Object, "assign");
319 (0, _invariant.default)(objectAssign instanceof _index.ECMAScriptFunctionValue);
320 let objectAssignCall = objectAssign.$Call;
321 (0, _invariant.default)(objectAssignCall !== undefined);
322
323 if (state instanceof _index.AbstractValue && !(state instanceof _index.AbstractObjectValue)) {
324 const kind = state.kind;
325
326 if (kind === "conditional") {
327 let condition = state.args[0];
328 let a = deriveState(state.args[1]);
329 let b = deriveState(state.args[2]);
330 (0, _invariant.default)(condition instanceof _index.AbstractValue);
331
332 if (a === null && b === null) {
333 return null;
334 } else if (a === null) {
335 (0, _invariant.default)(b instanceof _index.Value);
336 return _index.AbstractValue.createFromConditionalOp(realm, condition, realm.intrinsics.false, b);
337 } else if (b === null) {
338 (0, _invariant.default)(a instanceof _index.Value);
339 return _index.AbstractValue.createFromConditionalOp(realm, condition, a, realm.intrinsics.false);
340 } else {
341 (0, _invariant.default)(a instanceof _index.Value);
342 (0, _invariant.default)(b instanceof _index.Value);
343 return _index.AbstractValue.createFromConditionalOp(realm, condition, a, b);
344 }
345 } else if (kind === "||" || kind === "&&") {
346 let a = deriveState(state.args[0]);
347 let b = deriveState(state.args[1]);
348
349 if (b === null) {
350 (0, _invariant.default)(a instanceof _index.Value);
351 return _index.AbstractValue.createFromLogicalOp(realm, kind, a, realm.intrinsics.false);
352 } else {
353 (0, _invariant.default)(a instanceof _index.Value);
354 (0, _invariant.default)(b instanceof _index.Value);
355 return _index.AbstractValue.createFromLogicalOp(realm, kind, a, b);
356 }
357 } else {
358 (0, _invariant.default)(state.args !== undefined, "TODO: unknown abstract value passed to deriveState"); // as the value is completely abstract, we need to add a bunch of
359 // operations to be emitted to ensure we do the right thing at runtime
360
361 let a = _index.AbstractValue.createFromBinaryOp(realm, "!==", state, realm.intrinsics.null);
362
363 let b = _index.AbstractValue.createFromBinaryOp(realm, "!==", state, realm.intrinsics.undefined);
364
365 let c = _index.AbstractValue.createFromLogicalOp(realm, "&&", a, b);
366
367 (0, _invariant.default)(c instanceof _index.AbstractValue);
368 let newState = new _index.ObjectValue(realm, realm.intrinsics.ObjectPrototype);
369 let preludeGenerator = realm.preludeGenerator;
370 (0, _invariant.default)(preludeGenerator !== undefined); // we cannot use the standard Object.assign as partial state
371 // is not simple. however, given getDerivedStateFromProps is
372 // meant to be pure, we can assume that there are no getters on
373 // the partial abstract state
374
375 _index.AbstractValue.createTemporalObjectAssign(realm, newState, [prevState, state]);
376
377 newState.makeSimple();
378 newState.makePartial();
379 newState.makeFinal();
380
381 let conditional = _index.AbstractValue.createFromLogicalOp(realm, "&&", c, newState);
382
383 return conditional;
384 }
385 } else if (state !== realm.intrinsics.null && state !== realm.intrinsics.undefined) {
386 let newState = new _index.ObjectValue(realm, realm.intrinsics.ObjectPrototype);
387
388 try {
389 objectAssignCall(realm.intrinsics.undefined, [newState, prevState, state]);
390 } catch (e) {
391 if (realm.isInPureScope() && e instanceof _errors2.FatalError) {
392 let preludeGenerator = realm.preludeGenerator;
393 (0, _invariant.default)(preludeGenerator !== undefined);
394
395 _index.AbstractValue.createTemporalObjectAssign(realm, newState, [prevState, state]);
396
397 newState.makeSimple();
398 newState.makePartial();
399 return newState;
400 }
401
402 throw e;
403 }
404
405 newState.makeFinal();
406 return newState;
407 } else {
408 return null;
409 }
410 };
411
412 let newState = deriveState(partialState);
413
414 if (newState !== null) {
415 if (newState instanceof _index.AbstractValue) {
416 newState = _index.AbstractValue.createFromLogicalOp(realm, "||", newState, prevState);
417 }
418
419 (0, _invariant.default)(newState instanceof _index.Value);
420
421 _singletons.Properties.Set(realm, instance, "state", newState, true);
422 }
423}
424//# sourceMappingURL=components.js.map
\No newline at end of file