2023-10-03 11:14:36 +08:00
"use strict" ;
Object . defineProperty ( exports , "__esModule" , {
value : true
} ) ;
exports . default = rewriteLiveReferences ;
var _assert = require ( "assert" ) ;
var _t = require ( "@babel/types" ) ;
var _template = require ( "@babel/template" ) ;
var _helperSimpleAccess = require ( "@babel/helper-simple-access" ) ;
const {
assignmentExpression ,
callExpression ,
cloneNode ,
expressionStatement ,
getOuterBindingIdentifiers ,
identifier ,
isMemberExpression ,
isVariableDeclaration ,
jsxIdentifier ,
jsxMemberExpression ,
memberExpression ,
numericLiteral ,
sequenceExpression ,
stringLiteral ,
variableDeclaration ,
variableDeclarator
} = _t ;
function isInType ( path ) {
do {
switch ( path . parent . type ) {
case "TSTypeAnnotation" :
case "TSTypeAliasDeclaration" :
case "TSTypeReference" :
case "TypeAnnotation" :
case "TypeAlias" :
return true ;
case "ExportSpecifier" :
return path . parentPath . parent . exportKind === "type" ;
default :
if ( path . parentPath . isStatement ( ) || path . parentPath . isExpression ( ) ) {
return false ;
}
}
} while ( path = path . parentPath ) ;
}
function rewriteLiveReferences ( programPath , metadata ) {
const imported = new Map ( ) ;
const exported = new Map ( ) ;
const requeueInParent = path => {
programPath . requeue ( path ) ;
} ;
for ( const [ source , data ] of metadata . source ) {
for ( const [ localName , importName ] of data . imports ) {
imported . set ( localName , [ source , importName , null ] ) ;
}
for ( const localName of data . importsNamespace ) {
imported . set ( localName , [ source , null , localName ] ) ;
}
}
for ( const [ local , data ] of metadata . local ) {
let exportMeta = exported . get ( local ) ;
if ( ! exportMeta ) {
exportMeta = [ ] ;
exported . set ( local , exportMeta ) ;
}
exportMeta . push ( ... data . names ) ;
}
const rewriteBindingInitVisitorState = {
metadata ,
requeueInParent ,
scope : programPath . scope ,
exported
} ;
programPath . traverse ( rewriteBindingInitVisitor , rewriteBindingInitVisitorState ) ;
( 0 , _helperSimpleAccess . default ) ( programPath , new Set ( [ ... Array . from ( imported . keys ( ) ) , ... Array . from ( exported . keys ( ) ) ] ) , false ) ;
const rewriteReferencesVisitorState = {
seen : new WeakSet ( ) ,
metadata ,
requeueInParent ,
scope : programPath . scope ,
imported ,
exported ,
buildImportReference : ( [ source , importName , localName ] , identNode ) => {
const meta = metadata . source . get ( source ) ;
meta . referenced = true ;
if ( localName ) {
if ( meta . lazy ) {
identNode = callExpression ( identNode , [ ] ) ;
}
return identNode ;
}
let namespace = identifier ( meta . name ) ;
if ( meta . lazy ) namespace = callExpression ( namespace , [ ] ) ;
if ( importName === "default" && meta . interop === "node-default" ) {
return namespace ;
}
const computed = metadata . stringSpecifiers . has ( importName ) ;
return memberExpression ( namespace , computed ? stringLiteral ( importName ) : identifier ( importName ) , computed ) ;
}
} ;
programPath . traverse ( rewriteReferencesVisitor , rewriteReferencesVisitorState ) ;
}
const rewriteBindingInitVisitor = {
Scope ( path ) {
path . skip ( ) ;
} ,
ClassDeclaration ( path ) {
const {
requeueInParent ,
exported ,
metadata
} = this ;
const {
id
} = path . node ;
if ( ! id ) throw new Error ( "Expected class to have a name" ) ;
const localName = id . name ;
const exportNames = exported . get ( localName ) || [ ] ;
if ( exportNames . length > 0 ) {
const statement = expressionStatement ( buildBindingExportAssignmentExpression ( metadata , exportNames , identifier ( localName ) , path . scope ) ) ;
statement . _blockHoist = path . node . _blockHoist ;
requeueInParent ( path . insertAfter ( statement ) [ 0 ] ) ;
}
} ,
VariableDeclaration ( path ) {
const {
requeueInParent ,
exported ,
metadata
} = this ;
Object . keys ( path . getOuterBindingIdentifiers ( ) ) . forEach ( localName => {
const exportNames = exported . get ( localName ) || [ ] ;
if ( exportNames . length > 0 ) {
const statement = expressionStatement ( buildBindingExportAssignmentExpression ( metadata , exportNames , identifier ( localName ) , path . scope ) ) ;
statement . _blockHoist = path . node . _blockHoist ;
requeueInParent ( path . insertAfter ( statement ) [ 0 ] ) ;
}
} ) ;
}
} ;
const buildBindingExportAssignmentExpression = ( metadata , exportNames , localExpr , scope ) => {
const exportsObjectName = metadata . exportName ;
for ( let currentScope = scope ; currentScope != null ; currentScope = currentScope . parent ) {
if ( currentScope . hasOwnBinding ( exportsObjectName ) ) {
currentScope . rename ( exportsObjectName ) ;
}
}
return ( exportNames || [ ] ) . reduce ( ( expr , exportName ) => {
const {
stringSpecifiers
} = metadata ;
const computed = stringSpecifiers . has ( exportName ) ;
return assignmentExpression ( "=" , memberExpression ( identifier ( exportsObjectName ) , computed ? stringLiteral ( exportName ) : identifier ( exportName ) , computed ) , expr ) ;
} , localExpr ) ;
} ;
const buildImportThrow = localName => {
return _template . default . expression . ast `
( function ( ) {
throw new Error ( '"' + '${localName}' + '" is read-only.' ) ;
} ) ( )
` ;
} ;
const rewriteReferencesVisitor = {
ReferencedIdentifier ( path ) {
const {
seen ,
buildImportReference ,
scope ,
imported ,
requeueInParent
} = this ;
if ( seen . has ( path . node ) ) return ;
seen . add ( path . node ) ;
const localName = path . node . name ;
const importData = imported . get ( localName ) ;
if ( importData ) {
if ( isInType ( path ) ) {
throw path . buildCodeFrameError ( ` Cannot transform the imported binding " ${ localName } " since it's also used in a type annotation. ` + ` Please strip type annotations using @babel/preset-typescript or @babel/preset-flow. ` ) ;
}
const localBinding = path . scope . getBinding ( localName ) ;
const rootBinding = scope . getBinding ( localName ) ;
if ( rootBinding !== localBinding ) return ;
const ref = buildImportReference ( importData , path . node ) ;
ref . loc = path . node . loc ;
if ( ( path . parentPath . isCallExpression ( {
callee : path . node
} ) || path . parentPath . isOptionalCallExpression ( {
callee : path . node
} ) || path . parentPath . isTaggedTemplateExpression ( {
tag : path . node
} ) ) && isMemberExpression ( ref ) ) {
path . replaceWith ( sequenceExpression ( [ numericLiteral ( 0 ) , ref ] ) ) ;
} else if ( path . isJSXIdentifier ( ) && isMemberExpression ( ref ) ) {
const {
object ,
property
} = ref ;
path . replaceWith ( jsxMemberExpression ( jsxIdentifier ( object . name ) , jsxIdentifier ( property . name ) ) ) ;
} else {
path . replaceWith ( ref ) ;
}
requeueInParent ( path ) ;
path . skip ( ) ;
}
} ,
UpdateExpression ( path ) {
const {
scope ,
seen ,
imported ,
exported ,
requeueInParent ,
buildImportReference
} = this ;
if ( seen . has ( path . node ) ) return ;
seen . add ( path . node ) ;
const arg = path . get ( "argument" ) ;
if ( arg . isMemberExpression ( ) ) return ;
const update = path . node ;
if ( arg . isIdentifier ( ) ) {
const localName = arg . node . name ;
if ( scope . getBinding ( localName ) !== path . scope . getBinding ( localName ) ) {
return ;
}
const exportedNames = exported . get ( localName ) ;
const importData = imported . get ( localName ) ;
if ( ( exportedNames == null ? void 0 : exportedNames . length ) > 0 || importData ) {
if ( importData ) {
path . replaceWith ( assignmentExpression ( update . operator [ 0 ] + "=" , buildImportReference ( importData , arg . node ) , buildImportThrow ( localName ) ) ) ;
} else if ( update . prefix ) {
path . replaceWith ( buildBindingExportAssignmentExpression ( this . metadata , exportedNames , cloneNode ( update ) , path . scope ) ) ;
} else {
const ref = scope . generateDeclaredUidIdentifier ( localName ) ;
path . replaceWith ( sequenceExpression ( [ assignmentExpression ( "=" , cloneNode ( ref ) , cloneNode ( update ) ) , buildBindingExportAssignmentExpression ( this . metadata , exportedNames , identifier ( localName ) , path . scope ) , cloneNode ( ref ) ] ) ) ;
}
}
}
requeueInParent ( path ) ;
path . skip ( ) ;
} ,
AssignmentExpression : {
exit ( path ) {
const {
scope ,
seen ,
imported ,
exported ,
requeueInParent ,
buildImportReference
} = this ;
if ( seen . has ( path . node ) ) return ;
seen . add ( path . node ) ;
const left = path . get ( "left" ) ;
if ( left . isMemberExpression ( ) ) return ;
if ( left . isIdentifier ( ) ) {
const localName = left . node . name ;
if ( scope . getBinding ( localName ) !== path . scope . getBinding ( localName ) ) {
return ;
}
const exportedNames = exported . get ( localName ) ;
const importData = imported . get ( localName ) ;
if ( ( exportedNames == null ? void 0 : exportedNames . length ) > 0 || importData ) {
_assert ( path . node . operator === "=" , "Path was not simplified" ) ;
const assignment = path . node ;
if ( importData ) {
assignment . left = buildImportReference ( importData , left . node ) ;
assignment . right = sequenceExpression ( [ assignment . right , buildImportThrow ( localName ) ] ) ;
}
path . replaceWith ( buildBindingExportAssignmentExpression ( this . metadata , exportedNames , assignment , path . scope ) ) ;
requeueInParent ( path ) ;
}
} else {
const ids = left . getOuterBindingIdentifiers ( ) ;
const programScopeIds = Object . keys ( ids ) . filter ( localName => scope . getBinding ( localName ) === path . scope . getBinding ( localName ) ) ;
const id = programScopeIds . find ( localName => imported . has ( localName ) ) ;
if ( id ) {
path . node . right = sequenceExpression ( [ path . node . right , buildImportThrow ( id ) ] ) ;
}
const items = [ ] ;
programScopeIds . forEach ( localName => {
const exportedNames = exported . get ( localName ) || [ ] ;
if ( exportedNames . length > 0 ) {
items . push ( buildBindingExportAssignmentExpression ( this . metadata , exportedNames , identifier ( localName ) , path . scope ) ) ;
}
} ) ;
if ( items . length > 0 ) {
let node = sequenceExpression ( items ) ;
if ( path . parentPath . isExpressionStatement ( ) ) {
node = expressionStatement ( node ) ;
node . _blockHoist = path . parentPath . node . _blockHoist ;
}
const statement = path . insertAfter ( node ) [ 0 ] ;
requeueInParent ( statement ) ;
}
}
}
} ,
"ForOfStatement|ForInStatement" ( path ) {
const {
scope ,
node
} = path ;
const {
left
} = node ;
const {
exported ,
imported ,
scope : programScope
} = this ;
if ( ! isVariableDeclaration ( left ) ) {
let didTransformExport = false ,
importConstViolationName ;
const loopBodyScope = path . get ( "body" ) . scope ;
for ( const name of Object . keys ( getOuterBindingIdentifiers ( left ) ) ) {
if ( programScope . getBinding ( name ) === scope . getBinding ( name ) ) {
if ( exported . has ( name ) ) {
didTransformExport = true ;
if ( loopBodyScope . hasOwnBinding ( name ) ) {
loopBodyScope . rename ( name ) ;
}
}
if ( imported . has ( name ) && ! importConstViolationName ) {
importConstViolationName = name ;
}
}
}
if ( ! didTransformExport && ! importConstViolationName ) {
return ;
}
path . ensureBlock ( ) ;
const bodyPath = path . get ( "body" ) ;
const newLoopId = scope . generateUidIdentifierBasedOnNode ( left ) ;
path . get ( "left" ) . replaceWith ( variableDeclaration ( "let" , [ variableDeclarator ( cloneNode ( newLoopId ) ) ] ) ) ;
scope . registerDeclaration ( path . get ( "left" ) ) ;
if ( didTransformExport ) {
bodyPath . unshiftContainer ( "body" , expressionStatement ( assignmentExpression ( "=" , left , newLoopId ) ) ) ;
}
if ( importConstViolationName ) {
bodyPath . unshiftContainer ( "body" , expressionStatement ( buildImportThrow ( importConstViolationName ) ) ) ;
}
}
}
} ;
//# sourceMappingURL=rewrite-live-references.js.map