Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F91594335
DefinePlugin.js
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Tue, Nov 12, 13:49
Size
9 KB
Mime Type
text/x-c++
Expires
Thu, Nov 14, 13:49 (2 d)
Engine
blob
Format
Raw Data
Handle
22290171
Attached To
rOACCT Open Access Compliance Check Tool (OACCT)
DefinePlugin.js
View Options
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
"use strict"
;
const
RuntimeGlobals
=
require
(
"./RuntimeGlobals"
);
const
ConstDependency
=
require
(
"./dependencies/ConstDependency"
);
const
BasicEvaluatedExpression
=
require
(
"./javascript/BasicEvaluatedExpression"
);
const
{
approve
,
evaluateToString
,
toConstantDependency
}
=
require
(
"./javascript/JavascriptParserHelpers"
);
/** @typedef {import("estree").Expression} Expression */
/** @typedef {import("./Compiler")} Compiler */
/** @typedef {import("./RuntimeTemplate")} RuntimeTemplate */
/** @typedef {import("./javascript/JavascriptParser")} JavascriptParser */
/** @typedef {null|undefined|RegExp|Function|string|number|boolean|bigint|undefined} CodeValuePrimitive */
/** @typedef {RecursiveArrayOrRecord<CodeValuePrimitive|RuntimeValue>} CodeValue */
class
RuntimeValue
{
constructor
(
fn
,
fileDependencies
)
{
this
.
fn
=
fn
;
this
.
fileDependencies
=
fileDependencies
||
[];
}
exec
(
parser
)
{
const
buildInfo
=
parser
.
state
.
module
.
buildInfo
;
if
(
this
.
fileDependencies
===
true
)
{
buildInfo
.
cacheable
=
false
;
}
else
{
for
(
const
fileDependency
of
this
.
fileDependencies
)
{
buildInfo
.
fileDependencies
.
add
(
fileDependency
);
}
}
return
this
.
fn
({
module
:
parser
.
state
.
module
});
}
}
/**
* @param {any[]|{[k: string]: any}} obj obj
* @param {JavascriptParser} parser Parser
* @param {RuntimeTemplate} runtimeTemplate the runtime template
* @param {boolean|undefined|null=} asiSafe asi safe (undefined: unknown, null: unneeded)
* @returns {string} code converted to string that evaluates
*/
const
stringifyObj
=
(
obj
,
parser
,
runtimeTemplate
,
asiSafe
)
=>
{
let
code
;
let
arr
=
Array
.
isArray
(
obj
);
if
(
arr
)
{
code
=
`
[
$
{
obj
.
map
(
code
=>
toCode
(
code
,
parser
,
runtimeTemplate
,
null
))
.
join
(
","
)}]
`
;
}
else
{
code
=
`
{
$
{
Object
.
keys
(
obj
)
.
map
(
key
=>
{
const
code
=
obj
[
key
];
return
(
JSON
.
stringify
(
key
)
+
":"
+
toCode
(
code
,
parser
,
runtimeTemplate
,
null
)
);
})
.
join
(
","
)}}
`
;
}
switch
(
asiSafe
)
{
case
null
:
return
code
;
case
true
:
return
arr
?
code
:
`
(
$
{
code
})
`
;
case
false
:
return
arr
?
`
;
$
{
code
}
`
:
`
;(
$
{
code
})
`
;
default
:
return
`
Object
(
$
{
code
})
`
;
}
};
/**
* Convert code to a string that evaluates
* @param {CodeValue} code Code to evaluate
* @param {JavascriptParser} parser Parser
* @param {RuntimeTemplate} runtimeTemplate the runtime template
* @param {boolean|undefined|null=} asiSafe asi safe (undefined: unknown, null: unneeded)
* @returns {string} code converted to string that evaluates
*/
const
toCode
=
(
code
,
parser
,
runtimeTemplate
,
asiSafe
)
=>
{
if
(
code
===
null
)
{
return
"null"
;
}
if
(
code
===
undefined
)
{
return
"undefined"
;
}
if
(
Object
.
is
(
code
,
-
0
))
{
return
"-0"
;
}
if
(
code
instanceof
RuntimeValue
)
{
return
toCode
(
code
.
exec
(
parser
),
parser
,
runtimeTemplate
,
asiSafe
);
}
if
(
code
instanceof
RegExp
&&
code
.
toString
)
{
return
code
.
toString
();
}
if
(
typeof
code
===
"function"
&&
code
.
toString
)
{
return
"("
+
code
.
toString
()
+
")"
;
}
if
(
typeof
code
===
"object"
)
{
return
stringifyObj
(
code
,
parser
,
runtimeTemplate
,
asiSafe
);
}
if
(
typeof
code
===
"bigint"
)
{
return
runtimeTemplate
.
supportsBigIntLiteral
()
?
`
$
{
code
}
n
`
:
`
BigInt
(
"${code}"
)
`
;
}
return
code
+
""
;
};
class
DefinePlugin
{
/**
* Create a new define plugin
* @param {Record<string, CodeValue>} definitions A map of global object definitions
*/
constructor
(
definitions
)
{
this
.
definitions
=
definitions
;
}
static
runtimeValue
(
fn
,
fileDependencies
)
{
return
new
RuntimeValue
(
fn
,
fileDependencies
);
}
/**
* Apply the plugin
* @param {Compiler} compiler the compiler instance
* @returns {void}
*/
apply
(
compiler
)
{
const
definitions
=
this
.
definitions
;
compiler
.
hooks
.
compilation
.
tap
(
"DefinePlugin"
,
(
compilation
,
{
normalModuleFactory
})
=>
{
compilation
.
dependencyTemplates
.
set
(
ConstDependency
,
new
ConstDependency
.
Template
()
);
const
{
runtimeTemplate
}
=
compilation
;
/**
* Handler
* @param {JavascriptParser} parser Parser
* @returns {void}
*/
const
handler
=
parser
=>
{
/**
* Walk definitions
* @param {Object} definitions Definitions map
* @param {string} prefix Prefix string
* @returns {void}
*/
const
walkDefinitions
=
(
definitions
,
prefix
)
=>
{
Object
.
keys
(
definitions
).
forEach
(
key
=>
{
const
code
=
definitions
[
key
];
if
(
code
&&
typeof
code
===
"object"
&&
!
(
code
instanceof
RuntimeValue
)
&&
!
(
code
instanceof
RegExp
)
)
{
walkDefinitions
(
code
,
prefix
+
key
+
"."
);
applyObjectDefine
(
prefix
+
key
,
code
);
return
;
}
applyDefineKey
(
prefix
,
key
);
applyDefine
(
prefix
+
key
,
code
);
});
};
/**
* Apply define key
* @param {string} prefix Prefix
* @param {string} key Key
* @returns {void}
*/
const
applyDefineKey
=
(
prefix
,
key
)
=>
{
const
splittedKey
=
key
.
split
(
"."
);
splittedKey
.
slice
(
1
).
forEach
((
_
,
i
)
=>
{
const
fullKey
=
prefix
+
splittedKey
.
slice
(
0
,
i
+
1
).
join
(
"."
);
parser
.
hooks
.
canRename
.
for
(
fullKey
).
tap
(
"DefinePlugin"
,
approve
);
});
};
/**
* Apply Code
* @param {string} key Key
* @param {CodeValue} code Code
* @returns {void}
*/
const
applyDefine
=
(
key
,
code
)
=>
{
const
isTypeof
=
/^typeof\s+/
.
test
(
key
);
if
(
isTypeof
)
key
=
key
.
replace
(
/^typeof\s+/
,
""
);
let
recurse
=
false
;
let
recurseTypeof
=
false
;
if
(
!
isTypeof
)
{
parser
.
hooks
.
canRename
.
for
(
key
).
tap
(
"DefinePlugin"
,
approve
);
parser
.
hooks
.
evaluateIdentifier
.
for
(
key
)
.
tap
(
"DefinePlugin"
,
expr
=>
{
/**
* this is needed in case there is a recursion in the DefinePlugin
* to prevent an endless recursion
* e.g.: new DefinePlugin({
* "a": "b",
* "b": "a"
* });
*/
if
(
recurse
)
return
;
recurse
=
true
;
const
res
=
parser
.
evaluate
(
toCode
(
code
,
parser
,
runtimeTemplate
,
null
)
);
recurse
=
false
;
res
.
setRange
(
expr
.
range
);
return
res
;
});
parser
.
hooks
.
expression
.
for
(
key
).
tap
(
"DefinePlugin"
,
expr
=>
{
const
strCode
=
toCode
(
code
,
parser
,
runtimeTemplate
,
!
parser
.
isAsiPosition
(
expr
.
range
[
0
])
);
if
(
/__webpack_require__\s*(!?\.)/
.
test
(
strCode
))
{
return
toConstantDependency
(
parser
,
strCode
,
[
RuntimeGlobals
.
require
])(
expr
);
}
else
if
(
/__webpack_require__/
.
test
(
strCode
))
{
return
toConstantDependency
(
parser
,
strCode
,
[
RuntimeGlobals
.
requireScope
])(
expr
);
}
else
{
return
toConstantDependency
(
parser
,
strCode
)(
expr
);
}
});
}
parser
.
hooks
.
evaluateTypeof
.
for
(
key
).
tap
(
"DefinePlugin"
,
expr
=>
{
/**
* this is needed in case there is a recursion in the DefinePlugin
* to prevent an endless recursion
* e.g.: new DefinePlugin({
* "typeof a": "typeof b",
* "typeof b": "typeof a"
* });
*/
if
(
recurseTypeof
)
return
;
recurseTypeof
=
true
;
const
typeofCode
=
isTypeof
?
toCode
(
code
,
parser
,
runtimeTemplate
,
null
)
:
"typeof ("
+
toCode
(
code
,
parser
,
runtimeTemplate
,
null
)
+
")"
;
const
res
=
parser
.
evaluate
(
typeofCode
);
recurseTypeof
=
false
;
res
.
setRange
(
expr
.
range
);
return
res
;
});
parser
.
hooks
.
typeof
.
for
(
key
).
tap
(
"DefinePlugin"
,
expr
=>
{
const
typeofCode
=
isTypeof
?
toCode
(
code
,
parser
,
runtimeTemplate
,
null
)
:
"typeof ("
+
toCode
(
code
,
parser
,
runtimeTemplate
,
null
)
+
")"
;
const
res
=
parser
.
evaluate
(
typeofCode
);
if
(
!
res
.
isString
())
return
;
return
toConstantDependency
(
parser
,
JSON
.
stringify
(
res
.
string
)
).
bind
(
parser
)(
expr
);
});
};
/**
* Apply Object
* @param {string} key Key
* @param {Object} obj Object
* @returns {void}
*/
const
applyObjectDefine
=
(
key
,
obj
)
=>
{
parser
.
hooks
.
canRename
.
for
(
key
).
tap
(
"DefinePlugin"
,
approve
);
parser
.
hooks
.
evaluateIdentifier
.
for
(
key
)
.
tap
(
"DefinePlugin"
,
expr
=>
new
BasicEvaluatedExpression
()
.
setTruthy
()
.
setSideEffects
(
false
)
.
setRange
(
expr
.
range
)
);
parser
.
hooks
.
evaluateTypeof
.
for
(
key
)
.
tap
(
"DefinePlugin"
,
evaluateToString
(
"object"
));
parser
.
hooks
.
expression
.
for
(
key
).
tap
(
"DefinePlugin"
,
expr
=>
{
const
strCode
=
stringifyObj
(
obj
,
parser
,
runtimeTemplate
,
!
parser
.
isAsiPosition
(
expr
.
range
[
0
])
);
if
(
/__webpack_require__\s*(!?\.)/
.
test
(
strCode
))
{
return
toConstantDependency
(
parser
,
strCode
,
[
RuntimeGlobals
.
require
])(
expr
);
}
else
if
(
/__webpack_require__/
.
test
(
strCode
))
{
return
toConstantDependency
(
parser
,
strCode
,
[
RuntimeGlobals
.
requireScope
])(
expr
);
}
else
{
return
toConstantDependency
(
parser
,
strCode
)(
expr
);
}
});
parser
.
hooks
.
typeof
.
for
(
key
)
.
tap
(
"DefinePlugin"
,
toConstantDependency
(
parser
,
JSON
.
stringify
(
"object"
))
);
};
walkDefinitions
(
definitions
,
""
);
};
normalModuleFactory
.
hooks
.
parser
.
for
(
"javascript/auto"
)
.
tap
(
"DefinePlugin"
,
handler
);
normalModuleFactory
.
hooks
.
parser
.
for
(
"javascript/dynamic"
)
.
tap
(
"DefinePlugin"
,
handler
);
normalModuleFactory
.
hooks
.
parser
.
for
(
"javascript/esm"
)
.
tap
(
"DefinePlugin"
,
handler
);
}
);
}
}
module
.
exports
=
DefinePlugin
;
Event Timeline
Log In to Comment