11/*
2- MIT License http://www.opensource.org/licenses/mit-license.php
3- Author Tobias Koppers @sokra
2+ MIT License http://www.opensource.org/licenses/mit-license.php
3+ Author Tobias Koppers @sokra
44*/
55import path from 'path' ;
66
7- import { promisify } from 'util' ;
8-
97import validateOptions from 'schema-utils' ;
10- import parseDataURL from 'data-urls' ;
11-
12- import { SourceMapConsumer } from 'source-map' ;
13-
14- import { labelToName , decode } from 'whatwg-encoding' ;
15- import { getOptions , urlToRequest } from 'loader-utils' ;
8+ import { getOptions } from 'loader-utils' ;
169
1710import schema from './options.json' ;
18- import {
19- flattenSourceMap ,
20- readFile ,
21- getContentFromSourcesContent ,
22- getSourceMappingUrl ,
23- getRequestedUrl ,
24- } from './utils' ;
11+ import { getSourceMappingURL , fetchFromURL , flattenSourceMap } from './utils' ;
2512
2613export default async function loader ( input , inputMap ) {
2714 const options = getOptions ( this ) ;
@@ -31,179 +18,117 @@ export default async function loader(input, inputMap) {
3118 baseDataPath : 'options' ,
3219 } ) ;
3320
34- let { url } = getSourceMappingUrl ( input ) ;
35- const { replacementString } = getSourceMappingUrl ( input ) ;
21+ const { sourceMappingURL, replacementString } = getSourceMappingURL ( input ) ;
3622 const callback = this . async ( ) ;
3723
38- if ( ! url ) {
24+ if ( ! sourceMappingURL ) {
3925 callback ( null , input , inputMap ) ;
4026
4127 return ;
4228 }
4329
44- const { fs, context, resolve, addDependency, emitWarning } = this ;
45- const resolver = promisify ( resolve ) ;
46- const reader = promisify ( fs . readFile ) . bind ( fs ) ;
30+ let sourceURL ;
31+ let sourceContent ;
4732
48- if ( url . toLowerCase ( ) . startsWith ( 'data:' ) ) {
49- const dataURL = parseDataURL ( url ) ;
50-
51- if ( dataURL ) {
52- let map ;
53-
54- try {
55- dataURL . encodingName =
56- labelToName ( dataURL . mimeType . parameters . get ( 'charset' ) ) || 'UTF-8' ;
57-
58- map = decode ( dataURL . body , dataURL . encodingName ) ;
59- map = JSON . parse ( map . replace ( / ^ \) \] \} ' / , '' ) ) ;
60- } catch ( error ) {
61- emitWarning (
62- `Cannot parse inline SourceMap with Charset ${ dataURL . encodingName } : ${ error } `
63- ) ;
33+ try {
34+ ( { sourceURL, sourceContent } = await fetchFromURL (
35+ this ,
36+ this . context ,
37+ sourceMappingURL
38+ ) ) ;
39+ } catch ( error ) {
40+ this . emitWarning ( error ) ;
6441
65- callback ( null , input , inputMap ) ;
42+ callback ( null , input , inputMap ) ;
6643
67- return ;
68- }
44+ return ;
45+ }
6946
70- processMap ( map , context , callback ) ;
47+ if ( sourceURL ) {
48+ this . addDependency ( sourceURL ) ;
49+ }
7150
72- return ;
73- }
51+ let map ;
7452
75- emitWarning ( `Cannot parse inline SourceMap: ${ url } ` ) ;
53+ try {
54+ map = JSON . parse ( sourceContent . replace ( / ^ \) \] \} ' / , '' ) ) ;
55+ } catch ( parseError ) {
56+ this . emitWarning (
57+ new Error ( `Cannot parse source map from '${ sourceURL } ': ${ parseError } ` )
58+ ) ;
7659
7760 callback ( null , input , inputMap ) ;
7861
7962 return ;
8063 }
8164
82- try {
83- url = getRequestedUrl ( url ) ;
84- } catch ( error ) {
85- emitWarning ( error . message ) ;
65+ const context = sourceURL ? path . dirname ( sourceURL ) : this . context ;
8666
87- callback ( null , input , inputMap ) ;
88-
89- return ;
67+ if ( map . sections ) {
68+ // eslint-disable-next-line no-param-reassign
69+ map = await flattenSourceMap ( map ) ;
9070 }
9171
92- let urlResolved ;
72+ const resolvedSources = await Promise . all (
73+ map . sources . map ( async ( source , i ) => {
74+ // eslint-disable-next-line no-shadow
75+ let sourceURL ;
76+ // eslint-disable-next-line no-shadow
77+ let sourceContent ;
9378
94- try {
95- urlResolved = await resolver ( context , urlToRequest ( url , true ) ) ;
96- } catch ( resolveError ) {
97- emitWarning ( `Cannot find SourceMap '${ url } ': ${ resolveError } ` ) ;
79+ const originalSourceContent =
80+ map . sourcesContent && map . sourcesContent [ i ]
81+ ? map . sourcesContent [ i ]
82+ : null ;
83+ const skipReading = originalSourceContent !== null ;
9884
99- callback ( null , input , inputMap ) ;
85+ try {
86+ ( { sourceURL, sourceContent } = await fetchFromURL (
87+ this ,
88+ context ,
89+ source ,
90+ map . sourceRoot ,
91+ skipReading
92+ ) ) ;
93+ } catch ( error ) {
94+ this . emitWarning ( error ) ;
10095
101- return ;
102- }
96+ sourceURL = source ;
97+ }
10398
104- urlResolved = urlResolved . toString ( ) ;
99+ if ( originalSourceContent ) {
100+ sourceContent = originalSourceContent ;
101+ }
105102
106- addDependency ( urlResolved ) ;
103+ if ( sourceURL ) {
104+ this . addDependency ( sourceURL ) ;
105+ }
107106
108- const content = await reader ( urlResolved ) ;
109- let map ;
107+ return { sourceURL, sourceContent } ;
108+ } )
109+ ) ;
110110
111- try {
112- map = JSON . parse ( content . toString ( ) ) ;
113- } catch ( parseError ) {
114- emitWarning ( `Cannot parse SourceMap '${ url } ': ${ parseError } ` ) ;
111+ const newMap = { ...map } ;
115112
116- callback ( null , input , inputMap ) ;
113+ newMap . sources = [ ] ;
114+ newMap . sourcesContent = [ ] ;
117115
118- return ;
119- }
116+ delete newMap . sourceRoot ;
120117
121- processMap ( map , path . dirname ( urlResolved ) , callback ) ;
122-
123- // eslint-disable-next-line no-shadow
124- async function processMap ( map , context , callback ) {
125- if ( map . sections ) {
126- // eslint-disable-next-line no-param-reassign
127- map = await flattenSourceMap ( map ) ;
128- }
129-
130- const mapConsumer = await new SourceMapConsumer ( map ) ;
131-
132- let resolvedSources ;
133-
134- try {
135- resolvedSources = await Promise . all (
136- map . sources . map ( async ( source ) => {
137- const fullPath = map . sourceRoot
138- ? `${ map . sourceRoot } ${ path . sep } ${ source } `
139- : source ;
140-
141- const originalData = getContentFromSourcesContent (
142- mapConsumer ,
143- source
144- ) ;
145-
146- if ( path . isAbsolute ( fullPath ) ) {
147- return originalData
148- ? { source : fullPath , content : originalData }
149- : readFile ( fullPath , emitWarning , reader ) ;
150- }
151-
152- let fullPathResolved ;
153-
154- try {
155- fullPathResolved = await resolver (
156- context ,
157- urlToRequest ( fullPath , true )
158- ) ;
159- } catch ( resolveError ) {
160- emitWarning ( `Cannot find source file '${ source } ': ${ resolveError } ` ) ;
161-
162- return originalData
163- ? {
164- source : fullPath ,
165- content : originalData ,
166- }
167- : { source : fullPath , content : null } ;
168- }
169-
170- return originalData
171- ? {
172- source : fullPathResolved ,
173- content : originalData ,
174- }
175- : readFile ( fullPathResolved , emitWarning , reader ) ;
176- } )
177- ) ;
178- } catch ( error ) {
179- emitWarning ( error ) ;
180-
181- callback ( null , input , inputMap ) ;
182- }
183-
184- const resultMap = { ...map } ;
185- resultMap . sources = [ ] ;
186- resultMap . sourcesContent = [ ] ;
187-
188- delete resultMap . sourceRoot ;
189-
190- resolvedSources . forEach ( ( res ) => {
191- // eslint-disable-next-line no-param-reassign
192- resultMap . sources . push ( path . normalize ( res . source ) ) ;
193- resultMap . sourcesContent . push ( res . content ) ;
194-
195- if ( res . source ) {
196- addDependency ( res . source ) ;
197- }
198- } ) ;
118+ resolvedSources . forEach ( ( source ) => {
119+ // eslint-disable-next-line no-shadow
120+ const { sourceURL, sourceContent } = source ;
199121
200- const sourcesContentIsEmpty =
201- resultMap . sourcesContent . filter ( ( entry ) => ! ! entry ) . length === 0 ;
122+ newMap . sources . push ( sourceURL || '' ) ;
123+ newMap . sourcesContent . push ( sourceContent || '' ) ;
124+ } ) ;
202125
203- if ( sourcesContentIsEmpty ) {
204- delete resultMap . sourcesContent ;
205- }
126+ const sourcesContentIsEmpty =
127+ newMap . sourcesContent . filter ( ( entry ) => Boolean ( entry ) ) . length === 0 ;
206128
207- callback ( null , input . replace ( replacementString , '' ) , resultMap ) ;
129+ if ( sourcesContentIsEmpty ) {
130+ delete newMap . sourcesContent ;
208131 }
132+
133+ callback ( null , input . replace ( replacementString , '' ) , newMap ) ;
209134}
0 commit comments