Merge pull request #6492 from loganfsmyth/better-template

Make babel-template nicer in a bunch of ways
This commit is contained in:
Logan Smyth 2017-10-18 14:14:14 -07:00 committed by GitHub
commit 97a217db30
30 changed files with 1556 additions and 860 deletions

View File

@ -1486,245 +1486,261 @@ declare module "babel-types" {
declare function tSTypeParameterInstantiation(params: any): BabelNodeTSTypeParameterInstantiation;
declare function tSTypeParameterDeclaration(params: any): BabelNodeTSTypeParameterDeclaration;
declare function tSTypeParameter(constraint?: ?BabelNodeTSType, _default?: ?BabelNodeTSType, name?: string): BabelNodeTSTypeParameter;
declare function isArrayExpression(node: Object, opts?: Object): boolean;
declare function isAssignmentExpression(node: Object, opts?: Object): boolean;
declare function isBinaryExpression(node: Object, opts?: Object): boolean;
declare function isDirective(node: Object, opts?: Object): boolean;
declare function isDirectiveLiteral(node: Object, opts?: Object): boolean;
declare function isBlockStatement(node: Object, opts?: Object): boolean;
declare function isBreakStatement(node: Object, opts?: Object): boolean;
declare function isCallExpression(node: Object, opts?: Object): boolean;
declare function isCatchClause(node: Object, opts?: Object): boolean;
declare function isConditionalExpression(node: Object, opts?: Object): boolean;
declare function isContinueStatement(node: Object, opts?: Object): boolean;
declare function isDebuggerStatement(node: Object, opts?: Object): boolean;
declare function isDoWhileStatement(node: Object, opts?: Object): boolean;
declare function isEmptyStatement(node: Object, opts?: Object): boolean;
declare function isExpressionStatement(node: Object, opts?: Object): boolean;
declare function isFile(node: Object, opts?: Object): boolean;
declare function isForInStatement(node: Object, opts?: Object): boolean;
declare function isForStatement(node: Object, opts?: Object): boolean;
declare function isFunctionDeclaration(node: Object, opts?: Object): boolean;
declare function isFunctionExpression(node: Object, opts?: Object): boolean;
declare function isIdentifier(node: Object, opts?: Object): boolean;
declare function isIfStatement(node: Object, opts?: Object): boolean;
declare function isLabeledStatement(node: Object, opts?: Object): boolean;
declare function isStringLiteral(node: Object, opts?: Object): boolean;
declare function isNumericLiteral(node: Object, opts?: Object): boolean;
declare function isNullLiteral(node: Object, opts?: Object): boolean;
declare function isBooleanLiteral(node: Object, opts?: Object): boolean;
declare function isRegExpLiteral(node: Object, opts?: Object): boolean;
declare function isLogicalExpression(node: Object, opts?: Object): boolean;
declare function isMemberExpression(node: Object, opts?: Object): boolean;
declare function isNewExpression(node: Object, opts?: Object): boolean;
declare function isProgram(node: Object, opts?: Object): boolean;
declare function isObjectExpression(node: Object, opts?: Object): boolean;
declare function isObjectMethod(node: Object, opts?: Object): boolean;
declare function isObjectProperty(node: Object, opts?: Object): boolean;
declare function isRestElement(node: Object, opts?: Object): boolean;
declare function isReturnStatement(node: Object, opts?: Object): boolean;
declare function isSequenceExpression(node: Object, opts?: Object): boolean;
declare function isSwitchCase(node: Object, opts?: Object): boolean;
declare function isSwitchStatement(node: Object, opts?: Object): boolean;
declare function isThisExpression(node: Object, opts?: Object): boolean;
declare function isThrowStatement(node: Object, opts?: Object): boolean;
declare function isTryStatement(node: Object, opts?: Object): boolean;
declare function isUnaryExpression(node: Object, opts?: Object): boolean;
declare function isUpdateExpression(node: Object, opts?: Object): boolean;
declare function isVariableDeclaration(node: Object, opts?: Object): boolean;
declare function isVariableDeclarator(node: Object, opts?: Object): boolean;
declare function isWhileStatement(node: Object, opts?: Object): boolean;
declare function isWithStatement(node: Object, opts?: Object): boolean;
declare function isAssignmentPattern(node: Object, opts?: Object): boolean;
declare function isArrayPattern(node: Object, opts?: Object): boolean;
declare function isArrowFunctionExpression(node: Object, opts?: Object): boolean;
declare function isClassBody(node: Object, opts?: Object): boolean;
declare function isClassDeclaration(node: Object, opts?: Object): boolean;
declare function isClassExpression(node: Object, opts?: Object): boolean;
declare function isExportAllDeclaration(node: Object, opts?: Object): boolean;
declare function isExportDefaultDeclaration(node: Object, opts?: Object): boolean;
declare function isExportNamedDeclaration(node: Object, opts?: Object): boolean;
declare function isExportSpecifier(node: Object, opts?: Object): boolean;
declare function isForOfStatement(node: Object, opts?: Object): boolean;
declare function isImportDeclaration(node: Object, opts?: Object): boolean;
declare function isImportDefaultSpecifier(node: Object, opts?: Object): boolean;
declare function isImportNamespaceSpecifier(node: Object, opts?: Object): boolean;
declare function isImportSpecifier(node: Object, opts?: Object): boolean;
declare function isMetaProperty(node: Object, opts?: Object): boolean;
declare function isClassMethod(node: Object, opts?: Object): boolean;
declare function isObjectPattern(node: Object, opts?: Object): boolean;
declare function isSpreadElement(node: Object, opts?: Object): boolean;
declare function isSuper(node: Object, opts?: Object): boolean;
declare function isTaggedTemplateExpression(node: Object, opts?: Object): boolean;
declare function isTemplateElement(node: Object, opts?: Object): boolean;
declare function isTemplateLiteral(node: Object, opts?: Object): boolean;
declare function isYieldExpression(node: Object, opts?: Object): boolean;
declare function isAnyTypeAnnotation(node: Object, opts?: Object): boolean;
declare function isArrayTypeAnnotation(node: Object, opts?: Object): boolean;
declare function isBooleanTypeAnnotation(node: Object, opts?: Object): boolean;
declare function isBooleanLiteralTypeAnnotation(node: Object, opts?: Object): boolean;
declare function isNullLiteralTypeAnnotation(node: Object, opts?: Object): boolean;
declare function isClassImplements(node: Object, opts?: Object): boolean;
declare function isDeclareClass(node: Object, opts?: Object): boolean;
declare function isDeclareFunction(node: Object, opts?: Object): boolean;
declare function isDeclareInterface(node: Object, opts?: Object): boolean;
declare function isDeclareModule(node: Object, opts?: Object): boolean;
declare function isDeclareModuleExports(node: Object, opts?: Object): boolean;
declare function isDeclareTypeAlias(node: Object, opts?: Object): boolean;
declare function isDeclareOpaqueType(node: Object, opts?: Object): boolean;
declare function isDeclareVariable(node: Object, opts?: Object): boolean;
declare function isDeclareExportDeclaration(node: Object, opts?: Object): boolean;
declare function isDeclareExportAllDeclaration(node: Object, opts?: Object): boolean;
declare function isDeclaredPredicate(node: Object, opts?: Object): boolean;
declare function isExistsTypeAnnotation(node: Object, opts?: Object): boolean;
declare function isFunctionTypeAnnotation(node: Object, opts?: Object): boolean;
declare function isFunctionTypeParam(node: Object, opts?: Object): boolean;
declare function isGenericTypeAnnotation(node: Object, opts?: Object): boolean;
declare function isInferredPredicate(node: Object, opts?: Object): boolean;
declare function isInterfaceExtends(node: Object, opts?: Object): boolean;
declare function isInterfaceDeclaration(node: Object, opts?: Object): boolean;
declare function isIntersectionTypeAnnotation(node: Object, opts?: Object): boolean;
declare function isMixedTypeAnnotation(node: Object, opts?: Object): boolean;
declare function isEmptyTypeAnnotation(node: Object, opts?: Object): boolean;
declare function isNullableTypeAnnotation(node: Object, opts?: Object): boolean;
declare function isNumberLiteralTypeAnnotation(node: Object, opts?: Object): boolean;
declare function isNumberTypeAnnotation(node: Object, opts?: Object): boolean;
declare function isObjectTypeAnnotation(node: Object, opts?: Object): boolean;
declare function isObjectTypeCallProperty(node: Object, opts?: Object): boolean;
declare function isObjectTypeIndexer(node: Object, opts?: Object): boolean;
declare function isObjectTypeProperty(node: Object, opts?: Object): boolean;
declare function isObjectTypeSpreadProperty(node: Object, opts?: Object): boolean;
declare function isOpaqueType(node: Object, opts?: Object): boolean;
declare function isQualifiedTypeIdentifier(node: Object, opts?: Object): boolean;
declare function isStringLiteralTypeAnnotation(node: Object, opts?: Object): boolean;
declare function isStringTypeAnnotation(node: Object, opts?: Object): boolean;
declare function isThisTypeAnnotation(node: Object, opts?: Object): boolean;
declare function isTupleTypeAnnotation(node: Object, opts?: Object): boolean;
declare function isTypeofTypeAnnotation(node: Object, opts?: Object): boolean;
declare function isTypeAlias(node: Object, opts?: Object): boolean;
declare function isTypeAnnotation(node: Object, opts?: Object): boolean;
declare function isTypeCastExpression(node: Object, opts?: Object): boolean;
declare function isTypeParameter(node: Object, opts?: Object): boolean;
declare function isTypeParameterDeclaration(node: Object, opts?: Object): boolean;
declare function isTypeParameterInstantiation(node: Object, opts?: Object): boolean;
declare function isUnionTypeAnnotation(node: Object, opts?: Object): boolean;
declare function isVoidTypeAnnotation(node: Object, opts?: Object): boolean;
declare function isJSXAttribute(node: Object, opts?: Object): boolean;
declare function isJSXClosingElement(node: Object, opts?: Object): boolean;
declare function isJSXElement(node: Object, opts?: Object): boolean;
declare function isJSXEmptyExpression(node: Object, opts?: Object): boolean;
declare function isJSXExpressionContainer(node: Object, opts?: Object): boolean;
declare function isJSXSpreadChild(node: Object, opts?: Object): boolean;
declare function isJSXIdentifier(node: Object, opts?: Object): boolean;
declare function isJSXMemberExpression(node: Object, opts?: Object): boolean;
declare function isJSXNamespacedName(node: Object, opts?: Object): boolean;
declare function isJSXOpeningElement(node: Object, opts?: Object): boolean;
declare function isJSXSpreadAttribute(node: Object, opts?: Object): boolean;
declare function isJSXText(node: Object, opts?: Object): boolean;
declare function isNoop(node: Object, opts?: Object): boolean;
declare function isParenthesizedExpression(node: Object, opts?: Object): boolean;
declare function isAwaitExpression(node: Object, opts?: Object): boolean;
declare function isBindExpression(node: Object, opts?: Object): boolean;
declare function isClassProperty(node: Object, opts?: Object): boolean;
declare function isImport(node: Object, opts?: Object): boolean;
declare function isDecorator(node: Object, opts?: Object): boolean;
declare function isDoExpression(node: Object, opts?: Object): boolean;
declare function isExportDefaultSpecifier(node: Object, opts?: Object): boolean;
declare function isExportNamespaceSpecifier(node: Object, opts?: Object): boolean;
declare function isTSParameterProperty(node: Object, opts?: Object): boolean;
declare function isTSDeclareFunction(node: Object, opts?: Object): boolean;
declare function isTSDeclareMethod(node: Object, opts?: Object): boolean;
declare function isTSQualifiedName(node: Object, opts?: Object): boolean;
declare function isTSCallSignatureDeclaration(node: Object, opts?: Object): boolean;
declare function isTSConstructSignatureDeclaration(node: Object, opts?: Object): boolean;
declare function isTSPropertySignature(node: Object, opts?: Object): boolean;
declare function isTSMethodSignature(node: Object, opts?: Object): boolean;
declare function isTSIndexSignature(node: Object, opts?: Object): boolean;
declare function isTSAnyKeyword(node: Object, opts?: Object): boolean;
declare function isTSNumberKeyword(node: Object, opts?: Object): boolean;
declare function isTSObjectKeyword(node: Object, opts?: Object): boolean;
declare function isTSBooleanKeyword(node: Object, opts?: Object): boolean;
declare function isTSStringKeyword(node: Object, opts?: Object): boolean;
declare function isTSSymbolKeyword(node: Object, opts?: Object): boolean;
declare function isTSVoidKeyword(node: Object, opts?: Object): boolean;
declare function isTSUndefinedKeyword(node: Object, opts?: Object): boolean;
declare function isTSNullKeyword(node: Object, opts?: Object): boolean;
declare function isTSNeverKeyword(node: Object, opts?: Object): boolean;
declare function isTSThisType(node: Object, opts?: Object): boolean;
declare function isTSFunctionType(node: Object, opts?: Object): boolean;
declare function isTSConstructorType(node: Object, opts?: Object): boolean;
declare function isTSTypeReference(node: Object, opts?: Object): boolean;
declare function isTSTypePredicate(node: Object, opts?: Object): boolean;
declare function isTSTypeQuery(node: Object, opts?: Object): boolean;
declare function isTSTypeLiteral(node: Object, opts?: Object): boolean;
declare function isTSArrayType(node: Object, opts?: Object): boolean;
declare function isTSTupleType(node: Object, opts?: Object): boolean;
declare function isTSUnionType(node: Object, opts?: Object): boolean;
declare function isTSIntersectionType(node: Object, opts?: Object): boolean;
declare function isTSParenthesizedType(node: Object, opts?: Object): boolean;
declare function isTSTypeOperator(node: Object, opts?: Object): boolean;
declare function isTSIndexedAccessType(node: Object, opts?: Object): boolean;
declare function isTSMappedType(node: Object, opts?: Object): boolean;
declare function isTSLiteralType(node: Object, opts?: Object): boolean;
declare function isTSExpressionWithTypeArguments(node: Object, opts?: Object): boolean;
declare function isTSInterfaceDeclaration(node: Object, opts?: Object): boolean;
declare function isTSInterfaceBody(node: Object, opts?: Object): boolean;
declare function isTSTypeAliasDeclaration(node: Object, opts?: Object): boolean;
declare function isTSAsExpression(node: Object, opts?: Object): boolean;
declare function isTSTypeAssertion(node: Object, opts?: Object): boolean;
declare function isTSEnumDeclaration(node: Object, opts?: Object): boolean;
declare function isTSEnumMember(node: Object, opts?: Object): boolean;
declare function isTSModuleDeclaration(node: Object, opts?: Object): boolean;
declare function isTSModuleBlock(node: Object, opts?: Object): boolean;
declare function isTSImportEqualsDeclaration(node: Object, opts?: Object): boolean;
declare function isTSExternalModuleReference(node: Object, opts?: Object): boolean;
declare function isTSNonNullExpression(node: Object, opts?: Object): boolean;
declare function isTSExportAssignment(node: Object, opts?: Object): boolean;
declare function isTSNamespaceExportDeclaration(node: Object, opts?: Object): boolean;
declare function isTSTypeAnnotation(node: Object, opts?: Object): boolean;
declare function isTSTypeParameterInstantiation(node: Object, opts?: Object): boolean;
declare function isTSTypeParameterDeclaration(node: Object, opts?: Object): boolean;
declare function isTSTypeParameter(node: Object, opts?: Object): boolean;
declare function isExpression(node: Object, opts?: Object): boolean;
declare function isBinary(node: Object, opts?: Object): boolean;
declare function isScopable(node: Object, opts?: Object): boolean;
declare function isBlockParent(node: Object, opts?: Object): boolean;
declare function isBlock(node: Object, opts?: Object): boolean;
declare function isStatement(node: Object, opts?: Object): boolean;
declare function isTerminatorless(node: Object, opts?: Object): boolean;
declare function isCompletionStatement(node: Object, opts?: Object): boolean;
declare function isConditional(node: Object, opts?: Object): boolean;
declare function isLoop(node: Object, opts?: Object): boolean;
declare function isWhile(node: Object, opts?: Object): boolean;
declare function isExpressionWrapper(node: Object, opts?: Object): boolean;
declare function isFor(node: Object, opts?: Object): boolean;
declare function isForXStatement(node: Object, opts?: Object): boolean;
declare function isFunction(node: Object, opts?: Object): boolean;
declare function isFunctionParent(node: Object, opts?: Object): boolean;
declare function isPureish(node: Object, opts?: Object): boolean;
declare function isDeclaration(node: Object, opts?: Object): boolean;
declare function isPatternLike(node: Object, opts?: Object): boolean;
declare function isLVal(node: Object, opts?: Object): boolean;
declare function isTSEntityName(node: Object, opts?: Object): boolean;
declare function isLiteral(node: Object, opts?: Object): boolean;
declare function isImmutable(node: Object, opts?: Object): boolean;
declare function isUserWhitespacable(node: Object, opts?: Object): boolean;
declare function isMethod(node: Object, opts?: Object): boolean;
declare function isObjectMember(node: Object, opts?: Object): boolean;
declare function isProperty(node: Object, opts?: Object): boolean;
declare function isUnaryLike(node: Object, opts?: Object): boolean;
declare function isPattern(node: Object, opts?: Object): boolean;
declare function isClass(node: Object, opts?: Object): boolean;
declare function isModuleDeclaration(node: Object, opts?: Object): boolean;
declare function isExportDeclaration(node: Object, opts?: Object): boolean;
declare function isModuleSpecifier(node: Object, opts?: Object): boolean;
declare function isFlow(node: Object, opts?: Object): boolean;
declare function isFlowBaseAnnotation(node: Object, opts?: Object): boolean;
declare function isFlowDeclaration(node: Object, opts?: Object): boolean;
declare function isFlowPredicate(node: Object, opts?: Object): boolean;
declare function isJSX(node: Object, opts?: Object): boolean;
declare function isTSTypeElement(node: Object, opts?: Object): boolean;
declare function isTSType(node: Object, opts?: Object): boolean;
declare function isNumberLiteral(node: Object, opts?: Object): boolean;
declare function isRegexLiteral(node: Object, opts?: Object): boolean;
declare function isArrayExpression(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeArrayExpression)
declare function isAssignmentExpression(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeAssignmentExpression)
declare function isBinaryExpression(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeBinaryExpression)
declare function isDirective(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeDirective)
declare function isDirectiveLiteral(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeDirectiveLiteral)
declare function isBlockStatement(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeBlockStatement)
declare function isBreakStatement(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeBreakStatement)
declare function isCallExpression(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeCallExpression)
declare function isCatchClause(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeCatchClause)
declare function isConditionalExpression(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeConditionalExpression)
declare function isContinueStatement(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeContinueStatement)
declare function isDebuggerStatement(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeDebuggerStatement)
declare function isDoWhileStatement(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeDoWhileStatement)
declare function isEmptyStatement(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeEmptyStatement)
declare function isExpressionStatement(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeExpressionStatement)
declare function isFile(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeFile)
declare function isForInStatement(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeForInStatement)
declare function isForStatement(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeForStatement)
declare function isFunctionDeclaration(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeFunctionDeclaration)
declare function isFunctionExpression(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeFunctionExpression)
declare function isIdentifier(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeIdentifier)
declare function isIfStatement(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeIfStatement)
declare function isLabeledStatement(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeLabeledStatement)
declare function isStringLiteral(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeStringLiteral)
declare function isNumericLiteral(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeNumericLiteral)
declare function isNullLiteral(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeNullLiteral)
declare function isBooleanLiteral(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeBooleanLiteral)
declare function isRegExpLiteral(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeRegExpLiteral)
declare function isLogicalExpression(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeLogicalExpression)
declare function isMemberExpression(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeMemberExpression)
declare function isNewExpression(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeNewExpression)
declare function isProgram(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeProgram)
declare function isObjectExpression(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeObjectExpression)
declare function isObjectMethod(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeObjectMethod)
declare function isObjectProperty(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeObjectProperty)
declare function isRestElement(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeRestElement)
declare function isReturnStatement(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeReturnStatement)
declare function isSequenceExpression(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeSequenceExpression)
declare function isSwitchCase(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeSwitchCase)
declare function isSwitchStatement(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeSwitchStatement)
declare function isThisExpression(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeThisExpression)
declare function isThrowStatement(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeThrowStatement)
declare function isTryStatement(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeTryStatement)
declare function isUnaryExpression(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeUnaryExpression)
declare function isUpdateExpression(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeUpdateExpression)
declare function isVariableDeclaration(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeVariableDeclaration)
declare function isVariableDeclarator(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeVariableDeclarator)
declare function isWhileStatement(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeWhileStatement)
declare function isWithStatement(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeWithStatement)
declare function isAssignmentPattern(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeAssignmentPattern)
declare function isArrayPattern(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeArrayPattern)
declare function isArrowFunctionExpression(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeArrowFunctionExpression)
declare function isClassBody(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeClassBody)
declare function isClassDeclaration(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeClassDeclaration)
declare function isClassExpression(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeClassExpression)
declare function isExportAllDeclaration(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeExportAllDeclaration)
declare function isExportDefaultDeclaration(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeExportDefaultDeclaration)
declare function isExportNamedDeclaration(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeExportNamedDeclaration)
declare function isExportSpecifier(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeExportSpecifier)
declare function isForOfStatement(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeForOfStatement)
declare function isImportDeclaration(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeImportDeclaration)
declare function isImportDefaultSpecifier(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeImportDefaultSpecifier)
declare function isImportNamespaceSpecifier(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeImportNamespaceSpecifier)
declare function isImportSpecifier(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeImportSpecifier)
declare function isMetaProperty(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeMetaProperty)
declare function isClassMethod(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeClassMethod)
declare function isObjectPattern(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeObjectPattern)
declare function isSpreadElement(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeSpreadElement)
declare function isSuper(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeSuper)
declare function isTaggedTemplateExpression(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeTaggedTemplateExpression)
declare function isTemplateElement(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeTemplateElement)
declare function isTemplateLiteral(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeTemplateLiteral)
declare function isYieldExpression(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeYieldExpression)
declare function isAnyTypeAnnotation(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeAnyTypeAnnotation)
declare function isArrayTypeAnnotation(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeArrayTypeAnnotation)
declare function isBooleanTypeAnnotation(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeBooleanTypeAnnotation)
declare function isBooleanLiteralTypeAnnotation(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeBooleanLiteralTypeAnnotation)
declare function isNullLiteralTypeAnnotation(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeNullLiteralTypeAnnotation)
declare function isClassImplements(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeClassImplements)
declare function isDeclareClass(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeDeclareClass)
declare function isDeclareFunction(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeDeclareFunction)
declare function isDeclareInterface(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeDeclareInterface)
declare function isDeclareModule(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeDeclareModule)
declare function isDeclareModuleExports(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeDeclareModuleExports)
declare function isDeclareTypeAlias(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeDeclareTypeAlias)
declare function isDeclareOpaqueType(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeDeclareOpaqueType)
declare function isDeclareVariable(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeDeclareVariable)
declare function isDeclareExportDeclaration(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeDeclareExportDeclaration)
declare function isDeclareExportAllDeclaration(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeDeclareExportAllDeclaration)
declare function isDeclaredPredicate(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeDeclaredPredicate)
declare function isExistsTypeAnnotation(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeExistsTypeAnnotation)
declare function isFunctionTypeAnnotation(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeFunctionTypeAnnotation)
declare function isFunctionTypeParam(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeFunctionTypeParam)
declare function isGenericTypeAnnotation(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeGenericTypeAnnotation)
declare function isInferredPredicate(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeInferredPredicate)
declare function isInterfaceExtends(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeInterfaceExtends)
declare function isInterfaceDeclaration(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeInterfaceDeclaration)
declare function isIntersectionTypeAnnotation(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeIntersectionTypeAnnotation)
declare function isMixedTypeAnnotation(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeMixedTypeAnnotation)
declare function isEmptyTypeAnnotation(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeEmptyTypeAnnotation)
declare function isNullableTypeAnnotation(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeNullableTypeAnnotation)
declare function isNumberLiteralTypeAnnotation(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeNumberLiteralTypeAnnotation)
declare function isNumberTypeAnnotation(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeNumberTypeAnnotation)
declare function isObjectTypeAnnotation(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeObjectTypeAnnotation)
declare function isObjectTypeCallProperty(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeObjectTypeCallProperty)
declare function isObjectTypeIndexer(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeObjectTypeIndexer)
declare function isObjectTypeProperty(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeObjectTypeProperty)
declare function isObjectTypeSpreadProperty(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeObjectTypeSpreadProperty)
declare function isOpaqueType(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeOpaqueType)
declare function isQualifiedTypeIdentifier(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeQualifiedTypeIdentifier)
declare function isStringLiteralTypeAnnotation(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeStringLiteralTypeAnnotation)
declare function isStringTypeAnnotation(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeStringTypeAnnotation)
declare function isThisTypeAnnotation(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeThisTypeAnnotation)
declare function isTupleTypeAnnotation(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeTupleTypeAnnotation)
declare function isTypeofTypeAnnotation(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeTypeofTypeAnnotation)
declare function isTypeAlias(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeTypeAlias)
declare function isTypeAnnotation(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeTypeAnnotation)
declare function isTypeCastExpression(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeTypeCastExpression)
declare function isTypeParameter(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeTypeParameter)
declare function isTypeParameterDeclaration(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeTypeParameterDeclaration)
declare function isTypeParameterInstantiation(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeTypeParameterInstantiation)
declare function isUnionTypeAnnotation(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeUnionTypeAnnotation)
declare function isVoidTypeAnnotation(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeVoidTypeAnnotation)
declare function isJSXAttribute(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeJSXAttribute)
declare function isJSXClosingElement(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeJSXClosingElement)
declare function isJSXElement(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeJSXElement)
declare function isJSXEmptyExpression(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeJSXEmptyExpression)
declare function isJSXExpressionContainer(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeJSXExpressionContainer)
declare function isJSXSpreadChild(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeJSXSpreadChild)
declare function isJSXIdentifier(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeJSXIdentifier)
declare function isJSXMemberExpression(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeJSXMemberExpression)
declare function isJSXNamespacedName(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeJSXNamespacedName)
declare function isJSXOpeningElement(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeJSXOpeningElement)
declare function isJSXSpreadAttribute(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeJSXSpreadAttribute)
declare function isJSXText(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeJSXText)
declare function isNoop(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeNoop)
declare function isParenthesizedExpression(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeParenthesizedExpression)
declare function isAwaitExpression(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeAwaitExpression)
declare function isBindExpression(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeBindExpression)
declare function isClassProperty(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeClassProperty)
declare function isImport(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeImport)
declare function isDecorator(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeDecorator)
declare function isDoExpression(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeDoExpression)
declare function isExportDefaultSpecifier(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeExportDefaultSpecifier)
declare function isExportNamespaceSpecifier(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeExportNamespaceSpecifier)
declare function isTSParameterProperty(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeTSParameterProperty)
declare function isTSDeclareFunction(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeTSDeclareFunction)
declare function isTSDeclareMethod(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeTSDeclareMethod)
declare function isTSQualifiedName(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeTSQualifiedName)
declare function isTSCallSignatureDeclaration(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeTSCallSignatureDeclaration)
declare function isTSConstructSignatureDeclaration(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeTSConstructSignatureDeclaration)
declare function isTSPropertySignature(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeTSPropertySignature)
declare function isTSMethodSignature(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeTSMethodSignature)
declare function isTSIndexSignature(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeTSIndexSignature)
declare function isTSAnyKeyword(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeTSAnyKeyword)
declare function isTSNumberKeyword(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeTSNumberKeyword)
declare function isTSObjectKeyword(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeTSObjectKeyword)
declare function isTSBooleanKeyword(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeTSBooleanKeyword)
declare function isTSStringKeyword(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeTSStringKeyword)
declare function isTSSymbolKeyword(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeTSSymbolKeyword)
declare function isTSVoidKeyword(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeTSVoidKeyword)
declare function isTSUndefinedKeyword(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeTSUndefinedKeyword)
declare function isTSNullKeyword(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeTSNullKeyword)
declare function isTSNeverKeyword(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeTSNeverKeyword)
declare function isTSThisType(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeTSThisType)
declare function isTSFunctionType(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeTSFunctionType)
declare function isTSConstructorType(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeTSConstructorType)
declare function isTSTypeReference(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeTSTypeReference)
declare function isTSTypePredicate(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeTSTypePredicate)
declare function isTSTypeQuery(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeTSTypeQuery)
declare function isTSTypeLiteral(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeTSTypeLiteral)
declare function isTSArrayType(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeTSArrayType)
declare function isTSTupleType(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeTSTupleType)
declare function isTSUnionType(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeTSUnionType)
declare function isTSIntersectionType(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeTSIntersectionType)
declare function isTSParenthesizedType(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeTSParenthesizedType)
declare function isTSTypeOperator(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeTSTypeOperator)
declare function isTSIndexedAccessType(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeTSIndexedAccessType)
declare function isTSMappedType(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeTSMappedType)
declare function isTSLiteralType(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeTSLiteralType)
declare function isTSExpressionWithTypeArguments(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeTSExpressionWithTypeArguments)
declare function isTSInterfaceDeclaration(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeTSInterfaceDeclaration)
declare function isTSInterfaceBody(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeTSInterfaceBody)
declare function isTSTypeAliasDeclaration(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeTSTypeAliasDeclaration)
declare function isTSAsExpression(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeTSAsExpression)
declare function isTSTypeAssertion(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeTSTypeAssertion)
declare function isTSEnumDeclaration(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeTSEnumDeclaration)
declare function isTSEnumMember(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeTSEnumMember)
declare function isTSModuleDeclaration(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeTSModuleDeclaration)
declare function isTSModuleBlock(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeTSModuleBlock)
declare function isTSImportEqualsDeclaration(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeTSImportEqualsDeclaration)
declare function isTSExternalModuleReference(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeTSExternalModuleReference)
declare function isTSNonNullExpression(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeTSNonNullExpression)
declare function isTSExportAssignment(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeTSExportAssignment)
declare function isTSNamespaceExportDeclaration(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeTSNamespaceExportDeclaration)
declare function isTSTypeAnnotation(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeTSTypeAnnotation)
declare function isTSTypeParameterInstantiation(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeTSTypeParameterInstantiation)
declare function isTSTypeParameterDeclaration(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeTSTypeParameterDeclaration)
declare function isTSTypeParameter(node: Object, opts?: ?Object): boolean %checks (node instanceof BabelNodeTSTypeParameter)
declare function isExpression(node: Object, opts?: ?Object): boolean
declare function isBinary(node: Object, opts?: ?Object): boolean
declare function isScopable(node: Object, opts?: ?Object): boolean
declare function isBlockParent(node: Object, opts?: ?Object): boolean
declare function isBlock(node: Object, opts?: ?Object): boolean
declare function isStatement(node: Object, opts?: ?Object): boolean
declare function isTerminatorless(node: Object, opts?: ?Object): boolean
declare function isCompletionStatement(node: Object, opts?: ?Object): boolean
declare function isConditional(node: Object, opts?: ?Object): boolean
declare function isLoop(node: Object, opts?: ?Object): boolean
declare function isWhile(node: Object, opts?: ?Object): boolean
declare function isExpressionWrapper(node: Object, opts?: ?Object): boolean
declare function isFor(node: Object, opts?: ?Object): boolean
declare function isForXStatement(node: Object, opts?: ?Object): boolean
declare function isFunction(node: Object, opts?: ?Object): boolean
declare function isFunctionParent(node: Object, opts?: ?Object): boolean
declare function isPureish(node: Object, opts?: ?Object): boolean
declare function isDeclaration(node: Object, opts?: ?Object): boolean
declare function isPatternLike(node: Object, opts?: ?Object): boolean
declare function isLVal(node: Object, opts?: ?Object): boolean
declare function isTSEntityName(node: Object, opts?: ?Object): boolean
declare function isLiteral(node: Object, opts?: ?Object): boolean
declare function isImmutable(node: Object, opts?: ?Object): boolean
declare function isUserWhitespacable(node: Object, opts?: ?Object): boolean
declare function isMethod(node: Object, opts?: ?Object): boolean
declare function isObjectMember(node: Object, opts?: ?Object): boolean
declare function isProperty(node: Object, opts?: ?Object): boolean
declare function isUnaryLike(node: Object, opts?: ?Object): boolean
declare function isPattern(node: Object, opts?: ?Object): boolean
declare function isClass(node: Object, opts?: ?Object): boolean
declare function isModuleDeclaration(node: Object, opts?: ?Object): boolean
declare function isExportDeclaration(node: Object, opts?: ?Object): boolean
declare function isModuleSpecifier(node: Object, opts?: ?Object): boolean
declare function isFlow(node: Object, opts?: ?Object): boolean
declare function isFlowBaseAnnotation(node: Object, opts?: ?Object): boolean
declare function isFlowDeclaration(node: Object, opts?: ?Object): boolean
declare function isFlowPredicate(node: Object, opts?: ?Object): boolean
declare function isJSX(node: Object, opts?: ?Object): boolean
declare function isTSTypeElement(node: Object, opts?: ?Object): boolean
declare function isTSType(node: Object, opts?: ?Object): boolean
declare function isNumberLiteral(node: Object, opts?: ?Object): boolean
declare function isRegexLiteral(node: Object, opts?: ?Object): boolean
declare function validate(n: BabelNode, key: string, value: mixed): void;
declare function clone<T>(n: T): T;
declare function cloneDeep<T>(n: T): T;
declare function removeProperties<T>(n: T, opts: ?{}): void;
declare function removePropertiesDeep<T>(n: T, opts: ?{}): T;
declare type TraversalAncestors = Array<{
node: BabelNode,
key: string,
index?: number,
}>;
declare type TraversalHandler<T> = (BabelNode, TraversalAncestors, T) => void;
declare type TraversalHandlers<T> = {
enter?: TraversalHandler<T>,
exit?: TraversalHandler<T>,
};
declare function traverse<T>(n: BabelNode, TraversalHandler<T> | TraversalHandlers<T>, state?: T): void;
}

View File

@ -102,14 +102,6 @@ export function wrapInterop(
return t.callExpression(programPath.hub.file.addHelper(helper), [expr]);
}
const buildNamespaceInit = template(`
var NAME = SOURCE;
`);
const buildReexportNamespace = template(`
EXPORTS.NAME = NAMESPACE;
`);
/**
* Create the runtime initialization statements for a given requested source.
* These will initialize all of the runtime import/export logic that
@ -127,19 +119,19 @@ export function buildNamespaceInitStatements(
// Create and assign binding to namespace object
statements.push(
buildNamespaceInit({
NAME: t.identifier(localName),
SOURCE: t.identifier(sourceMetadata.name),
template.statement`var NAME = SOURCE;`({
NAME: localName,
SOURCE: sourceMetadata.name,
}),
);
}
for (const exportName of sourceMetadata.reexportNamespace) {
// Assign export to namespace object.
statements.push(
buildReexportNamespace({
EXPORTS: t.identifier(metadata.exportName),
NAME: t.identifier(exportName),
NAMESPACE: t.identifier(sourceMetadata.name),
template.statement`EXPORTS.NAME = NAMESPACE;`({
EXPORTS: metadata.exportName,
NAME: exportName,
NAMESPACE: sourceMetadata.name,
}),
);
}
@ -153,16 +145,6 @@ export function buildNamespaceInitStatements(
return statements;
}
const moduleHeader = template(`
Object.defineProperty(EXPORTS, "__esModule", {
value: true,
})
`);
const moduleHeaderLoose = template(`
EXPORTS.__esModule = true;
`);
/**
* Build an "__esModule" header statement setting the property on a given object.
*/
@ -170,58 +152,44 @@ function buildESModuleHeader(
metadata: ModuleMetadata,
enumerable: boolean = false,
) {
if (enumerable) {
return moduleHeaderLoose({
EXPORTS: t.identifier(metadata.exportName),
});
}
return moduleHeader({
EXPORTS: t.identifier(metadata.exportName),
});
return (enumerable
? template.statement`
EXPORTS.__esModule = true;
`
: template.statement`
Object.defineProperty(EXPORTS, "__esModule", {
value: true,
});
`)({ EXPORTS: metadata.exportName });
}
const namespaceReexport = template(`
Object.keys(NAMESPACE).forEach(function(key) {
if (key === "default" || key === "__esModule") return;
VERIFY_NAME_LIST;
Object.defineProperty(EXPORTS, key, {
enumerable: true,
get: function() {
return NAMESPACE[key];
},
});
});
`);
const buildNameListCheck = template(`
if (Object.prototype.hasOwnProperty.call(EXPORTS_LIST, key)) return;
`);
/**
* Create a re-export initialization loop for a specific imported namespace.
*/
function buildNamespaceReexport(metadata, namespace) {
return namespaceReexport({
NAMESPACE: t.identifier(namespace),
EXPORTS: t.identifier(metadata.exportName),
return template.statement`
Object.keys(NAMESPACE).forEach(function(key) {
if (key === "default" || key === "__esModule") return;
VERIFY_NAME_LIST;
Object.defineProperty(EXPORTS, key, {
enumerable: true,
get: function() {
return NAMESPACE[key];
},
});
});
`({
NAMESPACE: namespace,
EXPORTS: metadata.exportName,
VERIFY_NAME_LIST: metadata.exportNameListName
? buildNameListCheck({
EXPORTS_LIST: t.identifier(metadata.exportNameListName),
})
? template`
if (Object.prototype.hasOwnProperty.call(EXPORTS_LIST, key)) return;
`({ EXPORTS_LIST: metadata.exportNameListName })
: null,
});
}
const reexportGetter = template(`
Object.defineProperty(EXPORTS, EXPORT_NAME, {
enumerable: true,
get: function() {
return NAMESPACE.IMPORT_NAME;
},
});
`);
/**
* Build a statement declaring a variable that contains all of the exported
* variable names in an object so they can easily be referenced from an
@ -289,11 +257,18 @@ function buildExportInitializationStatements(
for (const data of metadata.source.values()) {
for (const [exportName, importName] of data.reexports) {
initStatements.push(
reexportGetter({
EXPORTS: t.identifier(metadata.exportName),
EXPORT_NAME: t.stringLiteral(exportName),
NAMESPACE: t.identifier(data.name),
IMPORT_NAME: t.identifier(importName),
template`
Object.defineProperty(EXPORTS, "EXPORT_NAME", {
enumerable: true,
get: function() {
return NAMESPACE.IMPORT_NAME;
},
});
`({
EXPORTS: metadata.exportName,
EXPORT_NAME: exportName,
NAMESPACE: data.name,
IMPORT_NAME: importName,
}),
);
}
@ -315,22 +290,20 @@ function buildExportInitializationStatements(
return initStatements;
}
const initStatement = template(`
EXPORTS.NAME = VALUE;
`);
/**
* Given a set of export names, create a set of nested assignments to
* initialize them all to a given expression.
*/
function buildInitStatement(metadata, exportNames, initExpr) {
return t.expressionStatement(
exportNames.reduce((acc, exportName) => {
return initStatement({
EXPORTS: t.identifier(metadata.exportName),
NAME: t.identifier(exportName),
VALUE: acc,
}).expression;
}, initExpr),
exportNames.reduce(
(acc, exportName) =>
template.expression`EXPORTS.NAME = VALUE`({
EXPORTS: metadata.exportName,
NAME: exportName,
VALUE: acc,
}),
initExpr,
),
);
}

View File

@ -142,16 +142,12 @@ const buildBindingExportAssignmentExpression = (
}, localExpr);
};
const importThrow = template(`
(function() {
throw new Error('"' + NAME + '" is read-only.');
})();
`);
const buildImportThrow = localName => {
return importThrow({
NAME: t.stringLiteral(localName),
}).expression;
return template.expression.ast`
(function() {
throw new Error('"' + '${localName}' + '" is read-only.');
})()
`;
};
const rewriteReferencesVisitor = {

View File

@ -72,7 +72,7 @@ export default function(path, helpers) {
OBJECT: node.right,
STEP_VALUE: stepValue,
STEP_KEY: stepKey,
AWAIT: helpers.wrapAwait,
...(helpers.wrapAwait ? { AWAIT: helpers.wrapAwait } : {}),
});
// remove generator function wrapper

View File

@ -5,9 +5,9 @@ import template from "@babel/template";
const helpers = {};
export default helpers;
function defineHelper(str) {
return template(str, { sourceType: "module" });
}
// Helpers never include placeholders, so we disable placeholder pattern
// matching to allow us to use pattern-like variable names.
const defineHelper = template.program({ placeholderPattern: false });
helpers.typeof = defineHelper(`
export default function _typeof(obj) {

View File

@ -232,8 +232,7 @@ function loadHelper(name) {
if (!helpers[name]) throw new ReferenceError(`Unknown helper ${name}`);
const fn = () => {
const ast = helpers[name]();
return t.file(t.program(Array.isArray(ast) ? ast : [ast]));
return t.file(helpers[name]());
};
const metadata = getHelperMetadata(fn());

View File

@ -17,7 +17,7 @@ export default function defineHelper(
throw new Error(`The ${id} helper is already defined.`);
}
Object.defineProperty(helpers, id, {
value: template(code, { sourceType: "module" }),
value: template.program(code),
});
return id;
}

View File

@ -25,30 +25,27 @@ export default function({ types: t }, options) {
},
};
const buildObjectDefineProperty = template(`
Object.defineProperty(REF, KEY, {
configurable: true,
enumerable: true,
writable: true,
value: VALUE
});
`);
const buildClassPropertySpec = (ref, { key, value, computed }, scope) =>
buildObjectDefineProperty({
const buildClassPropertySpec = (ref, { key, value, computed }, scope) => {
return template.statement`
Object.defineProperty(REF, KEY, {
configurable: true,
enumerable: true,
writable: true,
value: VALUE
});
`({
REF: ref,
KEY: t.isIdentifier(key) && !computed ? t.stringLiteral(key.name) : key,
VALUE: value ? value : scope.buildUndefinedNode(),
VALUE: value || scope.buildUndefinedNode(),
});
};
const buildClassPropertyLoose = (ref, { key, value, computed }, scope) =>
t.expressionStatement(
t.assignmentExpression(
"=",
t.memberExpression(ref, key, computed || t.isLiteral(key)),
value ? value : scope.buildUndefinedNode(),
),
);
const buildClassPropertyLoose = (ref, { key, value, computed }, scope) => {
return template.statement`MEMBER = VALUE`({
MEMBER: t.memberExpression(ref, key, computed || t.isLiteral(key)),
VALUE: value || scope.buildUndefinedNode(),
});
};
const buildClassProperty = loose
? buildClassPropertyLoose

View File

@ -6,12 +6,6 @@ import * as defineMap from "@babel/helper-define-map";
import template from "@babel/template";
import * as t from "@babel/types";
const buildDerivedConstructor = template(`
(function () {
super(...arguments);
})
`);
const noMethodVisitor = {
"FunctionExpression|FunctionDeclaration"(path) {
path.skip();
@ -212,7 +206,11 @@ export default class ClassTransformer {
let params, body;
if (this.isDerived) {
const constructor = buildDerivedConstructor().expression;
const constructor = template.expression.ast`
(function () {
super(...arguments);
})
`;
params = constructor.params;
body = constructor.body;
} else {

View File

@ -245,7 +245,6 @@ export default function({ template, types: t }, options) {
ITERATOR_KEY: iteratorKey,
STEP_KEY: stepKey,
OBJECT: node.right,
BODY: null,
});
const isLabeledParent = t.isLabeledStatement(parent);

View File

@ -37,23 +37,16 @@ export default function({ types: t }, options) {
});
const amdArgs = [];
const commonjsArgs = [];
const importNames = [];
if (hasExports(meta)) {
amdArgs.push(t.stringLiteral("exports"));
commonjsArgs.push(t.identifier("exports"));
importNames.push(t.identifier(meta.exportName));
}
for (const [source, metadata] of meta.source) {
amdArgs.push(t.stringLiteral(source));
commonjsArgs.push(
t.callExpression(t.identifier("require"), [
t.stringLiteral(source),
]),
);
importNames.push(t.identifier(metadata.name));
if (!isSideEffectImport(metadata)) {
@ -89,7 +82,6 @@ export default function({ types: t }, options) {
MODULE_NAME: moduleName,
AMD_ARGUMENTS: t.arrayExpression(amdArgs),
COMMONJS_ARGUMENTS: commonjsArgs,
IMPORT_NAMES: importNames,
}),
])[0];

View File

@ -19,19 +19,11 @@ export default function({ types: t, template }, options) {
// Defaulting to 'true' for now. May change before 7.x major.
allowCommonJSExports = true,
} = options;
const moduleAssertion = template(`
const getAssertion = localName => template.expression.ast`
(function(){
throw new Error("The CommonJS 'module' variable is not available in ES6 modules.");
})();
`);
const exportsAssertion = template(`
(function(){
throw new Error("The CommonJS 'exports' variable is not available in ES6 modules.");
})();
`);
const getAssertion = localName =>
(localName === "module" ? moduleAssertion() : exportsAssertion())
.expression;
throw new Error("The CommonJS '" + "${localName}" + "' variable is not available in ES6 modules.");
})()
`;
const moduleExportsVisitor = {
ReferencedIdentifier(path) {

View File

@ -3,56 +3,56 @@
require("foo");
console.log(function () {
throw new Error("The CommonJS 'exports' variable is not available in ES6 modules.");
throw new Error("The CommonJS '" + "exports" + "' variable is not available in ES6 modules.");
}());
console.log(function () {
throw new Error("The CommonJS 'exports' variable is not available in ES6 modules.");
throw new Error("The CommonJS '" + "exports" + "' variable is not available in ES6 modules.");
}().prop);
exports = function () {
throw new Error("The CommonJS 'exports' variable is not available in ES6 modules.");
throw new Error("The CommonJS '" + "exports" + "' variable is not available in ES6 modules.");
}() + 1;
exports = function () {
throw new Error("The CommonJS 'exports' variable is not available in ES6 modules.");
throw new Error("The CommonJS '" + "exports" + "' variable is not available in ES6 modules.");
}() + 4;
({
exports
} = ({}, function () {
throw new Error("The CommonJS 'exports' variable is not available in ES6 modules.");
throw new Error("The CommonJS '" + "exports" + "' variable is not available in ES6 modules.");
}()));
[exports] = ([], function () {
throw new Error("The CommonJS 'exports' variable is not available in ES6 modules.");
throw new Error("The CommonJS '" + "exports" + "' variable is not available in ES6 modules.");
}());
exports = {};
(function () {
throw new Error("The CommonJS 'exports' variable is not available in ES6 modules.");
throw new Error("The CommonJS '" + "exports" + "' variable is not available in ES6 modules.");
})().prop = "";
console.log(function () {
throw new Error("The CommonJS 'module' variable is not available in ES6 modules.");
throw new Error("The CommonJS '" + "module" + "' variable is not available in ES6 modules.");
}());
console.log(function () {
throw new Error("The CommonJS 'module' variable is not available in ES6 modules.");
throw new Error("The CommonJS '" + "module" + "' variable is not available in ES6 modules.");
}().exports);
module = function () {
throw new Error("The CommonJS 'module' variable is not available in ES6 modules.");
throw new Error("The CommonJS '" + "module" + "' variable is not available in ES6 modules.");
}() + 1;
module = function () {
throw new Error("The CommonJS 'module' variable is not available in ES6 modules.");
throw new Error("The CommonJS '" + "module" + "' variable is not available in ES6 modules.");
}() + 4;
({
module
} = ({}, function () {
throw new Error("The CommonJS 'module' variable is not available in ES6 modules.");
throw new Error("The CommonJS '" + "module" + "' variable is not available in ES6 modules.");
}()));
[module] = ([], function () {
throw new Error("The CommonJS 'module' variable is not available in ES6 modules.");
throw new Error("The CommonJS '" + "module" + "' variable is not available in ES6 modules.");
}());
module = {};
(function () {
throw new Error("The CommonJS 'module' variable is not available in ES6 modules.");
throw new Error("The CommonJS '" + "module" + "' variable is not available in ES6 modules.");
})().prop = "";

View File

@ -2,11 +2,11 @@ import hoistVariables from "@babel/helper-hoist-variables";
import template from "@babel/template";
const buildTemplate = template(`
SYSTEM_REGISTER(MODULE_NAME, [SOURCES], function (EXPORT_IDENTIFIER, CONTEXT_IDENTIFIER) {
SYSTEM_REGISTER(MODULE_NAME, SOURCES, function (EXPORT_IDENTIFIER, CONTEXT_IDENTIFIER) {
"use strict";
BEFORE_BODY;
return {
setters: [SETTERS],
setters: SETTERS,
execute: function () {
BODY;
}
@ -365,8 +365,8 @@ export default function({ types: t }, options) {
),
BEFORE_BODY: beforeBody,
MODULE_NAME: moduleName,
SETTERS: setters,
SOURCES: sources,
SETTERS: t.arrayExpression(setters),
SOURCES: t.arrayExpression(sources),
BODY: path.node.body,
EXPORT_IDENTIFIER: exportIdent,
CONTEXT_IDENTIFIER: contextIdent,

View File

@ -111,7 +111,7 @@ export default function convertFunctionParams(path, loose) {
});
body.push(defNode);
} else if (firstOptionalIndex !== null) {
const defNode = buildArgumentsAccess(param.node, t.numericLiteral(i));
const defNode = buildArgumentsAccess([param.node, t.numericLiteral(i)]);
body.push(defNode);
} else if (param.isObjectPattern() || param.isArrayPattern()) {
const uid = path.scope.generateUidIdentifier("ref");

View File

@ -1,6 +1,6 @@
# @babel/template
> Generate an AST from a string template.
> Generate an AST from a string template or template literal.
In computer science, this is known as an implementation of quasiquotes.
@ -10,7 +10,7 @@ In computer science, this is known as an implementation of quasiquotes.
npm install --save-dev @babel/template
```
## Usage
## String Usage
```js
import template from "@babel/template";
@ -33,6 +33,93 @@ console.log(generate(ast).code);
const myModule = require("my-module");
```
### `.ast`
If no placeholders are in use and you just want a simple way to parse a
string into an AST, you can use the `.ast` version of the template.
```js
const ast = template.ast(`
var myModule = require("my-module");
`);
```
which will parse and return the AST directly.
## Template Literal Usage
```js
import template from "babel-template";
import generate from "babel-generator";
import * as t from "babel-types";
const fn = template`
var IMPORT_NAME = require('${"my-module"}');
`);
const ast = fn({
IMPORT_NAME: t.identifier("myModule");
});
console.log(generate(ast).code);
```
Note that placeholders can be passed directly as part of the template literal
in order to make things as readable as possible, or they can be passed into
the template function.
### `.ast`
If no placeholders are in use and you just want a simple way to parse a
string into an AST, you can use the `.ast` version of the template.
```js
const name = "my-module";
const mod = "myModule";
const ast = template.ast`
var ${mod} = require("${name}");
`;
```
which will parse and return the AST directly. Note that unlike the string-based
version mentioned earlier, since this is a template literal, it is still
valid to perform replacements using template literal replacements.
## AST results
The `babel-template` API exposes a few flexible APIs to make it as easy as
possible to create ASTs with an expected structure. Each of these also has
the `.ast` property mentioned above.
### `template`
`template` returns either a single statement, or an array of
statements, depending on the parsed result.
### `template.smart`
This is the same as the default `template` API, returning either a single
node, or an array of nodes, depending on the parsed result.
### `template.statement`
`template.statement("foo;")()` returns a single statement node, and throw
an exception if the result is anything but a single statement.
### `template.statements`
`template.statements("foo;foo;")()` returns an array of statement nodes.
### `template.expression`
`template.expression("foo")()` returns the expression node.
### `template.program`
`template.program("foo;")()` returns the `Program` node for the template.
## API
### `template(code, [opts])`
@ -48,6 +135,25 @@ some defaults of its own:
* `allowReturnOutsideFunction` is set to `true` by default.
* `allowSuperOutsideMethod` is set to `true` by default.
* `sourceType` is set to `module` by default.
##### placeholderWhitelist
Type: `Set<string>`
Default: `undefined`
A set of placeholder names to automatically accept. Items in this list do
not need to match the given placeholder pattern.
##### placeholderPattern
Type: `RegExp | false`
Default: `/^[_$A-Z0-9]+$/`
A pattern to search for when looking for Identifier and StringLiteral
nodes that should be considered placeholders.
'false' will disable placeholder searching entirely, leaving only the
'placeholderWhitelist' value to find placeholders.
##### preserveComments
@ -58,7 +164,9 @@ Set this to `true` to preserve any comments from the `code` parameter.
#### Return value
`@babel/template` returns a `function` which is invoked with an optional object
of replacements. See the usage section for an example.
By default `@babel/template` returns a `function` which is invoked with an
optional object of replacements. See the usage section for an example.
When using `.ast`, the AST will be returned directly.
[babylon]: https://github.com/babel/babylon#options

View File

@ -9,7 +9,6 @@
"main": "lib/index.js",
"dependencies": {
"@babel/code-frame": "7.0.0-beta.3",
"@babel/traverse": "7.0.0-beta.3",
"@babel/types": "7.0.0-beta.3",
"babylon": "7.0.0-beta.29",
"lodash": "^4.2.0"

View File

@ -0,0 +1,131 @@
// @flow
import {
merge,
validate,
type TemplateOpts,
type PublicOpts,
type PublicReplacements,
} from "./options";
import type { Formatter } from "./formatters";
import stringTemplate from "./string";
import literalTemplate from "./literal";
export type TemplateBuilder<T> = {
// Build a new builder, merging the given options with the previous ones.
(opts: PublicOpts): TemplateBuilder<T>,
// Building from a string produces an AST builder function by default.
(tpl: string, opts: ?PublicOpts): (?PublicReplacements) => T,
// Building from a template literal produces an AST builder function by default.
(tpl: Array<string>, ...args: Array<mixed>): (?PublicReplacements) => T,
// Allow users to explicitly create templates that produce ASTs, skipping
// the need for an intermediate function.
ast: {
(tpl: string, opts: ?PublicOpts): T,
(tpl: Array<string>, ...args: Array<mixed>): T,
},
};
// Prebuild the options that will be used when parsing a `.ast` template.
// These do not use a pattern because there is no way for users to pass in
// replacement patterns to begin with, and disabling pattern matching means
// users have more flexibility in what type of content they have in their
// template JS.
const NO_PLACEHOLDER: TemplateOpts = validate({
placeholderPattern: false,
});
export default function createTemplateBuilder<T>(
formatter: Formatter<T>,
defaultOpts?: TemplateOpts,
): TemplateBuilder<T> {
const templateFnCache = new WeakMap();
const templateAstCache = new WeakMap();
const cachedOpts = defaultOpts || validate(null);
return Object.assign(
((tpl, ...args) => {
if (typeof tpl === "string") {
if (args.length > 1) throw new Error("Unexpected extra params.");
return extendedTrace(
stringTemplate(formatter, tpl, merge(cachedOpts, validate(args[0]))),
);
} else if (Array.isArray(tpl)) {
let builder = templateFnCache.get(tpl);
if (!builder) {
builder = literalTemplate(formatter, tpl, cachedOpts);
templateFnCache.set(tpl, builder);
}
return extendedTrace(builder(args));
} else if (typeof tpl === "object" && tpl) {
if (args.length > 0) throw new Error("Unexpected extra params.");
return createTemplateBuilder(
formatter,
merge(cachedOpts, validate(tpl)),
);
}
throw new Error(`Unexpected template param ${typeof tpl}`);
}: Function),
{
ast: (tpl, ...args) => {
if (typeof tpl === "string") {
if (args.length > 1) throw new Error("Unexpected extra params.");
return stringTemplate(
formatter,
tpl,
merge(merge(cachedOpts, validate(args[0])), NO_PLACEHOLDER),
)();
} else if (Array.isArray(tpl)) {
let builder = templateAstCache.get(tpl);
if (!builder) {
builder = literalTemplate(
formatter,
tpl,
merge(cachedOpts, NO_PLACEHOLDER),
);
templateAstCache.set(tpl, builder);
}
return builder(args)();
}
throw new Error(`Unexpected template param ${typeof tpl}`);
},
},
);
}
function extendedTrace<Arg, Result>(fn: Arg => Result): Arg => Result {
// Since we lazy parse the template, we get the current stack so we have the
// original stack to append if it errors when parsing
let rootStack = "";
try {
// error stack gets populated in IE only on throw
// (https://msdn.microsoft.com/en-us/library/hh699850(v=vs.94).aspx)
throw new Error();
} catch (error) {
if (error.stack) {
// error.stack does not exists in IE <= 9
// We slice off the top 3 items in the stack to remove the call to
// 'extendedTrace', and the anonymous builder function, with the final
// stripped line being the error message itself since we threw it
// in the first place and it doesn't matter.
rootStack = error.stack
.split("\n")
.slice(3)
.join("\n");
}
}
return (arg: Arg) => {
try {
return fn(arg);
} catch (err) {
err.stack += `\n =============\n${rootStack}`;
throw err;
}
};
}

View File

@ -0,0 +1,74 @@
// @flow
export type Formatter<T> = {
code: string => string,
validate: BabelNodeFile => void,
unwrap: BabelNodeFile => T,
};
function makeStatementFormatter<T>(
fn: (Array<BabelNodeStatement>) => T,
): Formatter<T> {
return {
// We need to prepend a ";" to force statement parsing so that
// ExpressionStatement strings won't be parsed as directives.
// Alonside that, we also prepend a comment so that when a syntax error
// is encountered, the user will be less likely to get confused about
// where the random semicolon came from.
code: str => `/* @babel/template */;\n${str}`,
validate: () => {},
unwrap: (ast: BabelNodeFile): T => {
return fn(ast.program.body.slice(1));
},
};
}
export const smart: Formatter<
Array<BabelNodeStatement> | BabelNodeStatement,
> = makeStatementFormatter(body => {
if (body.length > 1) {
return body;
} else {
return body[0];
}
});
export const statements: Formatter<
Array<BabelNodeStatement>,
> = makeStatementFormatter(body => body);
export const statement: Formatter<
BabelNodeStatement,
> = makeStatementFormatter(body => {
// We do this validation when unwrapping since the replacement process
// could have added or removed statements.
if (body.length === 0) {
throw new Error("Found nothing to return.");
}
if (body.length > 1) {
throw new Error("Found multiple statements but wanted one");
}
return body[0];
});
export const expression: Formatter<BabelNodeExpression> = {
code: str => `(\n${str}\n)`,
validate: (ast: BabelNodeFile) => {
const { program } = ast;
if (program.body.length > 1) {
throw new Error("Found multiple statements but wanted one");
}
const expression = program.body[0].expression;
if (expression.start === 0) {
throw new Error("Parse result included parens.");
}
},
unwrap: ast => ast.program.body[0].expression,
};
export const program: Formatter<BabelNodeProgram> = {
code: str => str,
validate: () => {},
unwrap: ast => ast.program,
};

View File

@ -1,221 +1,31 @@
import cloneDeep from "lodash/cloneDeep";
import has from "lodash/has";
import traverse from "@babel/traverse";
import * as babylon from "babylon";
import { codeFrameColumns } from "@babel/code-frame";
import * as t from "@babel/types";
// @flow
const FROM_TEMPLATE = new Set();
import * as formatters from "./formatters";
import createTemplateBuilder from "./builder";
export default function(firstArg, ...rest) {
if (typeof firstArg === "string") {
return factory(firstArg, ...rest);
} else {
return template(firstArg, ...rest);
}
}
export const smart = createTemplateBuilder(formatters.smart);
export const statement = createTemplateBuilder(formatters.statement);
export const statements = createTemplateBuilder(formatters.statements);
export const expression = createTemplateBuilder(formatters.expression);
export const program = createTemplateBuilder(formatters.program);
function template(partials: Object | string[], ...args: Array<Object>) {
if (!Array.isArray(partials)) {
// support template({ options })`string`
return templateApply.bind(undefined, partials);
}
return templateApply(null, partials, ...args);
}
function templateApply(
opts: Object | null,
partials: string[],
...args: Array<Object>
) {
if (partials.some(str => str.includes("$BABEL_TEMPLATE$"))) {
throw new Error("Template contains illegal substring $BABEL_TEMPLATE$");
}
if (partials.length == 1) {
return factory(partials[0], opts);
}
const replacementSet = new Set();
const replacementMap = new Map();
const replacementValueMap = new Map();
let hasNonNumericReplacement = false;
for (const arg of args) {
if (replacementMap.has(arg)) {
continue;
}
if (typeof arg === "number") {
replacementMap.set(arg, `$${arg}`);
} else if (typeof arg === "string") {
// avoid duplicates should t.toIdentifier produce the same result for different arguments
const replacementBase = `$BABEL_TEMPLATE$$${t.toIdentifier(arg)}`;
let replacement = replacementBase;
for (let i = 2; replacementSet.has(replacement); i++) {
replacement = `${replacementBase}${i}`;
}
replacementSet.add(replacement);
replacementMap.set(arg, replacement);
hasNonNumericReplacement = true;
} else {
// there can't be duplicates as the size always grows
const name = `$BABEL_TEMPLATE$VALUE$${replacementValueMap.size}`;
// TODO: check if the arg is a Node
replacementMap.set(arg, name);
replacementValueMap.set(name, arg);
hasNonNumericReplacement = true;
}
}
if (hasNonNumericReplacement && replacementMap.has(0)) {
throw new Error(
"Template cannot have a '0' replacement and a named replacement at the same time",
);
}
const code = partials.reduce((acc, partial, i) => {
if (acc == null) {
return partial;
}
const replacement = replacementMap.get(args[i - 1]);
return `${acc}${replacement}${partial}`;
}, null);
const func = factory(code, opts);
return (...args: Array<Object>) => {
if (hasNonNumericReplacement) {
const argObj = args[0] || {};
const converted = {};
for (const [key, replacement] of replacementMap) {
if (typeof key === "number") continue;
if (replacementValueMap.has(replacement)) {
converted[replacement] = replacementValueMap.get(replacement);
} else {
converted[replacement] = argObj[key];
}
}
args[0] = converted;
}
return func(...args);
};
}
function factory(code: string, opts?: Object): Function {
// since we lazy parse the template, we get the current stack so we have the
// original stack to append if it errors when parsing
let stack;
try {
// error stack gets populated in IE only on throw
// (https://msdn.microsoft.com/en-us/library/hh699850(v=vs.94).aspx)
throw new Error();
} catch (error) {
if (error.stack) {
// error.stack does not exists in IE <= 9
stack = error.stack
.split("\n")
.slice(2)
.join("\n");
}
}
opts = Object.assign(
{
allowReturnOutsideFunction: true,
allowSuperOutsideMethod: true,
preserveComments: false,
},
opts,
);
let getAst = function() {
let ast;
try {
ast = babylon.parse(code, opts);
ast = traverse.removeProperties(ast, {
preserveComments: opts.preserveComments,
});
} catch (err) {
const loc = err.loc;
if (loc) {
err.loc = null;
err.message += "\n" + codeFrameColumns(code, { start: loc });
}
err.stack = `${err.stack}\n ==========================\n${stack}`;
throw err;
}
getAst = function() {
return ast;
};
return ast;
};
return function(...args) {
return useTemplate(getAst(), args);
};
}
function useTemplate(ast, nodes?: Array<Object>) {
ast = cloneDeep(ast);
const { program } = ast;
if (nodes.length) {
traverse.cheap(ast, function(node) {
FROM_TEMPLATE.add(node);
});
traverse(ast, templateVisitor, null, nodes);
FROM_TEMPLATE.clear();
}
if (program.body.length > 1) {
return program.body;
} else {
return program.body[0];
}
}
const templateVisitor = {
// 360
noScope: true,
Identifier(path, args) {
const { node, parentPath } = path;
if (!FROM_TEMPLATE.has(node)) return path.skip();
let replacement;
if (has(args[0], node.name)) {
replacement = args[0][node.name];
} else if (node.name[0] === "$") {
const i = +node.name.slice(1);
if (args[i]) replacement = args[i];
}
if (parentPath.isExpressionStatement()) {
path = parentPath;
}
if (replacement === null) {
path.remove();
} else if (replacement) {
path.replaceInline(replacement);
path.skip();
}
},
exit({ node }) {
if (!node.loc) {
traverse.clearNode(node);
}
},
type DefaultTemplateBuilder = typeof smart & {
smart: typeof smart,
statement: typeof statement,
statements: typeof statements,
expression: typeof expression,
program: typeof program,
ast: typeof smart.ast,
};
export default Object.assign(
((smart.bind(undefined): any): DefaultTemplateBuilder),
{
smart,
statement,
statements,
expression,
program,
ast: smart.ast,
},
);

View File

@ -0,0 +1,103 @@
// @flow
import type { Formatter } from "./formatters";
import { normalizeReplacements, type TemplateOpts } from "./options";
import parseAndBuildMetadata from "./parse";
import populatePlaceholders from "./populate";
export default function literalTemplate<T>(
formatter: Formatter<T>,
tpl: Array<string>,
opts: TemplateOpts,
): (Array<mixed>) => mixed => T {
const { metadata, names } = buildLiteralData(formatter, tpl, opts);
return (arg: Array<mixed>) => {
const defaultReplacements = arg.reduce((acc, replacement, i) => {
acc[names[i]] = replacement;
return acc;
}, {});
return (arg: mixed) => {
const replacements = normalizeReplacements(arg);
if (replacements) {
Object.keys(replacements).forEach(key => {
if (Object.prototype.hasOwnProperty.call(defaultReplacements, key)) {
throw new Error("Unexpected replacement overlap.");
}
});
}
return formatter.unwrap(
populatePlaceholders(
metadata,
replacements
? Object.assign(replacements, defaultReplacements)
: defaultReplacements,
),
);
};
};
}
function buildLiteralData<T>(
formatter: Formatter<T>,
tpl: Array<string>,
opts: TemplateOpts,
) {
let names;
let nameSet;
let metadata;
let prefix = "";
do {
// If there are cases where the template already contains $0 or any other
// matching pattern, we keep adding "$" characters until a unique prefix
// is found.
prefix += "$";
const result = buildTemplateCode(tpl, prefix);
names = result.names;
nameSet = new Set(names);
metadata = parseAndBuildMetadata(formatter, formatter.code(result.code), {
parser: opts.parser,
// Explicitly include our generated names in the whitelist so users never
// have to think about whether their placeholder pattern will match.
placeholderWhitelist: new Set(
result.names.concat(
opts.placeholderWhitelist
? Array.from(opts.placeholderWhitelist)
: [],
),
),
placeholderPattern: opts.placeholderPattern,
preserveComments: opts.preserveComments,
});
} while (
metadata.placeholders.some(
placeholder => placeholder.isDuplicate && nameSet.has(placeholder.name),
)
);
return { metadata, names };
}
function buildTemplateCode(
tpl: Array<string>,
prefix: string,
): { names: Array<string>, code: string } {
const names = [];
let code = tpl[0];
for (let i = 1; i < tpl.length; i++) {
const value = `${prefix}${i - 1}`;
names.push(value);
code += value + tpl[i];
}
return { names, code };
}

View File

@ -0,0 +1,116 @@
// @flow
/**
* These are the options that 'babel-template' actually accepts and typechecks
* when called. All other options are passed through to the parser.
*/
export type PublicOpts = {
/**
* A set of placeholder names to automatically accept, ignoring the given
* pattern entirely.
*/
placeholderWhitelist?: ?Set<string>,
/**
* A pattern to search for when looking for Identifier and StringLiteral
* nodes that can be replaced.
*
* 'false' will disable placeholder searching entirely, leaving only the
* 'placeholderWhitelist' value to find replacements.
*
* Defaults to /^[_$A-Z0-9]+$/.
*/
placeholderPattern?: ?(RegExp | false),
/**
* 'true' to pass through comments from the template into the resulting AST,
* or 'false' to automatically discard comments. Defaults to 'false'.
*/
preserveComments?: ?boolean,
};
export type TemplateOpts = {|
parser: {},
placeholderWhitelist: Set<string> | void,
placeholderPattern: RegExp | false | void,
preserveComments: boolean | void,
|};
export function merge(a: TemplateOpts, b: TemplateOpts): TemplateOpts {
const {
placeholderWhitelist = a.placeholderWhitelist,
placeholderPattern = a.placeholderPattern,
preserveComments = a.preserveComments,
} = b;
return {
parser: Object.assign({}, a.parser, b.parser),
placeholderWhitelist,
placeholderPattern,
preserveComments,
};
}
export function validate(opts: mixed): TemplateOpts {
if (opts != null && typeof opts !== "object") {
throw new Error("Unknown template options.");
}
const {
placeholderWhitelist,
placeholderPattern,
preserveComments,
...parser
} =
opts || {};
if (placeholderWhitelist != null && !(placeholderWhitelist instanceof Set)) {
throw new Error(
"'.placeholderWhitelist' must be a Set, null, or undefined",
);
}
if (
placeholderPattern != null &&
!(placeholderPattern instanceof RegExp) &&
placeholderPattern !== false
) {
throw new Error(
"'.placeholderPattern' must be a RegExp, false, null, or undefined",
);
}
if (preserveComments != null && typeof preserveComments !== "boolean") {
throw new Error(
"'.preserveComments' must be a boolean, null, or undefined",
);
}
return {
parser,
placeholderWhitelist: placeholderWhitelist || undefined,
placeholderPattern:
placeholderPattern == null ? undefined : placeholderPattern,
preserveComments: preserveComments == null ? false : preserveComments,
};
}
export type PublicReplacements = { [string]: mixed } | Array<mixed>;
export type TemplateReplacements = { [string]: mixed } | void;
export function normalizeReplacements(
replacements: mixed,
): TemplateReplacements {
if (Array.isArray(replacements)) {
return replacements.reduce((acc, replacement, i) => {
acc["$" + i] = replacement;
return acc;
}, {});
} else if (typeof replacements === "object" || replacements == null) {
return replacements || undefined;
}
throw new Error(
"Template replacements must be an array, object, null, or undefined",
);
}

View File

@ -0,0 +1,156 @@
// @flow
import * as t from "@babel/types";
import type { TraversalAncestors, TraversalHandler } from "@babel/types";
import { parse } from "babylon";
import { codeFrameColumns } from "@babel/code-frame";
import type { TemplateOpts } from "./options";
import type { Formatter } from "./formatters";
export type Metadata = {
ast: BabelNodeFile,
placeholders: Array<Placeholder>,
placeholderNames: Set<string>,
};
type PlaceholderType = "string" | "param" | "statement" | "other";
export type Placeholder = {|
name: string,
resolve: BabelNodeFile => { parent: BabelNode, key: string, index?: number },
type: PlaceholderType,
isDuplicate: boolean,
|};
const PATTERN = /^[_$A-Z0-9]+$/;
export default function parseAndBuildMetadata<T>(
formatter: Formatter<T>,
code: string,
opts: TemplateOpts,
): Metadata {
const ast = parseWithCodeFrame(code, opts.parser);
const {
placeholderWhitelist,
placeholderPattern = PATTERN,
preserveComments,
} = opts;
t.removePropertiesDeep(ast, {
preserveComments,
});
formatter.validate(ast);
const placeholders = [];
const placeholderNames = new Set();
t.traverse(ast, (placeholderVisitorHandler: TraversalHandler<*>), {
placeholders,
placeholderNames,
placeholderWhitelist,
placeholderPattern,
});
return {
ast,
placeholders,
placeholderNames,
};
}
function placeholderVisitorHandler(
node: BabelNode,
ancestors: TraversalAncestors,
state: MetadataState,
) {
let name;
if (t.isIdentifier(node)) {
name = ((node: any): BabelNodeIdentifier).name;
} else if (t.isStringLiteral(node)) {
name = ((node: any): BabelNodeStringLiteral).value;
} else {
return;
}
if (
(!state.placeholderPattern || !state.placeholderPattern.test(name)) &&
(!state.placeholderWhitelist || !state.placeholderWhitelist.has(name))
) {
return;
}
// Keep our own copy of the ancestors so we can use it in .resolve().
ancestors = ancestors.slice();
const { node: parent, key } = ancestors[ancestors.length - 1];
let type: PlaceholderType;
if (t.isStringLiteral(node)) {
type = "string";
} else if (
(t.isNewExpression(parent) && key === "arguments") ||
(t.isCallExpression(parent) && key === "arguments") ||
(t.isFunction(parent) && key === "params")
) {
type = "param";
} else if (t.isExpressionStatement(parent)) {
type = "statement";
ancestors = ancestors.slice(0, -1);
} else {
type = "other";
}
state.placeholders.push({
name,
type,
resolve: ast => resolveAncestors(ast, ancestors),
isDuplicate: state.placeholderNames.has(name),
});
state.placeholderNames.add(name);
}
function resolveAncestors(ast: BabelNodeFile, ancestors: TraversalAncestors) {
let parent: BabelNode = ast;
for (let i = 0; i < ancestors.length - 1; i++) {
const { key, index } = ancestors[i];
if (index === undefined) {
parent = (parent: any)[key];
} else {
parent = (parent: any)[key][index];
}
}
const { key, index } = ancestors[ancestors.length - 1];
return { parent, key, index };
}
type MetadataState = {
placeholders: Array<Placeholder>,
placeholderNames: Set<string>,
placeholderWhitelist: Set<string> | void,
placeholderPattern: RegExp | false,
};
function parseWithCodeFrame(code: string, parserOpts: {}): BabelNodeFile {
parserOpts = Object.assign(
{
allowReturnOutsideFunction: true,
allowSuperOutsideMethod: true,
sourceType: "module",
},
parserOpts,
);
try {
return parse(code, parserOpts);
} catch (err) {
const loc = err.loc;
if (loc) {
err.loc = null;
err.message += "\n" + codeFrameColumns(code, { start: loc });
}
throw err;
}
}

View File

@ -0,0 +1,131 @@
// @flow
import * as t from "@babel/types";
import type { TemplateReplacements } from "./options";
import type { Metadata, Placeholder } from "./parse";
export default function populatePlaceholders(
metadata: Metadata,
replacements: TemplateReplacements,
): BabelNodeFile {
const ast = t.cloneDeep(metadata.ast);
if (replacements) {
metadata.placeholders.forEach(placeholder => {
if (
!Object.prototype.hasOwnProperty.call(replacements, placeholder.name)
) {
throw new Error(`No substitution given for "${placeholder.name}"`);
}
});
Object.keys(replacements).forEach(key => {
if (!metadata.placeholderNames.has(key)) {
throw new Error(`Unknown substitution "${key}" given`);
}
});
}
// Process in reverse order to AST mutation doesn't change indices that
// will be needed for later calls to `placeholder.resolve()`.
metadata.placeholders
.slice()
.reverse()
.forEach(placeholder => {
try {
applyReplacement(
placeholder,
ast,
(replacements && replacements[placeholder.name]) || null,
);
} catch (e) {
e.message = `babel-template placeholder "${placeholder.name}": ${e.message}`;
throw e;
}
});
return ast;
}
function applyReplacement(
placeholder: Placeholder,
ast: BabelNodeFile,
replacement: any,
) {
// Track inserted nodes and clone them if they are inserted more than
// once to avoid injecting the same node multiple times.
if (placeholder.isDuplicate) {
if (Array.isArray(replacement)) {
replacement = replacement.map(node => t.cloneDeep(node));
} else if (typeof replacement === "object") {
replacement = t.cloneDeep(replacement);
}
}
const { parent, key, index } = placeholder.resolve(ast);
if (placeholder.type === "string") {
if (typeof replacement === "string") {
replacement = t.stringLiteral(replacement);
}
if (!replacement || !t.isStringLiteral(replacement)) {
throw new Error("Expected string substitution");
}
} else if (placeholder.type === "statement") {
if (index === undefined) {
if (!replacement) {
replacement = t.emptyStatement();
} else if (Array.isArray(replacement)) {
replacement = t.blockStatement(replacement);
} else if (typeof replacement === "string") {
replacement = t.expressionStatement(t.identifier(replacement));
} else if (!t.isStatement(replacement)) {
replacement = t.expressionStatement((replacement: any));
}
} else {
if (replacement && !Array.isArray(replacement)) {
if (typeof replacement === "string") {
replacement = t.identifier(replacement);
}
if (!t.isStatement(replacement)) {
replacement = t.expressionStatement((replacement: any));
}
}
}
} else if (placeholder.type === "param") {
if (typeof replacement === "string") {
replacement = t.identifier(replacement);
}
if (index === undefined) throw new Error("Assertion failure.");
} else {
if (typeof replacement === "string") {
replacement = t.identifier(replacement);
}
if (Array.isArray(replacement)) {
throw new Error("Cannot replace single expression with an array.");
}
}
if (index === undefined) {
t.validate(parent, key, replacement);
(parent: any)[key] = replacement;
} else {
const items: Array<BabelNode> = (parent: any)[key].slice();
if (placeholder.type === "statement" || placeholder.type === "param") {
if (replacement == null) {
items.splice(index, 1);
} else if (Array.isArray(replacement)) {
items.splice(index, 1, ...replacement);
} else {
items[index] = replacement;
}
} else {
items[index] = replacement;
}
t.validate(parent, key, items);
(parent: any)[key] = items;
}
}

View File

@ -0,0 +1,23 @@
// @flow
import type { Formatter } from "./formatters";
import { normalizeReplacements, type TemplateOpts } from "./options";
import parseAndBuildMetadata from "./parse";
import populatePlaceholders from "./populate";
export default function stringTemplate<T>(
formatter: Formatter<T>,
code: string,
opts: TemplateOpts,
): mixed => T {
code = formatter.code(code);
let metadata;
return (arg?: mixed) => {
const replacements = normalizeReplacements(arg);
if (!metadata) metadata = parseAndBuildMetadata(formatter, code, opts);
return formatter.unwrap(populatePlaceholders(metadata, replacements));
};
}

View File

@ -1,34 +1,202 @@
import generator from "../../babel-generator";
import template from "../lib";
import chai from "chai";
import { expect } from "chai";
import * as t from "babel-types";
const comments = "// Sum two numbers\nconst add = (a, b) => a + b;";
describe("templating", function() {
it("import statement will cause parser to throw by default", function() {
chai
.expect(function() {
template("import foo from 'foo'")({});
})
.to.throw();
describe("babel-template", function() {
it("import statements are allowed by default", function() {
expect(function() {
template("import foo from 'foo'")({});
}).not.to.throw();
});
it("import statements are allowed with sourceType: module", function() {
chai
.expect(function() {
template("import foo from 'foo'", { sourceType: "module" })({});
})
.not.to.throw();
it("with statements are allowed with sourceType: script", function() {
expect(function() {
template("with({}){}", { sourceType: "script" })({});
}).not.to.throw();
});
it("should strip comments by default", function() {
const code = "const add = (a, b) => a + b;";
const output = template(comments)();
chai.expect(generator(output).code).to.be.equal(code);
expect(generator(output).code).to.be.equal(code);
});
it("should preserve comments with a flag", function() {
const output = template(comments, { preserveComments: true })();
chai.expect(generator(output).code).to.be.equal(comments);
expect(generator(output).code).to.be.equal(comments);
});
describe("string-based", () => {
it("should handle replacing values from an object", () => {
const value = t.stringLiteral("some string value");
const result = template(`
if (SOME_VAR === "") {}
`)({
SOME_VAR: value,
});
expect(result.type).to.equal("IfStatement");
expect(result.test.type).to.equal("BinaryExpression");
expect(result.test.left).to.equal(value);
});
it("should handle replacing values given an array", () => {
const value = t.stringLiteral("some string value");
const result = template(`
if ($0 === "") {}
`)([value]);
expect(result.type).to.equal("IfStatement");
expect(result.test.type).to.equal("BinaryExpression");
expect(result.test.left).to.equal(value);
});
it("should handle replacing values with null to remove them", () => {
const result = template(`
callee(ARG);
`)({ ARG: null });
expect(result.type).to.equal("ExpressionStatement");
expect(result.expression.type).to.equal("CallExpression");
expect(result.expression.arguments).to.eql([]);
});
it("should handle replacing values that are string content", () => {
const result = template(`
("ARG");
`)({ ARG: "some new content" });
expect(result.type).to.equal("ExpressionStatement");
expect(result.expression.type).to.equal("StringLiteral");
expect(result.expression.value).to.equal("some new content");
});
it("should automatically clone nodes if they are injected twice", () => {
const id = t.identifier("someIdent");
const result = template(`
ID;
ID;
`)({ ID: id });
expect(result[0].type).to.equal("ExpressionStatement");
expect(result[0].expression).to.equal(id);
expect(result[1].type).to.equal("ExpressionStatement");
expect(result[1].expression).not.to.equal(id);
expect(result[1].expression).to.eql(id);
});
it("should allow passing in a whitelist of replacement names", () => {
const id = t.identifier("someIdent");
const result = template(
`
some_id;
`,
{ placeholderWhitelist: new Set(["some_id"]) },
)({ some_id: id });
expect(result.type).to.equal("ExpressionStatement");
expect(result.expression).to.equal(id);
});
it("should allow passing in a RegExp to match replacement patterns", () => {
const id = t.identifier("someIdent");
const result = template(
`
ID;
ANOTHER_ID;
`,
{ placeholderPattern: /^ID$/ },
)({ ID: id });
expect(result[0].type).to.equal("ExpressionStatement");
expect(result[0].expression).to.equal(id);
expect(result[1].type).to.equal("ExpressionStatement");
expect(result[1].expression.type).to.equal("Identifier");
expect(result[1].expression.name).to.equal("ANOTHER_ID");
});
it("should throw if unknown replacements are provided", () => {
expect(() => {
template(`
ID;
`)({ ID: t.identifier("someIdent"), ANOTHER_ID: null });
}).to.throw(Error, 'Unknown substitution "ANOTHER_ID" given');
});
it("should throw if placeholders are not given explicit values", () => {
expect(() => {
template(`
ID;
ANOTHER_ID;
`)({ ID: t.identifier("someIdent") });
}).to.throw(Error, 'No substitution given for "ANOTHER_ID"');
});
it("should return the AST directly when using .ast", () => {
const result = template.ast(`
if ("some string value" === "") {}
`);
expect(result.type).to.equal("IfStatement");
expect(result.test.type).to.equal("BinaryExpression");
expect(result.test.left.type).to.equal("StringLiteral");
expect(result.test.left.value).to.equal("some string value");
});
});
describe("literal-based", () => {
it("should handle replacing values from an object", () => {
const value = t.stringLiteral("some string value");
const result = template`
if (${value} === "") {}
`();
expect(result.type).to.equal("IfStatement");
expect(result.test.type).to.equal("BinaryExpression");
expect(result.test.left).to.equal(value);
});
it("should handle replacing values with null to remove them", () => {
const result = template`
callee(${null});
`();
expect(result.type).to.equal("ExpressionStatement");
expect(result.expression.type).to.equal("CallExpression");
expect(result.expression.arguments).to.eql([]);
});
it("should handle replacing values that are string content", () => {
const result = template`
("${"some new content"}");
`();
expect(result.type).to.equal("ExpressionStatement");
expect(result.expression.type).to.equal("StringLiteral");
expect(result.expression.value).to.equal("some new content");
});
it("should allow setting options by passing an object", () => {
const result = template({ sourceType: "script" })`
with({}){}
`();
expect(result.type).to.equal("WithStatement");
});
it("should return the AST directly when using .ast", () => {
const value = t.stringLiteral("some string value");
const result = template.ast`
if (${value} === "") {}
`;
expect(result.type).to.equal("IfStatement");
expect(result.test.type).to.equal("BinaryExpression");
expect(result.test.left).to.equal(value);
});
});
});

View File

@ -1,183 +0,0 @@
import generator from "../../babel-generator";
import * as t from "@babel/types";
import template from "../lib";
import chai from "chai";
const expect = chai.expect;
describe("tagged templating", () => {
it("basic support", () => {
const tpl = template`("stringLiteral")`;
const result = tpl();
expect(result).to.be.ok;
expect(t.isStringLiteral(result.expression)).to.be.true;
});
describe("numeric interpolation", () => {
it("single replacement", () => {
const tpl = template`+${0}`;
const node = t.numericLiteral(123);
const result = tpl(node);
expect(result).to.be.ok;
expect(t.isUnaryExpression(result.expression)).to.be.true;
expect(result.expression.argument).to.equal(node);
});
it("duplicate replacement", () => {
const tpl = template`${0} + ${0}`;
const node = t.numericLiteral(123);
const result = tpl(node);
expect(result).to.be.ok;
expect(t.isBinaryExpression(result.expression)).to.be.true;
expect(result.expression.left).to.equal(node);
expect(result.expression.right).to.equal(result.expression.left);
});
it("multiple replacement", () => {
const tpl = template`${0}.${1}(${2})`;
const object = t.identifier("foo");
const property = t.identifier("bar");
const argument = t.numericLiteral(123);
const result = tpl(object, property, argument);
expect(result).to.be.ok;
expect(t.isCallExpression(result.expression)).to.be.true;
const { callee, arguments: args } = result.expression;
expect(t.isMemberExpression(callee)).to.be.true;
expect(callee.object).to.equal(object);
expect(callee.property).to.equal(property);
expect(args).to.deep.equal([argument]);
});
});
describe("string interpolation", () => {
it("has expected internal representation", () => {
const tpl = template`${"foo"}(${"b a r"})`;
expect(generator(tpl()).code).to.equal(
"$BABEL_TEMPLATE$$foo($BABEL_TEMPLATE$$bAR);",
);
});
it("simple replacement", () => {
const tpl = template`${"foo"}(${"b a r"})`;
const arg = {
foo: t.identifier("baz"),
"b a r": t.numericLiteral(123),
};
const result = tpl(arg);
expect(result).to.be.ok;
expect(t.isCallExpression(result.expression)).to.be.true;
const { callee, arguments: args } = result.expression;
expect(callee).to.equal(arg.foo);
expect(args).to.deep.equal([arg["b a r"]]);
});
it("does not conflict with similar identifiers", () => {
const tpl = template`foo + ${"foo"}`;
const arg = {
foo: t.identifier("foo"),
};
const result = tpl(arg);
expect(result).to.be.ok;
expect(t.isBinaryExpression(result.expression)).to.be.true;
const { left, right } = result.expression;
expect(left).to.not.equal(right);
expect(t.isIdentifier(left, { name: "foo" })).to.be.true;
expect(right).to.equal(arg.foo);
});
it("does not conflict when t.toIdentifier conflicts", () => {
const tpl = template`${"fOO"} + ${"f o o"}`;
const arg = {
fOO: t.numericLiteral(123),
"f o o": t.numericLiteral(321),
};
const result = tpl(arg);
expect(result).to.be.ok;
expect(t.isBinaryExpression(result.expression)).to.be.true;
const { left, right } = result.expression;
expect(left).to.not.equal(right);
expect(left).to.equal(arg.fOO);
expect(right).to.equal(arg["f o o"]);
});
});
describe("mixed interpolation", () => {
it("throws when 0 is used", () => {
expect(() => template`${0} - ${"foo"}`).to.throw(
"Template cannot have a '0' replacement and a named replacement at the same time",
);
});
it("works", () => {
const tpl = template`${1}.${"prop"}`;
const arg = {
prop: t.identifier("prop"),
};
const result = tpl(arg, t.thisExpression());
expect(result).to.be.ok;
expect(t.isMemberExpression(result.expression)).to.be.true;
const { object, property } = result.expression;
expect(t.isThisExpression(object)).to.be.true;
expect(property).to.equal(arg.prop);
});
});
describe("Node interpolation", () => {
it("works", () => {
const node = t.identifier("foo");
const tpl = template`${node}`;
const result = tpl();
expect(result).to.be.ok;
expect(result.expression).to.equal(node);
});
});
describe("options", () => {
it("works", () => {
const remove = template({ preserveComments: false })`// comment\nid;`;
const preserve = template({ preserveComments: true })`// comment\nid;`;
const removeResult = remove();
const preserveResult = preserve();
expect(removeResult);
expect(preserveResult).to.be.ok;
// it exists, it just resets to undefined
expect(removeResult.leadingComments).to.be.undefined;
expect(Array.isArray(preserveResult.leadingComments)).to.be.true;
expect(preserveResult.leadingComments[0]).to.have.property(
"type",
"CommentLine",
);
expect(preserveResult.leadingComments[0]).to.have.property(
"value",
" comment",
);
});
});
});

View File

@ -66,6 +66,9 @@ export { VISITOR_KEYS, ALIAS_KEYS, NODE_FIELDS, BUILDER_KEYS, DEPRECATED_KEYS };
import * as _react from "./react";
export { _react as react };
import { traverse, traverseFast } from "./traverse";
export { traverse, traverseFast };
/**
* Registers `is[Type]` and `assert[Type]` for all types.
*/
@ -534,36 +537,6 @@ export function isNode(node?): boolean {
toFastProperties(t);
toFastProperties(t.VISITOR_KEYS);
/**
* A prefix AST traversal implementation implementation.
*/
export function traverseFast(
node: Node,
enter: (node: Node) => void,
opts?: Object,
) {
if (!node) return;
const keys = t.VISITOR_KEYS[node.type];
if (!keys) return;
opts = opts || {};
enter(node, opts);
for (const key of keys) {
const subNode = node[key];
if (Array.isArray(subNode)) {
for (const node of subNode) {
traverseFast(node, enter, opts);
}
} else {
traverseFast(subNode, enter, opts);
}
}
}
const CLEAR_KEYS: Array = ["tokens", "start", "end", "loc", "raw", "rawValue"];
const CLEAR_KEYS_PLUS_COMMENTS: Array = t.COMMENT_KEYS

View File

@ -0,0 +1,99 @@
import { VISITOR_KEYS } from "./index";
/**
* A prefix AST traversal implementation meant for simple searching
* and processing.
*/
export function traverseFast(
node: Node,
enter: (node: Node) => void,
opts?: Object,
) {
if (!node) return;
const keys = VISITOR_KEYS[node.type];
if (!keys) return;
opts = opts || {};
enter(node, opts);
for (const key of keys) {
const subNode = node[key];
if (Array.isArray(subNode)) {
for (const node of subNode) {
traverseFast(node, enter, opts);
}
} else {
traverseFast(subNode, enter, opts);
}
}
}
export type TraversalAncestors = Array<{
node: BabelNode,
key: string,
index?: number,
}>;
export type TraversalHandler<T> = (BabelNode, TraversalAncestors, T) => void;
export type TraversalHandlers<T> = {
enter?: TraversalHandler<T>,
exit?: TraversalHandler<T>,
};
/**
* A general AST traversal with both prefix and postfix handlers, and a
* state object. Exposes ancestry data to each handler so that more complex
* AST data can be taken into account.
*/
export function traverse<T>(
node: BabelNode,
handlers: TraversalHandler<T> | TraversalHandlers<T>,
state?: T,
) {
if (typeof handlers === "function") {
handlers = { enter: handlers };
}
const { enter, exit } = handlers;
traverseSimpleImpl(node, enter, exit, state, []);
}
function traverseSimpleImpl(node, enter, exit, state, ancestors) {
const keys = VISITOR_KEYS[node.type];
if (!keys) return;
if (enter) enter(node, ancestors, state);
for (const key of keys) {
const subNode = node[key];
if (Array.isArray(subNode)) {
for (let i = 0; i < subNode.length; i++) {
const child = subNode[i];
if (!child) continue;
ancestors.push({
node,
key,
index: i,
});
traverseSimpleImpl(child, enter, exit, state, ancestors);
ancestors.pop();
}
} else if (subNode) {
ancestors.push({
node,
key,
});
traverseSimpleImpl(subNode, enter, exit, state, ancestors);
ancestors.pop();
}
}
if (exit) exit(node, ancestors, state);
}

View File

@ -124,11 +124,37 @@ for (const type in t.NODE_FIELDS) {
}
for (let i = 0; i < t.TYPES.length; i++) {
lines.push(
`declare function is${t.TYPES[i]}(node: Object, opts?: Object): boolean;`
);
let decl = `declare function is${t.TYPES[
i
]}(node: Object, opts?: ?Object): boolean`;
if (t.NODE_FIELDS[t.TYPES[i]]) {
decl += ` %checks (node instanceof ${NODE_PREFIX}${t.TYPES[i]})`;
}
lines.push(decl);
}
lines.push(
`declare function validate(n: BabelNode, key: string, value: mixed): void;`,
`declare function clone<T>(n: T): T;`,
`declare function cloneDeep<T>(n: T): T;`,
`declare function removeProperties<T>(n: T, opts: ?{}): void;`,
`declare function removePropertiesDeep<T>(n: T, opts: ?{}): T;`,
`declare type TraversalAncestors = Array<{
node: BabelNode,
key: string,
index?: number,
}>;
declare type TraversalHandler<T> = (BabelNode, TraversalAncestors, T) => void;
declare type TraversalHandlers<T> = {
enter?: TraversalHandler<T>,
exit?: TraversalHandler<T>,
};`.replace(/(^|\n) {2}/g, "$1"),
// eslint-disable-next-line
`declare function traverse<T>(n: BabelNode, TraversalHandler<T> | TraversalHandlers<T>, state?: T): void;`
);
for (const type in t.FLIPPED_ALIAS_KEYS) {
const types = t.FLIPPED_ALIAS_KEYS[type];
code += `type ${NODE_PREFIX}${type} = ${types