Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F95426226
index.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
Sun, Dec 15, 15:51
Size
28 KB
Mime Type
text/x-c++
Expires
Tue, Dec 17, 15:51 (2 d)
Engine
blob
Format
Raw Data
Handle
22985288
Attached To
rOACCT Open Access Compliance Check Tool (OACCT)
index.js
View Options
"use strict"
;
const
path
=
require
(
"path"
);
const
{
validate
}
=
require
(
"schema-utils"
);
const
serialize
=
require
(
"serialize-javascript"
);
const
normalizePath
=
require
(
"normalize-path"
);
const
globParent
=
require
(
"glob-parent"
);
const
fastGlob
=
require
(
"fast-glob"
);
// @ts-ignore
const
{
version
}
=
require
(
"../package.json"
);
const
schema
=
require
(
"./options.json"
);
const
{
readFile
,
stat
,
throttleAll
}
=
require
(
"./utils"
);
const
template
=
/\[\\*([\w:]+)\\*\]/i
;
/** @typedef {import("schema-utils/declarations/validate").Schema} Schema */
/** @typedef {import("webpack").Compiler} Compiler */
/** @typedef {import("webpack").Compilation} Compilation */
/** @typedef {import("webpack").WebpackError} WebpackError */
/** @typedef {import("webpack").Asset} Asset */
/** @typedef {import("globby").Options} GlobbyOptions */
/** @typedef {import("globby").GlobEntry} GlobEntry */
/** @typedef {ReturnType<Compilation["getLogger"]>} WebpackLogger */
/** @typedef {ReturnType<Compilation["getCache"]>} CacheFacade */
/** @typedef {ReturnType<ReturnType<Compilation["getCache"]>["getLazyHashedEtag"]>} Etag */
/** @typedef {ReturnType<Compilation["fileSystemInfo"]["mergeSnapshots"]>} Snapshot */
/**
* @typedef {boolean} Force
*/
/**
* @typedef {Object} CopiedResult
* @property {string} sourceFilename
* @property {string} absoluteFilename
* @property {string} filename
* @property {Asset["source"]} source
* @property {Force | undefined} force
* @property {Record<string, any>} info
*/
/**
* @typedef {string} StringPattern
*/
/**
* @typedef {boolean} NoErrorOnMissing
*/
/**
* @typedef {string} Context
*/
/**
* @typedef {string} From
*/
/**
* @callback ToFunction
* @param {{ context: string, absoluteFilename?: string }} pathData
* @return {string | Promise<string>}
*/
/**
* @typedef {string | ToFunction} To
*/
/**
* @typedef {"dir" | "file" | "template"} ToType
*/
/**
* @callback TransformerFunction
* @param {Buffer} input
* @param {string} absoluteFilename
* @returns {string | Buffer | Promise<string> | Promise<Buffer>}
*/
/**
* @typedef {{ keys: { [key: string]: any } } | { keys: ((defaultCacheKeys: { [key: string]: any }, absoluteFilename: string) => Promise<{ [key: string]: any }>) }} TransformerCacheObject
*/
/**
* @typedef {Object} TransformerObject
* @property {TransformerFunction} transformer
* @property {boolean | TransformerCacheObject} [cache]
*/
/**
* @typedef {TransformerFunction | TransformerObject} Transform
*/
/**
* @callback Filter
* @param {string} filepath
* @returns {boolean | Promise<boolean>}
*/
/**
* @callback TransformAllFunction
* @param {{ data: Buffer, sourceFilename: string, absoluteFilename: string }[]} data
* @returns {string | Buffer | Promise<string> | Promise<Buffer>}
*/
/**
* @typedef { Record<string, any> | ((item: { absoluteFilename: string, sourceFilename: string, filename: string, toType: ToType }) => Record<string, any>) } Info
*/
/**
* @typedef {Object} ObjectPattern
* @property {From} from
* @property {GlobbyOptions} [globOptions]
* @property {Context} [context]
* @property {To} [to]
* @property {ToType} [toType]
* @property {Info} [info]
* @property {Filter} [filter]
* @property {Transform} [transform]
* @property {TransformAllFunction} [transformAll]
* @property {Force} [force]
* @property {number} [priority]
* @property {NoErrorOnMissing} [noErrorOnMissing]
*/
/**
* @typedef {StringPattern | ObjectPattern} Pattern
*/
/**
* @typedef {Object} AdditionalOptions
* @property {number} [concurrency]
*/
/**
* @typedef {Object} PluginOptions
* @property {Pattern[]} patterns
* @property {AdditionalOptions} [options]
*/
class
CopyPlugin
{
/**
* @param {PluginOptions} [options]
*/
constructor
(
options
=
{
patterns
:
[]
})
{
validate
(
/** @type {Schema} */
schema
,
options
,
{
name
:
"Copy Plugin"
,
baseDataPath
:
"options"
});
/**
* @private
* @type {Pattern[]}
*/
this
.
patterns
=
options
.
patterns
;
/**
* @private
* @type {AdditionalOptions}
*/
this
.
options
=
options
.
options
||
{};
}
/**
* @private
* @param {Compilation} compilation
* @param {number} startTime
* @param {string} dependency
* @returns {Promise<Snapshot | undefined>}
*/
static
async
createSnapshot
(
compilation
,
startTime
,
dependency
)
{
// eslint-disable-next-line consistent-return
return
new
Promise
((
resolve
,
reject
)
=>
{
compilation
.
fileSystemInfo
.
createSnapshot
(
startTime
,
[
dependency
],
// @ts-ignore
// eslint-disable-next-line no-undefined
undefined
,
// eslint-disable-next-line no-undefined
undefined
,
null
,
(
error
,
snapshot
)
=>
{
if
(
error
)
{
reject
(
error
);
return
;
}
resolve
(
/** @type {Snapshot} */
snapshot
);
});
});
}
/**
* @private
* @param {Compilation} compilation
* @param {Snapshot} snapshot
* @returns {Promise<boolean | undefined>}
*/
static
async
checkSnapshotValid
(
compilation
,
snapshot
)
{
// eslint-disable-next-line consistent-return
return
new
Promise
((
resolve
,
reject
)
=>
{
compilation
.
fileSystemInfo
.
checkSnapshotValid
(
snapshot
,
(
error
,
isValid
)
=>
{
if
(
error
)
{
reject
(
error
);
return
;
}
resolve
(
isValid
);
});
});
}
/**
* @private
* @param {Compiler} compiler
* @param {Compilation} compilation
* @param {Buffer} source
* @returns {string}
*/
static
getContentHash
(
compiler
,
compilation
,
source
)
{
const
{
outputOptions
}
=
compilation
;
const
{
hashDigest
,
hashDigestLength
,
hashFunction
,
hashSalt
}
=
outputOptions
;
const
hash
=
compiler
.
webpack
.
util
.
createHash
(
/** @type {string} */
hashFunction
);
if
(
hashSalt
)
{
hash
.
update
(
hashSalt
);
}
hash
.
update
(
source
);
const
fullContentHash
=
hash
.
digest
(
hashDigest
);
return
fullContentHash
.
toString
().
slice
(
0
,
hashDigestLength
);
}
/**
* @private
* @param {typeof import("globby").globby} globby
* @param {Compiler} compiler
* @param {Compilation} compilation
* @param {WebpackLogger} logger
* @param {CacheFacade} cache
* @param {ObjectPattern & { context: string }} inputPattern
* @param {number} index
* @returns {Promise<Array<CopiedResult | undefined> | undefined>}
*/
static
async
runPattern
(
globby
,
compiler
,
compilation
,
logger
,
cache
,
inputPattern
,
index
)
{
const
{
RawSource
}
=
compiler
.
webpack
.
sources
;
const
pattern
=
{
...
inputPattern
};
const
originalFrom
=
pattern
.
from
;
const
normalizedOriginalFrom
=
path
.
normalize
(
originalFrom
);
logger
.
log
(
`
starting
to
process
a
pattern
from
'${normalizedOriginalFrom}'
using
'${pattern.context}'
context
`
);
let
absoluteFrom
;
if
(
path
.
isAbsolute
(
normalizedOriginalFrom
))
{
absoluteFrom
=
normalizedOriginalFrom
;
}
else
{
absoluteFrom
=
path
.
resolve
(
pattern
.
context
,
normalizedOriginalFrom
);
}
logger
.
debug
(
`
getting
stats
for
'${absoluteFrom}'
...
`
);
const
{
inputFileSystem
}
=
compiler
;
let
stats
;
try
{
stats
=
await
stat
(
inputFileSystem
,
absoluteFrom
);
}
catch
(
error
)
{
// Nothing
}
/**
* @type {"file" | "dir" | "glob"}
*/
let
fromType
;
if
(
stats
)
{
if
(
stats
.
isDirectory
())
{
fromType
=
"dir"
;
logger
.
debug
(
`
determined
'${absoluteFrom}'
is
a
directory
`
);
}
else
if
(
stats
.
isFile
())
{
fromType
=
"file"
;
logger
.
debug
(
`
determined
'${absoluteFrom}'
is
a
file
`
);
}
else
{
// Fallback
fromType
=
"glob"
;
logger
.
debug
(
`
determined
'${absoluteFrom}'
is
unknown
`
);
}
}
else
{
fromType
=
"glob"
;
logger
.
debug
(
`
determined
'${absoluteFrom}'
is
a
glob
`
);
}
/** @type {GlobbyOptions & { objectMode: true }} */
const
globOptions
=
{
...{
followSymbolicLinks
:
true
},
...(
pattern
.
globOptions
||
{}),
...{
cwd
:
pattern
.
context
,
objectMode
:
true
}
};
// @ts-ignore
globOptions
.
fs
=
inputFileSystem
;
let
glob
;
switch
(
fromType
)
{
case
"dir"
:
compilation
.
contextDependencies
.
add
(
absoluteFrom
);
logger
.
debug
(
`
added
'${absoluteFrom}'
as
a
context
dependency
`
);
pattern
.
context
=
absoluteFrom
;
glob
=
path
.
posix
.
join
(
fastGlob
.
escapePath
(
normalizePath
(
path
.
resolve
(
absoluteFrom
))),
"**/*"
);
absoluteFrom
=
path
.
join
(
absoluteFrom
,
"**/*"
);
if
(
typeof
globOptions
.
dot
===
"undefined"
)
{
globOptions
.
dot
=
true
;
}
break
;
case
"file"
:
compilation
.
fileDependencies
.
add
(
absoluteFrom
);
logger
.
debug
(
`
added
'${absoluteFrom}'
as
a
file
dependency
`
);
pattern
.
context
=
path
.
dirname
(
absoluteFrom
);
glob
=
fastGlob
.
escapePath
(
normalizePath
(
path
.
resolve
(
absoluteFrom
)));
if
(
typeof
globOptions
.
dot
===
"undefined"
)
{
globOptions
.
dot
=
true
;
}
break
;
case
"glob"
:
default
:
{
const
contextDependencies
=
path
.
normalize
(
globParent
(
absoluteFrom
));
compilation
.
contextDependencies
.
add
(
contextDependencies
);
logger
.
debug
(
`
added
'${contextDependencies}'
as
a
context
dependency
`
);
glob
=
path
.
isAbsolute
(
originalFrom
)
?
originalFrom
:
path
.
posix
.
join
(
fastGlob
.
escapePath
(
normalizePath
(
path
.
resolve
(
pattern
.
context
))),
originalFrom
);
}
}
logger
.
log
(
`
begin
globbing
'${glob}'
...
`
);
/**
* @type {GlobEntry[]}
*/
let
globEntries
;
try
{
globEntries
=
await
globby
(
glob
,
globOptions
);
}
catch
(
error
)
{
compilation
.
errors
.
push
(
/** @type {WebpackError} */
error
);
return
;
}
if
(
globEntries
.
length
===
0
)
{
if
(
pattern
.
noErrorOnMissing
)
{
logger
.
log
(
`
finished
to
process
a
pattern
from
'${normalizedOriginalFrom}'
using
'${pattern.context}'
context
to
'${pattern.to}'
`
);
return
;
}
const
missingError
=
new
Error
(
`
unable
to
locate
'${glob}'
glob
`
);
compilation
.
errors
.
push
(
/** @type {WebpackError} */
missingError
);
return
;
}
/**
* @type {Array<CopiedResult | undefined>}
*/
let
copiedResult
;
try
{
copiedResult
=
await
Promise
.
all
(
globEntries
.
map
(
/**
* @param {GlobEntry} globEntry
* @returns {Promise<CopiedResult | undefined>}
*/
async
globEntry
=>
{
// Exclude directories
if
(
!
globEntry
.
dirent
.
isFile
())
{
return
;
}
if
(
pattern
.
filter
)
{
let
isFiltered
;
try
{
isFiltered
=
await
pattern
.
filter
(
globEntry
.
path
);
}
catch
(
error
)
{
compilation
.
errors
.
push
(
/** @type {WebpackError} */
error
);
return
;
}
if
(
!
isFiltered
)
{
logger
.
log
(
`
skip
'${globEntry.path}'
,
because
it
was
filtered
`
);
return
;
}
}
const
from
=
globEntry
.
path
;
logger
.
debug
(
`
found
'${from}'
`
);
// `globby`/`fast-glob` return the relative path when the path contains special characters on windows
const
absoluteFilename
=
path
.
resolve
(
pattern
.
context
,
from
);
const
to
=
typeof
pattern
.
to
===
"function"
?
await
pattern
.
to
({
context
:
pattern
.
context
,
absoluteFilename
})
:
path
.
normalize
(
typeof
pattern
.
to
!==
"undefined"
?
pattern
.
to
:
""
);
const
toType
=
pattern
.
toType
?
pattern
.
toType
:
template
.
test
(
to
)
?
"template"
:
path
.
extname
(
to
)
===
""
||
to
.
slice
(
-
1
)
===
path
.
sep
?
"dir"
:
"file"
;
logger
.
log
(
`
'to'
option
'${to}'
determinated
as
'${toType}'
`
);
const
relativeFrom
=
path
.
relative
(
pattern
.
context
,
absoluteFilename
);
let
filename
=
toType
===
"dir"
?
path
.
join
(
to
,
relativeFrom
)
:
to
;
if
(
path
.
isAbsolute
(
filename
))
{
filename
=
path
.
relative
(
/** @type {string} */
compiler
.
options
.
output
.
path
,
filename
);
}
logger
.
log
(
`
determined
that
'${from}'
should
write
to
'${filename}'
`
);
const
sourceFilename
=
normalizePath
(
path
.
relative
(
compiler
.
context
,
absoluteFilename
));
// If this came from a glob or dir, add it to the file dependencies
if
(
fromType
===
"dir"
||
fromType
===
"glob"
)
{
compilation
.
fileDependencies
.
add
(
absoluteFilename
);
logger
.
debug
(
`
added
'${absoluteFilename}'
as
a
file
dependency
`
);
}
let
cacheEntry
;
logger
.
debug
(
`
getting
cache
for
'${absoluteFilename}'
...
`
);
try
{
cacheEntry
=
await
cache
.
getPromise
(
`
$
{
sourceFilename
}
|
$
{
index
}
`
,
null
);
}
catch
(
error
)
{
compilation
.
errors
.
push
(
/** @type {WebpackError} */
error
);
return
;
}
/**
* @type {Asset["source"] | undefined}
*/
let
source
;
if
(
cacheEntry
)
{
logger
.
debug
(
`
found
cache
for
'${absoluteFilename}'
...
`
);
let
isValidSnapshot
;
logger
.
debug
(
`
checking
snapshot
on
valid
for
'${absoluteFilename}'
...
`
);
try
{
isValidSnapshot
=
await
CopyPlugin
.
checkSnapshotValid
(
compilation
,
cacheEntry
.
snapshot
);
}
catch
(
error
)
{
compilation
.
errors
.
push
(
/** @type {WebpackError} */
error
);
return
;
}
if
(
isValidSnapshot
)
{
logger
.
debug
(
`
snapshot
for
'${absoluteFilename}'
is
valid
`
);
({
source
}
=
cacheEntry
);
}
else
{
logger
.
debug
(
`
snapshot
for
'${absoluteFilename}'
is
invalid
`
);
}
}
else
{
logger
.
debug
(
`
missed
cache
for
'${absoluteFilename}'
`
);
}
if
(
!
source
)
{
const
startTime
=
Date
.
now
();
logger
.
debug
(
`
reading
'${absoluteFilename}'
...
`
);
let
data
;
try
{
data
=
await
readFile
(
inputFileSystem
,
absoluteFilename
);
}
catch
(
error
)
{
compilation
.
errors
.
push
(
/** @type {WebpackError} */
error
);
return
;
}
logger
.
debug
(
`
read
'${absoluteFilename}'
`
);
source
=
new
RawSource
(
data
);
let
snapshot
;
logger
.
debug
(
`
creating
snapshot
for
'${absoluteFilename}'
...
`
);
try
{
snapshot
=
await
CopyPlugin
.
createSnapshot
(
compilation
,
startTime
,
absoluteFilename
);
}
catch
(
error
)
{
compilation
.
errors
.
push
(
/** @type {WebpackError} */
error
);
return
;
}
if
(
snapshot
)
{
logger
.
debug
(
`
created
snapshot
for
'${absoluteFilename}'
`
);
logger
.
debug
(
`
storing
cache
for
'${absoluteFilename}'
...
`
);
try
{
await
cache
.
storePromise
(
`
$
{
sourceFilename
}
|
$
{
index
}
`
,
null
,
{
source
,
snapshot
});
}
catch
(
error
)
{
compilation
.
errors
.
push
(
/** @type {WebpackError} */
error
);
return
;
}
logger
.
debug
(
`
stored
cache
for
'${absoluteFilename}'
`
);
}
}
if
(
pattern
.
transform
)
{
/**
* @type {TransformerObject}
*/
const
transformObj
=
typeof
pattern
.
transform
===
"function"
?
{
transformer
:
pattern
.
transform
}
:
pattern
.
transform
;
if
(
transformObj
.
transformer
)
{
logger
.
log
(
`
transforming
content
for
'${absoluteFilename}'
...
`
);
const
buffer
=
source
.
buffer
();
if
(
transformObj
.
cache
)
{
// TODO: remove in the next major release
const
hasher
=
compiler
.
webpack
&&
compiler
.
webpack
.
util
&&
compiler
.
webpack
.
util
.
createHash
?
compiler
.
webpack
.
util
.
createHash
(
"xxhash64"
)
:
// eslint-disable-next-line global-require
require
(
"crypto"
).
createHash
(
"md4"
);
const
defaultCacheKeys
=
{
version
,
sourceFilename
,
transform
:
transformObj
.
transformer
,
contentHash
:
hasher
.
update
(
buffer
).
digest
(
"hex"
),
index
};
const
cacheKeys
=
`
transform
|
$
{
serialize
(
typeof
transformObj
.
cache
===
"boolean"
?
defaultCacheKeys
:
typeof
transformObj
.
cache
.
keys
===
"function"
?
await
transformObj
.
cache
.
keys
(
defaultCacheKeys
,
absoluteFilename
)
:
{
...
defaultCacheKeys
,
...
transformObj
.
cache
.
keys
})}
`
;
logger
.
debug
(
`
getting
transformation
cache
for
'${absoluteFilename}'
...
`
);
const
cacheItem
=
cache
.
getItemCache
(
cacheKeys
,
cache
.
getLazyHashedEtag
(
source
));
source
=
await
cacheItem
.
getPromise
();
logger
.
debug
(
source
?
`
found
transformation
cache
for
'${absoluteFilename}'
`
:
`
no
transformation
cache
for
'${absoluteFilename}'
`
);
if
(
!
source
)
{
const
transformed
=
await
transformObj
.
transformer
(
buffer
,
absoluteFilename
);
source
=
new
RawSource
(
transformed
);
logger
.
debug
(
`
caching
transformation
for
'${absoluteFilename}'
...
`
);
await
cacheItem
.
storePromise
(
source
);
logger
.
debug
(
`
cached
transformation
for
'${absoluteFilename}'
`
);
}
}
else
{
source
=
new
RawSource
(
await
transformObj
.
transformer
(
buffer
,
absoluteFilename
));
}
}
}
let
info
=
typeof
pattern
.
info
===
"undefined"
?
{}
:
typeof
pattern
.
info
===
"function"
?
pattern
.
info
({
absoluteFilename
,
sourceFilename
,
filename
,
toType
})
||
{}
:
pattern
.
info
||
{};
if
(
toType
===
"template"
)
{
logger
.
log
(
`
interpolating
template
'${filename}'
for
'${sourceFilename}'
...
`
);
const
contentHash
=
CopyPlugin
.
getContentHash
(
compiler
,
compilation
,
source
.
buffer
());
const
ext
=
path
.
extname
(
sourceFilename
);
const
base
=
path
.
basename
(
sourceFilename
);
const
name
=
base
.
slice
(
0
,
base
.
length
-
ext
.
length
);
const
data
=
{
filename
:
normalizePath
(
path
.
relative
(
pattern
.
context
,
absoluteFilename
)),
contentHash
,
chunk
:
{
name
,
id
:
/** @type {string} */
sourceFilename
,
hash
:
contentHash
}
};
const
{
path
:
interpolatedFilename
,
info
:
assetInfo
}
=
compilation
.
getPathWithInfo
(
normalizePath
(
filename
),
data
);
info
=
{
...
info
,
...
assetInfo
};
filename
=
interpolatedFilename
;
logger
.
log
(
`
interpolated
template
'${filename}'
for
'${sourceFilename}'
`
);
}
else
{
filename
=
normalizePath
(
filename
);
}
// eslint-disable-next-line consistent-return
return
{
sourceFilename
,
absoluteFilename
,
filename
,
source
,
info
,
force
:
pattern
.
force
};
}));
}
catch
(
error
)
{
compilation
.
errors
.
push
(
/** @type {WebpackError} */
error
);
return
;
}
if
(
copiedResult
.
length
===
0
)
{
if
(
pattern
.
noErrorOnMissing
)
{
logger
.
log
(
`
finished
to
process
a
pattern
from
'${normalizedOriginalFrom}'
using
'${pattern.context}'
context
to
'${pattern.to}'
`
);
return
;
}
const
missingError
=
new
Error
(
`
unable
to
locate
'${glob}'
glob
after
filtering
paths
`
);
compilation
.
errors
.
push
(
/** @type {WebpackError} */
missingError
);
return
;
}
logger
.
log
(
`
finished
to
process
a
pattern
from
'${normalizedOriginalFrom}'
using
'${pattern.context}'
context
`
);
// eslint-disable-next-line consistent-return
return
copiedResult
;
}
/**
* @param {Compiler} compiler
*/
apply
(
compiler
)
{
const
pluginName
=
this
.
constructor
.
name
;
compiler
.
hooks
.
thisCompilation
.
tap
(
pluginName
,
compilation
=>
{
const
logger
=
compilation
.
getLogger
(
"copy-webpack-plugin"
);
const
cache
=
compilation
.
getCache
(
"CopyWebpackPlugin"
);
/**
* @type {typeof import("globby").globby}
*/
let
globby
;
compilation
.
hooks
.
processAssets
.
tapAsync
({
name
:
"copy-webpack-plugin"
,
stage
:
compiler
.
webpack
.
Compilation
.
PROCESS_ASSETS_STAGE_ADDITIONAL
},
async
(
unusedAssets
,
callback
)
=>
{
if
(
typeof
globby
===
"undefined"
)
{
try
{
// @ts-ignore
({
globby
}
=
await
import
(
"globby"
));
}
catch
(
error
)
{
callback
(
/** @type {Error} */
error
);
return
;
}
}
logger
.
log
(
"starting to add additional assets..."
);
const
copiedResultMap
=
new
Map
();
/**
* @type {(() => Promise<void>)[]}
*/
const
scheduledTasks
=
[];
this
.
patterns
.
map
(
/**
* @param {Pattern} item
* @param {number} index
* @return {number}
*/
(
item
,
index
)
=>
scheduledTasks
.
push
(
async
()
=>
{
/**
* @type {ObjectPattern}
*/
const
normalizedPattern
=
typeof
item
===
"string"
?
{
from
:
item
}
:
{
...
item
};
const
context
=
typeof
normalizedPattern
.
context
===
"undefined"
?
compiler
.
context
:
path
.
isAbsolute
(
normalizedPattern
.
context
)
?
normalizedPattern
.
context
:
path
.
join
(
compiler
.
context
,
normalizedPattern
.
context
);
normalizedPattern
.
context
=
context
;
/**
* @type {Array<CopiedResult | undefined> | undefined}
*/
let
copiedResult
;
try
{
copiedResult
=
await
CopyPlugin
.
runPattern
(
globby
,
compiler
,
compilation
,
logger
,
cache
,
/** @type {ObjectPattern & { context: string }} */
normalizedPattern
,
index
);
}
catch
(
error
)
{
compilation
.
errors
.
push
(
/** @type {WebpackError} */
error
);
return
;
}
if
(
!
copiedResult
)
{
return
;
}
/**
* @type {Array<CopiedResult>}
*/
let
filteredCopiedResult
=
copiedResult
.
filter
(
/**
* @param {CopiedResult | undefined} result
* @returns {result is CopiedResult}
*/
result
=>
Boolean
(
result
));
if
(
typeof
normalizedPattern
.
transformAll
!==
"undefined"
)
{
if
(
typeof
normalizedPattern
.
to
===
"undefined"
)
{
compilation
.
errors
.
push
(
/** @type {WebpackError} */
new
Error
(
`
Invalid
"pattern.to"
for
the
"pattern.from"
:
"${normalizedPattern.from}"
and
"pattern.transformAll"
function
.
The
"to"
option
must
be
specified
.
`
));
return
;
}
filteredCopiedResult
.
sort
((
a
,
b
)
=>
a
.
absoluteFilename
>
b
.
absoluteFilename
?
1
:
a
.
absoluteFilename
<
b
.
absoluteFilename
?
-
1
:
0
);
const
mergedEtag
=
filteredCopiedResult
.
length
===
1
?
cache
.
getLazyHashedEtag
(
filteredCopiedResult
[
0
].
source
)
:
filteredCopiedResult
.
reduce
(
/**
* @param {Etag} accumulator
* @param {CopiedResult} asset
* @param {number} i
* @return {Etag}
*/
// @ts-ignore
(
accumulator
,
asset
,
i
)
=>
{
// eslint-disable-next-line no-param-reassign
accumulator
=
cache
.
mergeEtags
(
i
===
1
?
cache
.
getLazyHashedEtag
(
/** @type {CopiedResult}*/
accumulator
.
source
)
:
accumulator
,
cache
.
getLazyHashedEtag
(
asset
.
source
));
return
accumulator
;
});
const
cacheItem
=
cache
.
getItemCache
(
`
transformAll
|
$
{
serialize
({
version
,
from
:
normalizedPattern
.
from
,
to
:
normalizedPattern
.
to
,
transformAll
:
normalizedPattern
.
transformAll
})}
`
,
mergedEtag
);
let
transformedAsset
=
await
cacheItem
.
getPromise
();
if
(
!
transformedAsset
)
{
transformedAsset
=
{
filename
:
normalizedPattern
.
to
};
try
{
transformedAsset
.
data
=
await
normalizedPattern
.
transformAll
(
filteredCopiedResult
.
map
(
asset
=>
{
return
{
data
:
asset
.
source
.
buffer
(),
sourceFilename
:
asset
.
sourceFilename
,
absoluteFilename
:
asset
.
absoluteFilename
};
}));
}
catch
(
error
)
{
compilation
.
errors
.
push
(
/** @type {WebpackError} */
error
);
return
;
}
const
filename
=
typeof
normalizedPattern
.
to
===
"function"
?
await
normalizedPattern
.
to
({
context
})
:
normalizedPattern
.
to
;
if
(
template
.
test
(
filename
))
{
const
contentHash
=
CopyPlugin
.
getContentHash
(
compiler
,
compilation
,
transformedAsset
.
data
);
const
{
path
:
interpolatedFilename
,
info
:
assetInfo
}
=
compilation
.
getPathWithInfo
(
normalizePath
(
filename
),
{
contentHash
,
chunk
:
{
id
:
"unknown-copied-asset"
,
hash
:
contentHash
}
});
transformedAsset
.
filename
=
interpolatedFilename
;
transformedAsset
.
info
=
assetInfo
;
}
const
{
RawSource
}
=
compiler
.
webpack
.
sources
;
transformedAsset
.
source
=
new
RawSource
(
transformedAsset
.
data
);
transformedAsset
.
force
=
normalizedPattern
.
force
;
await
cacheItem
.
storePromise
(
transformedAsset
);
}
filteredCopiedResult
=
[
transformedAsset
];
}
const
priority
=
normalizedPattern
.
priority
||
0
;
if
(
!
copiedResultMap
.
has
(
priority
))
{
copiedResultMap
.
set
(
priority
,
[]);
}
copiedResultMap
.
get
(
priority
).
push
(...
filteredCopiedResult
);
}));
await
throttleAll
(
this
.
options
.
concurrency
||
100
,
scheduledTasks
);
const
copiedResult
=
[...
copiedResultMap
.
entries
()].
sort
((
a
,
b
)
=>
a
[
0
]
-
b
[
0
]);
// Avoid writing assets inside `p-limit`, because it creates concurrency.
// It could potentially lead to an error - 'Multiple assets emit different content to the same filename'
copiedResult
.
reduce
((
acc
,
val
)
=>
acc
.
concat
(
val
[
1
]),
[]).
filter
(
Boolean
).
forEach
(
/**
* @param {CopiedResult} result
* @returns {void}
*/
result
=>
{
const
{
absoluteFilename
,
sourceFilename
,
filename
,
source
,
force
}
=
result
;
const
existingAsset
=
compilation
.
getAsset
(
filename
);
if
(
existingAsset
)
{
if
(
force
)
{
const
info
=
{
copied
:
true
,
sourceFilename
};
logger
.
log
(
`
force
updating
'${filename}'
from
'${absoluteFilename}'
to
compilation
assets
,
because
it
already
exists
...
`
);
compilation
.
updateAsset
(
filename
,
source
,
{
...
info
,
...
result
.
info
});
logger
.
log
(
`
force
updated
'${filename}'
from
'${absoluteFilename}'
to
compilation
assets
,
because
it
already
exists
`
);
return
;
}
logger
.
log
(
`
skip
adding
'${filename}'
from
'${absoluteFilename}'
to
compilation
assets
,
because
it
already
exists
`
);
return
;
}
const
info
=
{
copied
:
true
,
sourceFilename
};
logger
.
log
(
`
writing
'${filename}'
from
'${absoluteFilename}'
to
compilation
assets
...
`
);
compilation
.
emitAsset
(
filename
,
source
,
{
...
info
,
...
result
.
info
});
logger
.
log
(
`
written
'${filename}'
from
'${absoluteFilename}'
to
compilation
assets
`
);
});
logger
.
log
(
"finished to adding additional assets"
);
callback
();
});
if
(
compilation
.
hooks
.
statsPrinter
)
{
compilation
.
hooks
.
statsPrinter
.
tap
(
pluginName
,
stats
=>
{
stats
.
hooks
.
print
.
for
(
"asset.info.copied"
).
tap
(
"copy-webpack-plugin"
,
(
copied
,
{
green
,
formatFlag
})
=>
copied
?
/** @type {Function} */
green
(
/** @type {Function} */
formatFlag
(
"copied"
))
:
""
);
});
}
});
}
}
module
.
exports
=
CopyPlugin
;
Event Timeline
Log In to Comment