import * as Babel from "@babel/core" ; import * as pathLib from "path" ; const MODEL_BLACKLIST = [ "model" ] ; const isModelContextImport = ( importPath ) : boolean => importPath . startsWith ( "." ) && /^model(\.ctx)?(\.(j|t)sx?)?$/ . test ( pathLib . basename ( importPath ) ) ; export default ( t , type , name , path ) => { const universeImports = { specifiers : { } , } ; path . get ( "body" ) . traverse ( { Identifier ( p ) { if ( p . isReferencedIdentifier ( ) ) { const binding = p . scope . getBinding ( p . node . name ) ; if ( binding != null ) { const bindingPath = binding . path ; if ( ( ( t . isImportSpecifier ( bindingPath . node ) && ! MODEL_BLACKLIST . includes ( bindingPath . node . imported . name ) ) || t . isImportNamespaceSpecifier ( bindingPath . node ) || t . isImportDefaultSpecifier ( bindingPath . node ) ) && t . isImportDeclaration ( bindingPath . parent ) && isModelContextImport ( bindingPath . parent . source . value ) ) { universeImports . modelSource = bindingPath . parent . source . value . replace ( /(\.ctx)?(?=\.(j|t)sx?)?$/ , "" ) ; universeImports . programPath = bindingPath . parentPath . parentPath as Babel . NodePath < Babel . types . Program > ; if ( t . isImportSpecifier ( bindingPath . node ) ) { universeImports . specifiers [ bindingPath . node . imported . name ] = bindingPath . node . local . name ; } else if ( t . isImportNamespaceSpecifier ( bindingPath . node ) ) { universeImports . namespace = bindingPath . node . local . name ; } else if ( t . isImportDefaultSpecifier ( bindingPath . node ) ) { universeImports . specifiers . default = bindingPath . node . local . name ; } } else if ( t . isVariableDeclarator ( bindingPath . node ) && t . isCallExpression ( bindingPath . node . init ) && t . isIdentifier ( bindingPath . node . init . callee ) && bindingPath . node . init . callee . name === "require" && bindingPath . node . init . arguments . length === 1 && t . isStringLiteral ( bindingPath . node . init . arguments [ 0 ] ) && isModelContextImport ( ( bindingPath . node . init . arguments [ 0 ] as Babel . types . StringLiteral ) . value ) ) { universeImports . modelSource = ( bindingPath . node . init . arguments [ 0 ] as Babel . types . StringLiteral ) . value . replace ( /(\.ctx)?(?=\.(j|t)sx?)?$/ , "" ) ; universeImports . programPath = bindingPath . parentPath . parentPath as Babel . NodePath < Babel . types . Program > ; if ( t . isIdentifier ( bindingPath . node . id ) ) { universeImports . namespace = bindingPath . node . id . name ; } else if ( t . isObjectPattern ( bindingPath . node . id ) && ! MODEL_BLACKLIST . includes ( p . node . name ) ) { const property = bindingPath . node . id . properties . find ( ( prop ) => t . isObjectProperty ( prop ) ? t . isIdentifier ( prop . value ) && prop . value . name === p . node . name : t . isIdentifier ( prop . argument ) && prop . argument . name === p . node . name ) ; if ( property == null ) { throw new Error ( "You are using require in a way that the transpiler can't understand." ) ; } if ( t . isObjectProperty ( property ) ) { universeImports . specifiers [ property . key . name ] = ( property . value as Babel . types . Identifier ) . name ; } else { universeImports . specifierRest = ( property . argument as Babel . types . Identifier ) . name ; } } } } } } , } ) ; if ( universeImports . namespace == null && Object . keys ( universeImports . specifiers ) . length === 0 && universeImports . specifierRest == null ) { return ; } if ( universeImports . namespace != null && ( Object . keys ( universeImports . specifiers ) . length > 0 || universeImports . specifierRest != null ) ) { throw new Error ( "Cannot import the context as both a namespace and using named imports." ) ; } let modelImport ; if ( universeImports . programPath != null && universeImports . modelSource != null ) { const importDeclarationPath = universeImports . programPath . get ( "body" ) . find ( expressionPath => t . isImportDeclaration ( expressionPath . node ) && expressionPath . node . source . value === universeImports . modelSource ) ; if ( importDeclarationPath == null ) { const importDeclaration = t . importDeclaration ( [ t . importSpecifier ( t . identifier ( "model" ) , t . identifier ( "model" ) ) ] , t . stringLiteral ( universeImports . modelSource ) ) ; ( universeImports . programPath as any ) . unshiftContainer ( "body" , importDeclaration ) ; modelImport = { specifier : "model" } ; } else { if ( ( importDeclarationPath . node as Babel . types . ImportDeclaration ) . specifiers . some ( specifier => t . isImportNamespaceSpecifier ( specifier ) ) ) { modelImport = { namespace : ( importDeclarationPath . node as Babel . types . ImportDeclaration ) . specifiers . find ( specifier => t . isImportNamespaceSpecifier ( specifier ) ) ! . local . name , } ; } else if ( ( importDeclarationPath . node as Babel . types . ImportDeclaration ) . specifiers . some ( specifier => t . isImportSpecifier ( specifier ) && specifier . imported . name === "model" ) ) { modelImport = { specifier : ( importDeclarationPath . node as Babel . types . ImportDeclaration ) . specifiers . find ( specifier => t . isImportSpecifier ( specifier ) && specifier . imported . name === "model" ) ! . local . name , } ; } else { ( importDeclarationPath as any ) . unshiftContainer ( "specifiers" , t . importSpecifier ( t . identifier ( "model" ) , t . identifier ( "model" ) ) ) ; modelImport = { specifier : "model" } ; } } } if ( modelImport == null ) { throw new Error ( "Could not import the model." ) ; } if ( t . isFunctionDeclaration ( path . node ) ) { path . replaceWith ( t . variableDeclaration ( "const" , [ t . variableDeclarator ( t . identifier ( name ) , t . functionExpression ( null , path . node . params , t . isBlockStatement ( path . node . body ) ? path . node . body : t . blockStatement ( [ t . returnStatement ( path . node . body ) ] ) , path . node . generator , path . node . async ) ) , ] ) ) ; path = path . get ( "declarations" ) [ 0 ] . get ( "init" ) ; } path . replaceWith ( t . callExpression ( t . memberExpression ( "namespace" in modelImport ? t . memberExpression ( t . identifier ( modelImport ! . namespace ) , t . identifier ( "model" ) ) : t . identifier ( modelImport ! . specifier ) , t . identifier ( type === "action" ? "action" : "connect" ) ) , [ t . arrowFunctionExpression ( [ universeImports . namespace != null ? t . identifier ( universeImports . namespace ) : t . objectPattern ( [ ... Object . keys ( universeImports . specifiers ) . sort ( ) . map ( key => t . objectProperty ( t . identifier ( key ) , t . identifier ( universeImports . specifiers [ key ] ) , false , key === universeImports . specifiers [ key ] ) ) , ... ( universeImports . specifierRest != null ? [ t . restElement ( t . identifier ( universeImports . specifierRest ) ) , ] : [ ] ) , ] ) , ] , path . node as Babel . types . FunctionExpression | Babel . types . ArrowFunctionExpression ) , t . stringLiteral ( name ) , ] ) ) ; } ;