@joneff/sass-import-resolver

Resolves the path of sass imports, following a heavily opinionated and probably very shady algorithm

Downloads in past

Stats

StarsIssuesVersionUpdatedCreatedSize
@joneff/sass-import-resolver
1.0.03 years ago5 years agoMinified + gzip package size for @joneff/sass-import-resolver in KB

Readme

sass-import-resolver
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.

Purpose

The purpose of the package is to be used for sass importers or similar scripts. The API has similar signature to a sass importer.

Installation

npm install @joneff/sass-import-resolver --save-dev

Basic Usage

It'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.scss

API

The api has only two methods with both using the same params.

resolve()

  • 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.

resolve()

  • 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

  • options.file -- Path to a file
  • options.prev (Optional) -- Path to file (or dir) to be used for resolving url. 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 @import declarations. When resolving nodemodule (~), absolute (/) or parent (../) imports, this has no effect.
  • options.nodeModules (Optional) -- Location of node_modules when resolving. Defaults to ./node_modules.

Heavily Opinionated and Probably Very Shady Algorithm

The algorithm is based on Sass @import documentation, and should work as follows, assuming atleast options.file param is passed:
1) if file starts with http://, https://, //, \\\\ or url(, it's not proccessed at all and returned as is; 2) if prev is file, set cwd to the directory that file is in; 3) if prev is directory, set cwd to that directory; 4) if prev is not passed, set cwd to proccess.cwd(); 5) if includePaths is not passed, assume it's an empty array; 6) if file is absolute path, clear cwd and includePaths; 7) if file starts with ~, assume nodemodules import, set cwd to node_modules and clear includePaths; 8) if file starts with ., clear includePaths; 9) assuming there are any includePaths left, unique them with cwd and loop them:
1) if the file portion of `file` has `.css`, `.scss`, or `.sass` extension, resolve tha path and return it;
2) if the file portion `file` starts with `_`, resolve and return the following 7 variants in that order:
    1) `_file.css`
    2) `_file.scss`
    3) `_file.sass`
    4) `file/index.scss` (that's an exception from sass @import)
    5) `file/index.sass`  (that's an exception from sass @import)
    6) `file/_index.scss`
    7) `file/_index.sass`
3) resolve and return the following 9 variants in that order:
    1) `file.css`
    2) `file.scss`
    3) `file.sass`
    4) `_file.scss`
    5) `_file.sass`
    6) `file/index.scss` (that's an exception from sass @import)
    7) `file/index.sass`  (that's an exception from sass @import)
    8) `file/_index.scss`
    9) `file/_index.sass`
10) assuming there is an array of matches, loop over:
1) return the resolved path of the first file that exists on the file system
2) 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.

Contributing?

Sure.