You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					230 lines
				
				7.8 KiB
			
		
		
			
		
	
	
					230 lines
				
				7.8 KiB
			| 
											3 years ago
										 | 'use strict'; | ||
|  | 
 | ||
|  | Object.defineProperty(exports, '__esModule', { value: true }); | ||
|  | 
 | ||
|  | var helperPluginUtils = require('@babel/helper-plugin-utils'); | ||
|  | var syntaxOptionalChaining = require('@babel/plugin-syntax-optional-chaining'); | ||
|  | var core = require('@babel/core'); | ||
|  | var helperSkipTransparentExpressionWrappers = require('@babel/helper-skip-transparent-expression-wrappers'); | ||
|  | 
 | ||
|  | function willPathCastToBoolean(path) { | ||
|  |   const maybeWrapped = findOutermostTransparentParent(path); | ||
|  |   const { | ||
|  |     node, | ||
|  |     parentPath | ||
|  |   } = maybeWrapped; | ||
|  |   if (parentPath.isLogicalExpression()) { | ||
|  |     const { | ||
|  |       operator, | ||
|  |       right | ||
|  |     } = parentPath.node; | ||
|  |     if (operator === "&&" || operator === "||" || operator === "??" && node === right) { | ||
|  |       return willPathCastToBoolean(parentPath); | ||
|  |     } | ||
|  |   } | ||
|  |   if (parentPath.isSequenceExpression()) { | ||
|  |     const { | ||
|  |       expressions | ||
|  |     } = parentPath.node; | ||
|  |     if (expressions[expressions.length - 1] === node) { | ||
|  |       return willPathCastToBoolean(parentPath); | ||
|  |     } else { | ||
|  |       return true; | ||
|  |     } | ||
|  |   } | ||
|  |   return parentPath.isConditional({ | ||
|  |     test: node | ||
|  |   }) || parentPath.isUnaryExpression({ | ||
|  |     operator: "!" | ||
|  |   }) || parentPath.isLoop({ | ||
|  |     test: node | ||
|  |   }); | ||
|  | } | ||
|  | 
 | ||
|  | function findOutermostTransparentParent(path) { | ||
|  |   let maybeWrapped = path; | ||
|  |   path.findParent(p => { | ||
|  |     if (!helperSkipTransparentExpressionWrappers.isTransparentExprWrapper(p.node)) return true; | ||
|  |     maybeWrapped = p; | ||
|  |   }); | ||
|  |   return maybeWrapped; | ||
|  | } | ||
|  | 
 | ||
|  | const { | ||
|  |   ast | ||
|  | } = core.template.expression; | ||
|  | function isSimpleMemberExpression(expression) { | ||
|  |   expression = helperSkipTransparentExpressionWrappers.skipTransparentExprWrapperNodes(expression); | ||
|  |   return core.types.isIdentifier(expression) || core.types.isSuper(expression) || core.types.isMemberExpression(expression) && !expression.computed && isSimpleMemberExpression(expression.object); | ||
|  | } | ||
|  | 
 | ||
|  | function needsMemoize(path) { | ||
|  |   let optionalPath = path; | ||
|  |   const { | ||
|  |     scope | ||
|  |   } = path; | ||
|  |   while (optionalPath.isOptionalMemberExpression() || optionalPath.isOptionalCallExpression()) { | ||
|  |     const { | ||
|  |       node | ||
|  |     } = optionalPath; | ||
|  |     const childPath = helperSkipTransparentExpressionWrappers.skipTransparentExprWrappers( | ||
|  |     optionalPath.isOptionalMemberExpression() ? optionalPath.get("object") : optionalPath.get("callee")); | ||
|  |     if (node.optional) { | ||
|  |       return !scope.isStatic(childPath.node); | ||
|  |     } | ||
|  |     optionalPath = childPath; | ||
|  |   } | ||
|  | } | ||
|  | function transform(path, { | ||
|  |   pureGetters, | ||
|  |   noDocumentAll | ||
|  | }) { | ||
|  |   const { | ||
|  |     scope | ||
|  |   } = path; | ||
|  |   const maybeWrapped = findOutermostTransparentParent(path); | ||
|  |   const { | ||
|  |     parentPath | ||
|  |   } = maybeWrapped; | ||
|  |   const willReplacementCastToBoolean = willPathCastToBoolean(maybeWrapped); | ||
|  |   let isDeleteOperation = false; | ||
|  |   const parentIsCall = parentPath.isCallExpression({ | ||
|  |     callee: maybeWrapped.node | ||
|  |   }) && | ||
|  |   path.isOptionalMemberExpression(); | ||
|  |   const optionals = []; | ||
|  |   let optionalPath = path; | ||
|  |   if (scope.path.isPattern() && needsMemoize(optionalPath)) { | ||
|  |     path.replaceWith(core.template.ast`(() => ${path.node})()`); | ||
|  |     return; | ||
|  |   } | ||
|  |   while (optionalPath.isOptionalMemberExpression() || optionalPath.isOptionalCallExpression()) { | ||
|  |     const { | ||
|  |       node | ||
|  |     } = optionalPath; | ||
|  |     if (node.optional) { | ||
|  |       optionals.push(node); | ||
|  |     } | ||
|  |     if (optionalPath.isOptionalMemberExpression()) { | ||
|  |       optionalPath.node.type = "MemberExpression"; | ||
|  |       optionalPath = helperSkipTransparentExpressionWrappers.skipTransparentExprWrappers(optionalPath.get("object")); | ||
|  |     } else if (optionalPath.isOptionalCallExpression()) { | ||
|  |       optionalPath.node.type = "CallExpression"; | ||
|  |       optionalPath = helperSkipTransparentExpressionWrappers.skipTransparentExprWrappers(optionalPath.get("callee")); | ||
|  |     } | ||
|  |   } | ||
|  | 
 | ||
|  |   let replacementPath = path; | ||
|  |   if (parentPath.isUnaryExpression({ | ||
|  |     operator: "delete" | ||
|  |   })) { | ||
|  |     replacementPath = parentPath; | ||
|  |     isDeleteOperation = true; | ||
|  |   } | ||
|  |   for (let i = optionals.length - 1; i >= 0; i--) { | ||
|  |     const node = optionals[i]; | ||
|  |     const isCall = core.types.isCallExpression(node); | ||
|  |     const chainWithTypes = isCall ? | ||
|  |     node.callee : node.object; | ||
|  |     const chain = helperSkipTransparentExpressionWrappers.skipTransparentExprWrapperNodes(chainWithTypes); | ||
|  |     let ref; | ||
|  |     let check; | ||
|  |     if (isCall && core.types.isIdentifier(chain, { | ||
|  |       name: "eval" | ||
|  |     })) { | ||
|  |       check = ref = chain; | ||
|  |       node.callee = core.types.sequenceExpression([core.types.numericLiteral(0), ref]); | ||
|  |     } else if (pureGetters && isCall && isSimpleMemberExpression(chain)) { | ||
|  |       check = ref = node.callee; | ||
|  |     } else { | ||
|  |       ref = scope.maybeGenerateMemoised(chain); | ||
|  |       if (ref) { | ||
|  |         check = core.types.assignmentExpression("=", core.types.cloneNode(ref), | ||
|  |         chainWithTypes); | ||
|  |         isCall ? node.callee = ref : node.object = ref; | ||
|  |       } else { | ||
|  |         check = ref = chainWithTypes; | ||
|  |       } | ||
|  |     } | ||
|  | 
 | ||
|  |     if (isCall && core.types.isMemberExpression(chain)) { | ||
|  |       if (pureGetters && isSimpleMemberExpression(chain)) { | ||
|  |         node.callee = chainWithTypes; | ||
|  |       } else { | ||
|  |         const { | ||
|  |           object | ||
|  |         } = chain; | ||
|  |         let context; | ||
|  |         if (core.types.isSuper(object)) { | ||
|  |           context = core.types.thisExpression(); | ||
|  |         } else { | ||
|  |           const memoized = scope.maybeGenerateMemoised(object); | ||
|  |           if (memoized) { | ||
|  |             context = memoized; | ||
|  |             chain.object = core.types.assignmentExpression("=", memoized, object); | ||
|  |           } else { | ||
|  |             context = object; | ||
|  |           } | ||
|  |         } | ||
|  |         node.arguments.unshift(core.types.cloneNode(context)); | ||
|  |         node.callee = core.types.memberExpression(node.callee, core.types.identifier("call")); | ||
|  |       } | ||
|  |     } | ||
|  |     let replacement = replacementPath.node; | ||
|  |     if (i === 0 && parentIsCall) { | ||
|  |       var _baseRef; | ||
|  |       const object = helperSkipTransparentExpressionWrappers.skipTransparentExprWrapperNodes(replacement.object | ||
|  |       ); | ||
|  | 
 | ||
|  |       let baseRef; | ||
|  |       if (!pureGetters || !isSimpleMemberExpression(object)) { | ||
|  |         baseRef = scope.maybeGenerateMemoised(object); | ||
|  |         if (baseRef) { | ||
|  |           replacement.object = core.types.assignmentExpression("=", baseRef, object); | ||
|  |         } | ||
|  |       } | ||
|  |       replacement = core.types.callExpression(core.types.memberExpression(replacement, core.types.identifier("bind")), [core.types.cloneNode((_baseRef = baseRef) != null ? _baseRef : object)]); | ||
|  |     } | ||
|  |     if (willReplacementCastToBoolean) { | ||
|  |       const nonNullishCheck = noDocumentAll ? ast`${core.types.cloneNode(check)} != null` : ast`
 | ||
|  |             ${core.types.cloneNode(check)} !== null && ${core.types.cloneNode(ref)} !== void 0`;
 | ||
|  |       replacementPath.replaceWith(core.types.logicalExpression("&&", nonNullishCheck, replacement)); | ||
|  |       replacementPath = helperSkipTransparentExpressionWrappers.skipTransparentExprWrappers( | ||
|  |       replacementPath.get("right")); | ||
|  |     } else { | ||
|  |       const nullishCheck = noDocumentAll ? ast`${core.types.cloneNode(check)} == null` : ast`
 | ||
|  |             ${core.types.cloneNode(check)} === null || ${core.types.cloneNode(ref)} === void 0`;
 | ||
|  |       const returnValue = isDeleteOperation ? ast`true` : ast`void 0`; | ||
|  |       replacementPath.replaceWith(core.types.conditionalExpression(nullishCheck, returnValue, replacement)); | ||
|  |       replacementPath = helperSkipTransparentExpressionWrappers.skipTransparentExprWrappers( | ||
|  |       replacementPath.get("alternate")); | ||
|  |     } | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | var index = helperPluginUtils.declare((api, options) => { | ||
|  |   var _api$assumption, _api$assumption2; | ||
|  |   api.assertVersion(7); | ||
|  |   const { | ||
|  |     loose = false | ||
|  |   } = options; | ||
|  |   const noDocumentAll = (_api$assumption = api.assumption("noDocumentAll")) != null ? _api$assumption : loose; | ||
|  |   const pureGetters = (_api$assumption2 = api.assumption("pureGetters")) != null ? _api$assumption2 : loose; | ||
|  |   return { | ||
|  |     name: "proposal-optional-chaining", | ||
|  |     inherits: syntaxOptionalChaining.default, | ||
|  |     visitor: { | ||
|  |       "OptionalCallExpression|OptionalMemberExpression"(path) { | ||
|  |         transform(path, { | ||
|  |           noDocumentAll, | ||
|  |           pureGetters | ||
|  |         }); | ||
|  |       } | ||
|  |     } | ||
|  |   }; | ||
|  | }); | ||
|  | 
 | ||
|  | exports["default"] = index; | ||
|  | exports.transform = transform; | ||
|  | //# sourceMappingURL=index.js.map
 |