sass-import-resolver resolves the path of sass imports, following a heavily opinionated and probably very shady algorithm, which I will get to in a bit.
The purpose of the package is to be used for sass importers or similar scripts. The API has similar signature to a sass importer.
npm install @joneff/sass-import-resolver --save-devIt's probably not a good idea to use in any production code, without rigorous testing. Usage may feel a bit like a Kübler-Ross grief cycle -- denial, anger, barganing, depression, acceptance -- but it's the only sane solution I was able to come up with.
-- me
Something like this will yield results:
const resolver = require('@joneff/sass-import-resolver');
// assuming @import "../some/dependency.scss" in ./my/overly/nested/framework.scss
const file = ...;
const options = ...;
const result = resolver.resolve({ file, ...options });
console.log(result);
// if the file exists => ./my/overly/some/dependecy.scss
// if not => ../some/dependency.scssThe api has only two methods with both using the same params.
- Signature:
function resolve( options: { file: String, prev?: String, includePaths?: Array<String>, nodeModules?: String } ) : String
Just a facade -- passes everything down to _resove and waits for results.
- Signature:
function _resolve( options: { file: String, prev?: String, includePaths?: Array<String>, nodeModules?: String } ) : Array<String>
Does the actual work, collects unique matches and returns them.
options.file-- Path to a fileoptions.prev(Optional) -- Path to file (or dir) to be used for resolvingurl. Ideally, it should not be empty and should be the previously resolved path.options.includePaths(Optional) -- An array of paths that the script can look in when attempting to resolve@importdeclarations. When resolving node_module (~), absolute (/) or parent (../) imports, this has no effect.options.nodeModules(Optional) -- Location ofnode_moduleswhen resolving. Defaults to./node_modules.
The algorithm is based on Sass @import documentation, and should work as follows, assuming atleast options.file param is passed:
- if
filestarts withhttp://,https://,//,\\\\orurl(, it's not proccessed at all and returned as is; - if
previs file, setcwdto the directory that file is in; - if
previs directory, setcwdto that directory; - if
previs not passed, setcwdtoproccess.cwd(); - if
includePathsis not passed, assume it's an empty array; - if
fileis absolute path, clearcwdandincludePaths; - if
filestarts with~, assume node_modules import, setcwdtonode_modulesand clearincludePaths; - if
filestarts with., clearincludePaths; - assuming there are any
includePathsleft, unique them withcwdand loop them:- if the file portion of
filehas.css,.scss, or.sassextension, resolve tha path and return it; - if the file portion
filestarts with_, resolve and return the following 7 variants in that order:_file.css_file.scss_file.sassfile/index.scss(that's an exception from sass @import)file/index.sass(that's an exception from sass @import)file/_index.scssfile/_index.sass
- resolve and return the following 9 variants in that order:
file.cssfile.scssfile.sass_file.scss_file.sassfile/index.scss(that's an exception from sass @import)file/index.sass(that's an exception from sass @import)file/_index.scssfile/_index.sass
- if the file portion of
- assuming there is an array of matches, loop over:
- return the resolved path of the first file that exists on the file system
- otherwise return the original
file
Surely, the algorithm can be extended in various directions like scraping the package.json of resolved modules and looking for entry points, which is not a bad idea at all. However, if you are a sass package creator and you rely on such custom logic, things will not go well for consumers of said packages.
Sure.