@@ -2,66 +2,58 @@ import path from 'path';
2
2
import fs from 'fs' ;
3
3
import sass from 'sass' ;
4
4
5
+ const DEFAULT_EXTS = [ 'scss' , 'sass' , 'css' ] ;
6
+
7
+ export function resolveUrls ( url : string , extensions : string [ ] = DEFAULT_EXTS ) {
8
+ // We only care about tilde-prefixed imports that do not look like paths.
9
+ if ( ! url . startsWith ( '~' ) || url . startsWith ( '~/' ) ) {
10
+ return [ ] ;
11
+ }
12
+
13
+ const module_path = path . join ( 'node_modules' , url . substring ( 1 ) ) ;
14
+ let variants = [ module_path ] ;
15
+
16
+ const parts = path . parse ( module_path ) ;
17
+
18
+ // Support sass partials by including paths where the file is prefixed by an underscore.
19
+ if ( ! parts . base . startsWith ( '_' ) ) {
20
+ const underscore_name = '_' . concat ( parts . name ) ;
21
+ const replacement = {
22
+ root : parts . root ,
23
+ dir : parts . dir ,
24
+ ext : parts . ext ,
25
+ base : `${ underscore_name } ${ parts . ext } ` ,
26
+ name : underscore_name ,
27
+ } ;
28
+ variants . push ( path . format ( replacement ) ) ;
29
+ }
30
+
31
+ // Support index files.
32
+ variants . push ( path . join ( module_path , '_index' ) ) ;
33
+
34
+ // Create variants such that it has entries of the form
35
+ // node_modules/@foo /bar/baz.(scss|sass)
36
+ // for an import of the form ~@foo /bar/baz(.(scss|sass))?
37
+ if ( ! extensions . some ( ( ext ) => parts . ext == `.${ ext } ` ) ) {
38
+ variants = extensions . flatMap ( ( ext ) =>
39
+ variants . map ( ( variant ) => `${ variant } .${ ext } ` ) ,
40
+ ) ;
41
+ }
42
+
43
+ return variants ;
44
+ }
45
+
5
46
/**
6
47
* Creates a sass importer which resolves Webpack-style tilde-imports.
7
48
*/
8
49
export const sassTildeImporter : sass . FileImporter < 'sync' > = {
9
50
findFileUrl ( url ) {
10
- // We only care about tilde-prefixed imports that do not look like paths.
11
- if ( ! url . startsWith ( '~' ) || url . startsWith ( '~/' ) ) {
12
- return null ;
13
- }
14
-
15
- // Create subpathsWithExts such that it has entries of the form
16
- // node_modules/@foo /bar/baz.(scss|sass)
17
- // for an import of the form ~@foo /bar/baz(.(scss|sass))?
18
- const nodeModSubpath = path . join ( 'node_modules' , url . substring ( 1 ) ) ;
19
- const subpathsWithExts : string [ ] = [ ] ;
20
- if (
21
- nodeModSubpath . endsWith ( '.scss' ) ||
22
- nodeModSubpath . endsWith ( '.sass' ) ||
23
- nodeModSubpath . endsWith ( '.css' )
24
- ) {
25
- subpathsWithExts . push ( nodeModSubpath ) ;
26
- } else {
27
- // Look for .scss first.
28
- subpathsWithExts . push (
29
- `${ nodeModSubpath } .scss` ,
30
- `${ nodeModSubpath } .sass` ,
31
- `${ nodeModSubpath } .css` ,
32
- ) ;
33
- }
34
-
35
- // Support index files.
36
- subpathsWithExts . push (
37
- `${ nodeModSubpath } /_index.scss` ,
38
- `${ nodeModSubpath } /_index.sass` ,
39
- ) ;
40
-
41
- // Support sass partials by including paths where the file is prefixed by an underscore.
42
- const basename = path . basename ( nodeModSubpath ) ;
43
- if ( ! basename . startsWith ( '_' ) ) {
44
- const partials = subpathsWithExts . map ( ( file ) =>
45
- file . replace ( basename , `_${ basename } ` ) ,
46
- ) ;
47
- subpathsWithExts . push ( ...partials ) ;
48
- }
51
+ const searchPaths = resolveUrls ( url ) ;
49
52
50
- // Climbs the filesystem tree until we get to the root, looking for the first
51
- // node_modules directory which has a matching module and filename.
52
- let prevDir = '' ;
53
- let dir = path . dirname ( url ) ;
54
- while ( prevDir !== dir ) {
55
- const searchPaths = subpathsWithExts . map ( ( subpathWithExt ) =>
56
- path . join ( dir , subpathWithExt ) ,
57
- ) ;
58
- for ( const searchPath of searchPaths ) {
59
- if ( fs . existsSync ( searchPath ) ) {
60
- return new URL ( `file://${ path . resolve ( searchPath ) } ` ) ;
61
- }
53
+ for ( const searchPath of searchPaths ) {
54
+ if ( fs . existsSync ( searchPath ) ) {
55
+ return new URL ( `file://${ path . resolve ( searchPath ) } ` ) ;
62
56
}
63
- prevDir = dir ;
64
- dir = path . dirname ( dir ) ;
65
57
}
66
58
67
59
// Returning null is not itself an error, it tells sass to instead try the
0 commit comments