npm package: @joneff/sass-import-resolver
Description: Resolves the path of sass imports, following a heavily opinionated and probably very shady algorithm
Author: Ivan Zhekov
Latest version: 1.0.0

# 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](#API) has similar signature to a sass importer.

## Installation

```shell
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:

```javascript
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 node_module (`~`), 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 node_modules 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.

[sass-import-resolver]: https://github.com/joneff/sass-import-resolver
[sass importers]: https://github.com/sass/node-sass#importer--v200---experimental
[Kübler-Ross]: https://en.wikipedia.org/wiki/Elisabeth_K%C3%BCbler-Ross
[grief cycle]: https://en.wikipedia.org/wiki/K%C3%BCbler-Ross_model
[Sass `@import` documentation]: https://sass-lang.com/documentation/at-rules/import