Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F101090859
SourceMapDevToolPlugin.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
Wed, Feb 5, 16:03
Size
16 KB
Mime Type
text/x-c++
Expires
Fri, Feb 7, 16:03 (2 d)
Engine
blob
Format
Raw Data
Handle
24062848
Attached To
rOACCT Open Access Compliance Check Tool (OACCT)
SourceMapDevToolPlugin.js
View Options
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
"use strict"
;
const
asyncLib
=
require
(
"neo-async"
);
const
{
validate
}
=
require
(
"schema-utils"
);
const
{
ConcatSource
,
RawSource
}
=
require
(
"webpack-sources"
);
const
Compilation
=
require
(
"./Compilation"
);
const
ModuleFilenameHelpers
=
require
(
"./ModuleFilenameHelpers"
);
const
ProgressPlugin
=
require
(
"./ProgressPlugin"
);
const
SourceMapDevToolModuleOptionsPlugin
=
require
(
"./SourceMapDevToolModuleOptionsPlugin"
);
const
createHash
=
require
(
"./util/createHash"
);
const
{
relative
,
dirname
}
=
require
(
"./util/fs"
);
const
{
absolutify
}
=
require
(
"./util/identifier"
);
const
schema
=
require
(
"../schemas/plugins/SourceMapDevToolPlugin.json"
);
/** @typedef {import("source-map").RawSourceMap} SourceMap */
/** @typedef {import("webpack-sources").MapOptions} MapOptions */
/** @typedef {import("webpack-sources").Source} Source */
/** @typedef {import("../declarations/plugins/SourceMapDevToolPlugin").SourceMapDevToolPluginOptions} SourceMapDevToolPluginOptions */
/** @typedef {import("./Cache").Etag} Etag */
/** @typedef {import("./CacheFacade").ItemCacheFacade} ItemCacheFacade */
/** @typedef {import("./Chunk")} Chunk */
/** @typedef {import("./Compilation").AssetInfo} AssetInfo */
/** @typedef {import("./Compiler")} Compiler */
/** @typedef {import("./Module")} Module */
/** @typedef {import("./util/Hash")} Hash */
/**
* @typedef {object} SourceMapTask
* @property {Source} asset
* @property {AssetInfo} assetInfo
* @property {(string | Module)[]} modules
* @property {string} source
* @property {string} file
* @property {SourceMap} sourceMap
* @property {ItemCacheFacade} cacheItem cache item
*/
/**
* Escapes regular expression metacharacters
* @param {string} str String to quote
* @returns {string} Escaped string
*/
const
quoteMeta
=
str
=>
{
return
str
.
replace
(
/[-[\]\\/{}()*+?.^$|]/g
,
"\\$&"
);
};
/**
* Creating {@link SourceMapTask} for given file
* @param {string} file current compiled file
* @param {Source} asset the asset
* @param {AssetInfo} assetInfo the asset info
* @param {MapOptions} options source map options
* @param {Compilation} compilation compilation instance
* @param {ItemCacheFacade} cacheItem cache item
* @returns {SourceMapTask | undefined} created task instance or `undefined`
*/
const
getTaskForFile
=
(
file
,
asset
,
assetInfo
,
options
,
compilation
,
cacheItem
)
=>
{
let
source
;
/** @type {SourceMap} */
let
sourceMap
;
/**
* Check if asset can build source map
*/
if
(
asset
.
sourceAndMap
)
{
const
sourceAndMap
=
asset
.
sourceAndMap
(
options
);
sourceMap
=
/** @type {SourceMap} */
(
sourceAndMap
.
map
);
source
=
sourceAndMap
.
source
;
}
else
{
sourceMap
=
/** @type {SourceMap} */
(
asset
.
map
(
options
));
source
=
asset
.
source
();
}
if
(
!
sourceMap
||
typeof
source
!==
"string"
)
return
;
const
context
=
compilation
.
options
.
context
;
const
root
=
compilation
.
compiler
.
root
;
const
cachedAbsolutify
=
absolutify
.
bindContextCache
(
context
,
root
);
const
modules
=
sourceMap
.
sources
.
map
(
source
=>
{
if
(
!
source
.
startsWith
(
"webpack://"
))
return
source
;
source
=
cachedAbsolutify
(
source
.
slice
(
10
));
const
module
=
compilation
.
findModule
(
source
);
return
module
||
source
;
});
return
{
file
,
asset
,
source
,
assetInfo
,
sourceMap
,
modules
,
cacheItem
};
};
class
SourceMapDevToolPlugin
{
/**
* @param {SourceMapDevToolPluginOptions} [options] options object
* @throws {Error} throws error, if got more than 1 arguments
*/
constructor
(
options
=
{})
{
validate
(
schema
,
options
,
{
name
:
"SourceMap DevTool Plugin"
,
baseDataPath
:
"options"
});
/** @type {string | false} */
this
.
sourceMapFilename
=
options
.
filename
;
/** @type {string | false} */
this
.
sourceMappingURLComment
=
options
.
append
===
false
?
false
:
options
.
append
||
"\n//# source"
+
"MappingURL=[url]"
;
/** @type {string | Function} */
this
.
moduleFilenameTemplate
=
options
.
moduleFilenameTemplate
||
"webpack://[namespace]/[resourcePath]"
;
/** @type {string | Function} */
this
.
fallbackModuleFilenameTemplate
=
options
.
fallbackModuleFilenameTemplate
||
"webpack://[namespace]/[resourcePath]?[hash]"
;
/** @type {string} */
this
.
namespace
=
options
.
namespace
||
""
;
/** @type {SourceMapDevToolPluginOptions} */
this
.
options
=
options
;
}
/**
* Apply the plugin
* @param {Compiler} compiler compiler instance
* @returns {void}
*/
apply
(
compiler
)
{
const
outputFs
=
compiler
.
outputFileSystem
;
const
sourceMapFilename
=
this
.
sourceMapFilename
;
const
sourceMappingURLComment
=
this
.
sourceMappingURLComment
;
const
moduleFilenameTemplate
=
this
.
moduleFilenameTemplate
;
const
namespace
=
this
.
namespace
;
const
fallbackModuleFilenameTemplate
=
this
.
fallbackModuleFilenameTemplate
;
const
requestShortener
=
compiler
.
requestShortener
;
const
options
=
this
.
options
;
options
.
test
=
options
.
test
||
/\.(m?js|css)($|\?)/i
;
const
matchObject
=
ModuleFilenameHelpers
.
matchObject
.
bind
(
undefined
,
options
);
compiler
.
hooks
.
compilation
.
tap
(
"SourceMapDevToolPlugin"
,
compilation
=>
{
new
SourceMapDevToolModuleOptionsPlugin
(
options
).
apply
(
compilation
);
compilation
.
hooks
.
processAssets
.
tapAsync
(
{
name
:
"SourceMapDevToolPlugin"
,
stage
:
Compilation
.
PROCESS_ASSETS_STAGE_DEV_TOOLING
,
additionalAssets
:
true
},
(
assets
,
callback
)
=>
{
const
chunkGraph
=
compilation
.
chunkGraph
;
const
cache
=
compilation
.
getCache
(
"SourceMapDevToolPlugin"
);
/** @type {Map<string | Module, string>} */
const
moduleToSourceNameMapping
=
new
Map
();
/**
* @type {Function}
* @returns {void}
*/
const
reportProgress
=
ProgressPlugin
.
getReporter
(
compilation
.
compiler
)
||
(()
=>
{});
/** @type {Map<string, Chunk>} */
const
fileToChunk
=
new
Map
();
for
(
const
chunk
of
compilation
.
chunks
)
{
for
(
const
file
of
chunk
.
files
)
{
fileToChunk
.
set
(
file
,
chunk
);
}
for
(
const
file
of
chunk
.
auxiliaryFiles
)
{
fileToChunk
.
set
(
file
,
chunk
);
}
}
/** @type {string[]} */
const
files
=
[];
for
(
const
file
of
Object
.
keys
(
assets
))
{
if
(
matchObject
(
file
))
{
files
.
push
(
file
);
}
}
reportProgress
(
0.0
);
/** @type {SourceMapTask[]} */
const
tasks
=
[];
let
fileIndex
=
0
;
asyncLib
.
each
(
files
,
(
file
,
callback
)
=>
{
const
asset
=
compilation
.
getAsset
(
file
);
if
(
asset
.
info
.
related
&&
asset
.
info
.
related
.
sourceMap
)
{
fileIndex
++
;
return
callback
();
}
const
cacheItem
=
cache
.
getItemCache
(
file
,
cache
.
getLazyHashedEtag
(
asset
.
source
)
);
cacheItem
.
get
((
err
,
cacheEntry
)
=>
{
if
(
err
)
{
return
callback
(
err
);
}
/**
* If presented in cache, reassigns assets. Cache assets already have source maps.
*/
if
(
cacheEntry
)
{
const
{
assets
,
assetsInfo
}
=
cacheEntry
;
for
(
const
cachedFile
of
Object
.
keys
(
assets
))
{
if
(
cachedFile
===
file
)
{
compilation
.
updateAsset
(
cachedFile
,
assets
[
cachedFile
],
assetsInfo
[
cachedFile
]
);
}
else
{
compilation
.
emitAsset
(
cachedFile
,
assets
[
cachedFile
],
assetsInfo
[
cachedFile
]
);
}
/**
* Add file to chunk, if not presented there
*/
if
(
cachedFile
!==
file
)
{
const
chunk
=
fileToChunk
.
get
(
file
);
if
(
chunk
!==
undefined
)
chunk
.
auxiliaryFiles
.
add
(
cachedFile
);
}
}
reportProgress
(
(
0.5
*
++
fileIndex
)
/
files
.
length
,
file
,
"restored cached SourceMap"
);
return
callback
();
}
reportProgress
(
(
0.5
*
fileIndex
)
/
files
.
length
,
file
,
"generate SourceMap"
);
/** @type {SourceMapTask | undefined} */
const
task
=
getTaskForFile
(
file
,
asset
.
source
,
asset
.
info
,
{
module
:
options
.
module
,
columns
:
options
.
columns
},
compilation
,
cacheItem
);
if
(
task
)
{
const
modules
=
task
.
modules
;
for
(
let
idx
=
0
;
idx
<
modules
.
length
;
idx
++
)
{
const
module
=
modules
[
idx
];
if
(
!
moduleToSourceNameMapping
.
get
(
module
))
{
moduleToSourceNameMapping
.
set
(
module
,
ModuleFilenameHelpers
.
createFilename
(
module
,
{
moduleFilenameTemplate
:
moduleFilenameTemplate
,
namespace
:
namespace
},
{
requestShortener
,
chunkGraph
}
)
);
}
}
tasks
.
push
(
task
);
}
reportProgress
(
(
0.5
*
++
fileIndex
)
/
files
.
length
,
file
,
"generated SourceMap"
);
callback
();
});
},
err
=>
{
if
(
err
)
{
return
callback
(
err
);
}
reportProgress
(
0.5
,
"resolve sources"
);
/** @type {Set<string>} */
const
usedNamesSet
=
new
Set
(
moduleToSourceNameMapping
.
values
());
/** @type {Set<string>} */
const
conflictDetectionSet
=
new
Set
();
/**
* all modules in defined order (longest identifier first)
* @type {Array<string | Module>}
*/
const
allModules
=
Array
.
from
(
moduleToSourceNameMapping
.
keys
()
).
sort
((
a
,
b
)
=>
{
const
ai
=
typeof
a
===
"string"
?
a
:
a
.
identifier
();
const
bi
=
typeof
b
===
"string"
?
b
:
b
.
identifier
();
return
ai
.
length
-
bi
.
length
;
});
// find modules with conflicting source names
for
(
let
idx
=
0
;
idx
<
allModules
.
length
;
idx
++
)
{
const
module
=
allModules
[
idx
];
let
sourceName
=
moduleToSourceNameMapping
.
get
(
module
);
let
hasName
=
conflictDetectionSet
.
has
(
sourceName
);
if
(
!
hasName
)
{
conflictDetectionSet
.
add
(
sourceName
);
continue
;
}
// try the fallback name first
sourceName
=
ModuleFilenameHelpers
.
createFilename
(
module
,
{
moduleFilenameTemplate
:
fallbackModuleFilenameTemplate
,
namespace
:
namespace
},
{
requestShortener
,
chunkGraph
}
);
hasName
=
usedNamesSet
.
has
(
sourceName
);
if
(
!
hasName
)
{
moduleToSourceNameMapping
.
set
(
module
,
sourceName
);
usedNamesSet
.
add
(
sourceName
);
continue
;
}
// otherwise just append stars until we have a valid name
while
(
hasName
)
{
sourceName
+=
"*"
;
hasName
=
usedNamesSet
.
has
(
sourceName
);
}
moduleToSourceNameMapping
.
set
(
module
,
sourceName
);
usedNamesSet
.
add
(
sourceName
);
}
let
taskIndex
=
0
;
asyncLib
.
each
(
tasks
,
(
task
,
callback
)
=>
{
const
assets
=
Object
.
create
(
null
);
const
assetsInfo
=
Object
.
create
(
null
);
const
file
=
task
.
file
;
const
chunk
=
fileToChunk
.
get
(
file
);
const
sourceMap
=
task
.
sourceMap
;
const
source
=
task
.
source
;
const
modules
=
task
.
modules
;
reportProgress
(
0.5
+
(
0.5
*
taskIndex
)
/
tasks
.
length
,
file
,
"attach SourceMap"
);
const
moduleFilenames
=
modules
.
map
(
m
=>
moduleToSourceNameMapping
.
get
(
m
)
);
sourceMap
.
sources
=
moduleFilenames
;
if
(
options
.
noSources
)
{
sourceMap
.
sourcesContent
=
undefined
;
}
sourceMap
.
sourceRoot
=
options
.
sourceRoot
||
""
;
sourceMap
.
file
=
file
;
const
usesContentHash
=
sourceMapFilename
&&
/\[contenthash(:\w+)?\]/
.
test
(
sourceMapFilename
);
// If SourceMap and asset uses contenthash, avoid a circular dependency by hiding hash in `file`
if
(
usesContentHash
&&
task
.
assetInfo
.
contenthash
)
{
const
contenthash
=
task
.
assetInfo
.
contenthash
;
let
pattern
;
if
(
Array
.
isArray
(
contenthash
))
{
pattern
=
contenthash
.
map
(
quoteMeta
).
join
(
"|"
);
}
else
{
pattern
=
quoteMeta
(
contenthash
);
}
sourceMap
.
file
=
sourceMap
.
file
.
replace
(
new
RegExp
(
pattern
,
"g"
),
m
=>
"x"
.
repeat
(
m
.
length
)
);
}
/** @type {string | false} */
let
currentSourceMappingURLComment
=
sourceMappingURLComment
;
if
(
currentSourceMappingURLComment
!==
false
&&
/\.css($|\?)/i
.
test
(
file
)
)
{
currentSourceMappingURLComment
=
currentSourceMappingURLComment
.
replace
(
/^\n\/\/(.*)$/
,
"\n/*$1*/"
);
}
const
sourceMapString
=
JSON
.
stringify
(
sourceMap
);
if
(
sourceMapFilename
)
{
let
filename
=
file
;
const
sourceMapContentHash
=
usesContentHash
&&
/** @type {string} */
(
createHash
(
"md4"
)
.
update
(
sourceMapString
)
.
digest
(
"hex"
));
const
pathParams
=
{
chunk
,
filename
:
options
.
fileContext
?
relative
(
outputFs
,
`
/
$
{
options
.
fileContext
}
`
,
`
/
$
{
filename
}
`
)
:
filename
,
contentHash
:
sourceMapContentHash
};
const
{
path
:
sourceMapFile
,
info
:
sourceMapInfo
}
=
compilation
.
getPathWithInfo
(
sourceMapFilename
,
pathParams
);
const
sourceMapUrl
=
options
.
publicPath
?
options
.
publicPath
+
sourceMapFile
:
relative
(
outputFs
,
dirname
(
outputFs
,
`
/
$
{
file
}
`
),
`
/
$
{
sourceMapFile
}
`
);
/** @type {Source} */
let
asset
=
new
RawSource
(
source
);
if
(
currentSourceMappingURLComment
!==
false
)
{
// Add source map url to compilation asset, if currentSourceMappingURLComment is set
asset
=
new
ConcatSource
(
asset
,
compilation
.
getPath
(
currentSourceMappingURLComment
,
Object
.
assign
({
url
:
sourceMapUrl
},
pathParams
)
)
);
}
const
assetInfo
=
{
related
:
{
sourceMap
:
sourceMapFile
}
};
assets
[
file
]
=
asset
;
assetsInfo
[
file
]
=
assetInfo
;
compilation
.
updateAsset
(
file
,
asset
,
assetInfo
);
// Add source map file to compilation assets and chunk files
const
sourceMapAsset
=
new
RawSource
(
sourceMapString
);
const
sourceMapAssetInfo
=
{
...
sourceMapInfo
,
development
:
true
};
assets
[
sourceMapFile
]
=
sourceMapAsset
;
assetsInfo
[
sourceMapFile
]
=
sourceMapAssetInfo
;
compilation
.
emitAsset
(
sourceMapFile
,
sourceMapAsset
,
sourceMapAssetInfo
);
if
(
chunk
!==
undefined
)
chunk
.
auxiliaryFiles
.
add
(
sourceMapFile
);
}
else
{
if
(
currentSourceMappingURLComment
===
false
)
{
throw
new
Error
(
"SourceMapDevToolPlugin: append can't be false when no filename is provided"
);
}
/**
* Add source map as data url to asset
*/
const
asset
=
new
ConcatSource
(
new
RawSource
(
source
),
currentSourceMappingURLComment
.
replace
(
/\[map\]/g
,
()
=>
sourceMapString
)
.
replace
(
/\[url\]/g
,
()
=>
`
data
:
application
/
json
;
charset
=
utf
-
8
;
base64
,
$
{
Buffer
.
from
(
sourceMapString
,
"utf-8"
).
toString
(
"base64"
)}
`
)
);
assets
[
file
]
=
asset
;
assetsInfo
[
file
]
=
undefined
;
compilation
.
updateAsset
(
file
,
asset
);
}
task
.
cacheItem
.
store
({
assets
,
assetsInfo
},
err
=>
{
reportProgress
(
0.5
+
(
0.5
*
++
taskIndex
)
/
tasks
.
length
,
task
.
file
,
"attached SourceMap"
);
if
(
err
)
{
return
callback
(
err
);
}
callback
();
});
},
err
=>
{
reportProgress
(
1.0
);
callback
(
err
);
}
);
}
);
}
);
});
}
}
module
.
exports
=
SourceMapDevToolPlugin
;
Event Timeline
Log In to Comment