2015-01-13 00:45:30 +08:00
/ *
MIT License http : //www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @ sokra
* /
2018-07-30 23:08:51 +08:00
2017-01-03 05:30:08 +08:00
"use strict" ;
2025-07-02 20:02:03 +08:00
const WebpackError = require ( "../WebpackError" ) ;
2024-10-31 22:43:31 +08:00
const { getImportAttributes } = require ( "../javascript/JavascriptParser" ) ;
2020-01-29 21:24:55 +08:00
const InnerGraph = require ( "../optimize/InnerGraph" ) ;
2018-07-30 23:08:51 +08:00
const ConstDependency = require ( "./ConstDependency" ) ;
2017-01-03 05:30:08 +08:00
const HarmonyExportExpressionDependency = require ( "./HarmonyExportExpressionDependency" ) ;
const HarmonyExportHeaderDependency = require ( "./HarmonyExportHeaderDependency" ) ;
const HarmonyExportImportedSpecifierDependency = require ( "./HarmonyExportImportedSpecifierDependency" ) ;
2018-07-30 23:08:51 +08:00
const HarmonyExportSpecifierDependency = require ( "./HarmonyExportSpecifierDependency" ) ;
2021-11-03 01:16:59 +08:00
const { ExportPresenceModes } = require ( "./HarmonyImportDependency" ) ;
2019-09-03 20:11:50 +08:00
const {
2025-07-03 17:06:45 +08:00
getImportMode ,
harmonySpecifierTag
2019-09-03 20:11:50 +08:00
} = require ( "./HarmonyImportDependencyParserPlugin" ) ;
2018-07-30 23:08:51 +08:00
const HarmonyImportSideEffectDependency = require ( "./HarmonyImportSideEffectDependency" ) ;
2015-01-13 00:45:30 +08:00
2024-03-18 23:28:40 +08:00
/** @typedef {import("../Dependency").DependencyLocation} DependencyLocation */
2023-06-17 03:44:20 +08:00
/** @typedef {import("../javascript/JavascriptParser")} JavascriptParser */
2025-04-07 21:09:05 +08:00
/** @typedef {import("../javascript/JavascriptParser").ClassDeclaration} ClassDeclaration */
2024-03-14 23:15:13 +08:00
/** @typedef {import("../javascript/JavascriptParser").FunctionDeclaration} FunctionDeclaration */
2024-03-18 23:28:40 +08:00
/** @typedef {import("../javascript/JavascriptParser").Range} Range */
2025-09-09 23:41:52 +08:00
/** @typedef {import("./HarmonyImportDependencyParserPlugin").HarmonySettings} HarmonySettings */
2023-06-17 03:44:20 +08:00
2021-04-13 23:33:05 +08:00
const { HarmonyStarExportsList } = HarmonyExportImportedSpecifierDependency ;
2025-06-04 02:20:37 +08:00
const PLUGIN _NAME = "HarmonyExportDependencyParserPlugin" ;
2017-01-03 05:30:08 +08:00
module . exports = class HarmonyExportDependencyParserPlugin {
2023-05-22 08:03:05 +08:00
/ * *
* @ param { import ( "../../declarations/WebpackOptions" ) . JavascriptParserOptions } options options
* /
2025-07-28 20:18:09 +08:00
constructor ( options ) {
2021-11-03 01:16:59 +08:00
this . exportPresenceMode =
2021-11-06 08:01:21 +08:00
options . reexportExportsPresence !== undefined
? ExportPresenceModes . fromUserOption ( options . reexportExportsPresence )
: options . exportsPresence !== undefined
2024-01-14 09:41:34 +08:00
? ExportPresenceModes . fromUserOption ( options . exportsPresence )
: options . strictExportPresence
? ExportPresenceModes . ERROR
: ExportPresenceModes . AUTO ;
2025-07-28 20:18:09 +08:00
this . deferImport = options . deferImport ;
2017-11-23 21:10:52 +08:00
}
2024-03-14 23:15:13 +08:00
/ * *
* @ param { JavascriptParser } parser the parser
* @ returns { void }
* /
2017-01-03 05:30:08 +08:00
apply ( parser ) {
2021-11-03 01:16:59 +08:00
const { exportPresenceMode } = this ;
2025-07-17 00:13:14 +08:00
parser . hooks . export . tap ( PLUGIN _NAME , ( statement ) => {
2025-06-04 02:20:37 +08:00
const dep = new HarmonyExportHeaderDependency (
/** @type {Range | false} */ (
statement . declaration && statement . declaration . range
) ,
/** @type {Range} */ ( statement . range )
) ;
dep . loc = Object . create (
/** @type {DependencyLocation} */ ( statement . loc )
) ;
dep . loc . index = - 1 ;
parser . state . module . addPresentationalDependency ( dep ) ;
return true ;
} ) ;
parser . hooks . exportImport . tap ( PLUGIN _NAME , ( statement , source ) => {
parser . state . lastHarmonyImportOrder =
( parser . state . lastHarmonyImportOrder || 0 ) + 1 ;
const clearDep = new ConstDependency (
"" ,
/** @type {Range} */ ( statement . range )
) ;
clearDep . loc = /** @type {DependencyLocation} */ ( statement . loc ) ;
clearDep . loc . index = - 1 ;
parser . state . module . addPresentationalDependency ( clearDep ) ;
2025-07-25 23:14:00 +08:00
let defer = false ;
if ( this . deferImport ) {
( { defer } = getImportMode ( parser , statement ) ) ;
if ( defer ) {
const error = new WebpackError (
"Deferred re-export (`export defer * as namespace from '...'`) is not a part of the Import Defer proposal.\nUse the following code instead:\n import defer * as namespace from '...';\n export { namespace };"
) ;
error . loc = statement . loc || undefined ;
parser . state . current . addError ( error ) ;
}
2025-07-02 20:02:03 +08:00
}
2025-06-04 02:20:37 +08:00
const sideEffectDep = new HarmonyImportSideEffectDependency (
/** @type {string} */ ( source ) ,
parser . state . lastHarmonyImportOrder ,
2025-07-02 20:02:03 +08:00
getImportAttributes ( statement ) ,
defer
2025-06-04 02:20:37 +08:00
) ;
sideEffectDep . loc = Object . create (
/** @type {DependencyLocation} */ ( statement . loc )
) ;
sideEffectDep . loc . index = - 1 ;
parser . state . current . addDependency ( sideEffectDep ) ;
return true ;
} ) ;
parser . hooks . exportExpression . tap ( PLUGIN _NAME , ( statement , node ) => {
const isFunctionDeclaration = node . type === "FunctionDeclaration" ;
const exprRange = /** @type {Range} */ ( node . range ) ;
const statementRange = /** @type {Range} */ ( statement . range ) ;
const comments = parser . getComments ( [ statementRange [ 0 ] , exprRange [ 0 ] ] ) ;
const dep = new HarmonyExportExpressionDependency (
exprRange ,
statementRange ,
comments
2025-07-17 00:13:14 +08:00
. map ( ( c ) => {
2025-06-04 02:20:37 +08:00
switch ( c . type ) {
case "Block" :
return ` /* ${ c . value } */ ` ;
case "Line" :
return ` // ${ c . value } \n ` ;
}
return "" ;
} )
. join ( "" ) ,
node . type . endsWith ( "Declaration" ) &&
/** @type {FunctionDeclaration | ClassDeclaration} */ ( node ) . id
? /** @type {FunctionDeclaration | ClassDeclaration} */
( node ) . id . name
: isFunctionDeclaration
? {
range : [
exprRange [ 0 ] ,
node . params . length > 0
? /** @type {Range} */ ( node . params [ 0 ] . range ) [ 0 ]
: /** @type {Range} */ ( node . body . range ) [ 0 ]
] ,
prefix : ` ${ node . async ? "async " : "" } function ${
node . generator ? "*" : ""
} ` ,
suffix : ` ( ${ node . params . length > 0 ? "" : ") " } `
2018-09-17 20:58:55 +08:00
}
2025-06-04 02:20:37 +08:00
: undefined
) ;
dep . loc = Object . create (
/** @type {DependencyLocation} */ ( statement . loc )
) ;
dep . loc . index = - 1 ;
parser . state . current . addDependency ( dep ) ;
InnerGraph . addVariableUsage (
parser ,
node . type . endsWith ( "Declaration" ) &&
2025-04-07 21:09:05 +08:00
/** @type {FunctionDeclaration | ClassDeclaration} */ ( node ) . id
2025-06-04 02:20:37 +08:00
? /** @type {FunctionDeclaration | ClassDeclaration} */ ( node ) . id . name
: "*default*" ,
"default"
) ;
return true ;
} ) ;
2018-02-25 09:00:20 +08:00
parser . hooks . exportSpecifier . tap (
2025-06-04 02:20:37 +08:00
PLUGIN _NAME ,
2018-02-25 09:00:20 +08:00
( statement , id , name , idx ) => {
2025-09-09 23:41:52 +08:00
const settings =
/** @type {HarmonySettings} */
( parser . getTagData ( id , harmonySpecifierTag ) ) ;
2018-02-25 09:00:20 +08:00
const harmonyNamedExports = ( parser . state . harmonyNamedExports =
parser . state . harmonyNamedExports || new Set ( ) ) ;
2017-10-09 21:28:59 +08:00
harmonyNamedExports . add ( name ) ;
2020-01-29 21:24:55 +08:00
InnerGraph . addVariableUsage ( parser , id , name ) ;
2024-08-02 02:36:27 +08:00
const dep = settings
? new HarmonyExportImportedSpecifierDependency (
settings . source ,
settings . sourceOrder ,
settings . ids ,
name ,
harmonyNamedExports ,
null ,
exportPresenceMode ,
null ,
2025-07-02 20:02:03 +08:00
settings . attributes ,
settings . defer
2024-08-02 02:36:27 +08:00
)
: new HarmonyExportSpecifierDependency ( id , name ) ;
2024-03-18 23:28:40 +08:00
dep . loc = Object . create (
/** @type {DependencyLocation} */ ( statement . loc )
) ;
2018-02-25 09:00:20 +08:00
dep . loc . index = idx ;
2024-08-15 20:32:58 +08:00
const isAsiSafe = ! parser . isAsiPosition (
/** @type {Range} */
( statement . range ) [ 0 ]
) ;
if ( ! isAsiSafe ) {
parser . setAsiPosition ( /** @type {Range} */ ( statement . range ) [ 1 ] ) ;
}
2018-02-25 09:00:20 +08:00
parser . state . current . addDependency ( dep ) ;
return true ;
2017-10-09 21:28:59 +08:00
}
2018-02-25 09:00:20 +08:00
) ;
parser . hooks . exportImportSpecifier . tap (
2025-06-04 02:20:37 +08:00
PLUGIN _NAME ,
2018-02-25 09:00:20 +08:00
( statement , source , id , name , idx ) => {
const harmonyNamedExports = ( parser . state . harmonyNamedExports =
parser . state . harmonyNamedExports || new Set ( ) ) ;
2025-07-03 17:06:45 +08:00
/** @type {InstanceType<HarmonyStarExportsList> | null} */
2018-02-25 09:00:20 +08:00
let harmonyStarExports = null ;
if ( name ) {
harmonyNamedExports . add ( name ) ;
} else {
harmonyStarExports = parser . state . harmonyStarExports =
2021-04-13 23:33:05 +08:00
parser . state . harmonyStarExports || new HarmonyStarExportsList ( ) ;
2018-02-25 09:00:20 +08:00
}
2025-03-07 04:02:09 +08:00
const attributes = getImportAttributes ( statement ) ;
2025-07-25 23:14:00 +08:00
const defer = this . deferImport
? getImportMode ( parser , statement ) . defer
: false ;
2018-02-25 09:00:20 +08:00
const dep = new HarmonyExportImportedSpecifierDependency (
2025-07-03 17:06:45 +08:00
/** @type {string} */
( source ) ,
2018-02-25 09:00:20 +08:00
parser . state . lastHarmonyImportOrder ,
2019-03-14 19:06:59 +08:00
id ? [ id ] : [ ] ,
2018-02-25 09:00:20 +08:00
name ,
harmonyNamedExports ,
2025-07-03 17:06:45 +08:00
// eslint-disable-next-line unicorn/prefer-spread
2018-02-25 09:00:20 +08:00
harmonyStarExports && harmonyStarExports . slice ( ) ,
2021-11-03 01:16:59 +08:00
exportPresenceMode ,
2025-03-07 04:02:09 +08:00
harmonyStarExports ,
2025-07-02 20:02:03 +08:00
attributes ,
defer
2018-02-25 09:00:20 +08:00
) ;
if ( harmonyStarExports ) {
harmonyStarExports . push ( dep ) ;
}
2024-03-18 23:28:40 +08:00
dep . loc = Object . create (
/** @type {DependencyLocation} */ ( statement . loc )
) ;
2018-02-25 09:00:20 +08:00
dep . loc . index = idx ;
2024-08-14 19:47:21 +08:00
const isAsiSafe = ! parser . isAsiPosition (
/** @type {Range} */
( statement . range ) [ 0 ]
) ;
if ( ! isAsiSafe ) {
parser . setAsiPosition ( /** @type {Range} */ ( statement . range ) [ 1 ] ) ;
}
2018-02-25 09:00:20 +08:00
parser . state . current . addDependency ( dep ) ;
return true ;
2017-10-09 21:28:59 +08:00
}
2018-02-25 09:00:20 +08:00
) ;
2015-01-13 00:45:30 +08:00
}
2017-01-03 05:30:08 +08:00
} ;