sass-module-importer
Advanced tools
Comparing version
114
lib/index.js
'use strict'; | ||
Object.defineProperty(exports, '__esModule', { | ||
value: true | ||
}); | ||
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
var fs = _interopDefault(require('fs')); | ||
var path = _interopDefault(require('path')); | ||
var Map = _interopDefault(require('es6-map')); | ||
var assign = _interopDefault(require('object-assign')); | ||
var npmResolve = _interopDefault(require('resolve')); | ||
var bowerResolve = _interopDefault(require('resolve-bower')); | ||
var _es6Map = require('es6-map'); | ||
var options = void 0; | ||
var _es6Map2 = _interopRequireDefault(_es6Map); | ||
/** | ||
* Check for the "main" field to see if it contains any css/scss/sass | ||
* If not, try to use the "style" field from package.json - and if that fails | ||
* too, defaults to "index.css" | ||
*/ | ||
var filter = function filter(pkg) { | ||
if (!pkg.main || pkg.main && !pkg.main.match(/\.s?[c|a]ss$/g)) { | ||
pkg.main = pkg.style || 'index.css'; | ||
} | ||
return pkg; | ||
}; | ||
var _resolve = require('resolve'); | ||
var _resolve2 = _interopRequireDefault(_resolve); | ||
var _resolveBower = require('resolve-bower'); | ||
var _resolveBower2 = _interopRequireDefault(_resolveBower); | ||
function find(resolver, file) { | ||
/** | ||
* Simple Promise wrapper to resolve the npm/bower modules | ||
*/ | ||
var find = function find(resolver, _ref) { | ||
var url = _ref.url; | ||
var prev = _ref.prev; | ||
var resolved = _ref.resolved; | ||
return new Promise(function (resolve) { | ||
resolver(file, function (err, res) { | ||
return resolve(err ? file : res); | ||
}); | ||
if (resolved) { | ||
resolve({ url: url, prev: prev, resolved: resolved }); | ||
} else { | ||
resolver(url, options, function (err, res) { | ||
resolve({ url: err ? url : res, prev: prev, resolved: !err }); | ||
}); | ||
} | ||
}); | ||
} | ||
}; | ||
find.npm = function (file) { | ||
var npm = function npm(file) { | ||
return find(npmResolve, file); | ||
}; | ||
return find(_resolve2['default'], file); | ||
var bower = function bower(file) { | ||
return find(bowerResolve, file); | ||
}; | ||
find.bower = function (file) { | ||
return find(_resolveBower2['default'], file); | ||
/** | ||
* Read file's content | ||
*/ | ||
var read = function read(_ref2) { | ||
var url = _ref2.url; | ||
var prev = _ref2.prev; | ||
var resolved = _ref2.resolved; | ||
return new Promise(function (resolve, reject) { | ||
if (url.match(/\.s[c|a]ss/g) || !resolved) { | ||
var resolvedURL = url; | ||
if (prev && prev !== 'stdin' && !path.isAbsolute(url)) { | ||
resolvedURL = path.resolve(path.dirname(prev), url); | ||
} | ||
resolve({ file: resolvedURL }); | ||
} else { | ||
fs.readFile(url, 'utf8', function (err, contents) { | ||
return err ? reject(err) : resolve({ contents: contents }); | ||
}); | ||
} | ||
}); | ||
}; | ||
@@ -43,24 +76,23 @@ | ||
* Look for Sass files installed through npm | ||
* @param opts {Object} Options to be passed to the resolver module | ||
* | ||
* @return {Function} Function to be used by node-sass importer | ||
*/ | ||
function index (opts) { | ||
options = assign({}, { packageFilter: filter }, opts); | ||
exports['default'] = function () { | ||
var aliases = new Map(); | ||
var aliases = new _es6Map2['default'](); | ||
return function (url, _, done) { | ||
return function (url, prev, done) { | ||
if (aliases.has(url)) { | ||
return done({ file: aliases.get(url) }); | ||
done(aliases.get(url)); | ||
} else { | ||
npm({ url: url, prev: prev }).then(bower).then(read).then(function (res) { | ||
aliases.set(url, res); | ||
done(res); | ||
}); | ||
} | ||
find.npm(url).then(find.bower).then(function (file) { | ||
aliases.set(url, file); | ||
done({ file: file }); | ||
}); | ||
}; | ||
}; | ||
} | ||
module.exports = exports['default']; | ||
module.exports = index; |
{ | ||
"name": "sass-module-importer", | ||
"version": "1.0.2", | ||
"version": "1.1.0", | ||
"main": "lib/index.js", | ||
"jsnext:main": "src/index.js", | ||
"description": "Import Sass files from NPM and Bower Modules", | ||
@@ -24,28 +25,32 @@ "author": "Lucas Motta <mail@lucasmotta.com> (lucasmotta.com)", | ||
], | ||
"engines": { | ||
"node": ">=0.10.0" | ||
}, | ||
"scripts": { | ||
"test": "mocha --compilers js:babel/register", | ||
"compile": "babel -d lib/ src/", | ||
"pretest": "eslint src/index.js test.js", | ||
"prebuild": "npm test", | ||
"build": "rollup -c", | ||
"lint": "eslint src/index.js test.js", | ||
"pretest": "npm run lint", | ||
"test": "BABEL_ENV=test mocha --compilers js:babel-register", | ||
"prepublish": "npm run build", | ||
"preversion": "npm test", | ||
"prepublish": "npm test && npm run compile", | ||
"postpublish": "git push" | ||
"version": "npm run build", | ||
"postversion": "git push && git push --tags" | ||
}, | ||
"devDependencies": { | ||
"babel": "^5.8.3", | ||
"babel-eslint": "^3.1.20", | ||
"chai": "^3.0.0", | ||
"eslint": "^0.24.1", | ||
"eslint-config-mcsaatchi": "^1.0.2", | ||
"mocha": "^2.2.5", | ||
"node-sass": "^3.2.0", | ||
"sass-easing": "^1.0.3" | ||
"babel-preset-es2015": "^6.6.0", | ||
"babel-preset-es2015-rollup": "^1.1.1", | ||
"babel-register": "^6.6.5", | ||
"chai": "^3.5.0", | ||
"eslint": "^2.3.0", | ||
"eslint-config-airbnb": "^6.1.0", | ||
"mocha": "^2.4.5", | ||
"node-sass": "^3.4.2", | ||
"rollup": "^0.25.4", | ||
"rollup-plugin-babel": "^2.4.0", | ||
"rollup-plugin-commonjs": "^2.2.1" | ||
}, | ||
"dependencies": { | ||
"es6-map": "^0.1.1", | ||
"resolve": "^1.1.6", | ||
"es6-map": "0.1.3", | ||
"object-assign": "4.0.1", | ||
"resolve": "1.1.7", | ||
"resolve-bower": "0.0.1" | ||
} | ||
} |
@@ -0,1 +1,3 @@ | ||
[](https://travis-ci.org/lucasmotta/sass-module-importer) | ||
# sass-module-importer | ||
@@ -34,2 +36,10 @@ | ||
Assuming that the external library you are installing fits under one of those categories: | ||
1. Set a SCSS/Sass/CSS file on the "main" field of their package.json/bower.json | ||
2. Set a SCSS/Sass/CSS file on the "style" field of their package.json/bower.json | ||
3. Have a `index.css` file on the root of their module | ||
This tool it will also inline CSS files for you, since Sass [cannot import plain CSS files yet](https://github.com/sass/sass/issues/556). So if the dependency you are using exports a CSS file, it will work too. | ||
## How-to | ||
@@ -69,2 +79,8 @@ | ||
## Options | ||
You can pass any option supported by [node-resolve](https://github.com/substack/node-resolve#resolveid-opts-cb) directly, like this: | ||
```js | ||
moduleImporter({ basedir: path.join(__dirname, 'another-folder') }); | ||
``` | ||
## Tests | ||
@@ -71,0 +87,0 @@ Use `npm test` to run the tests. |
145
test.js
@@ -1,6 +0,4 @@ | ||
/*eslint no-unused-expressions: 0, no-var: 0 */ | ||
/*eslint-env node, mocha */ | ||
/* eslint max-len: 0 */ | ||
import { expect } from 'chai'; | ||
import path from 'path'; | ||
import sass from 'node-sass'; | ||
@@ -10,14 +8,13 @@ import moduleImporter from './src'; | ||
function getCSS(file) { | ||
function getCSS(file, data) { | ||
return new Promise((resolve, reject) => { | ||
sass.render({ | ||
file: `./fixtures/${file}`, | ||
data, | ||
file: file ? `./fixtures/${file}` : null, | ||
outputStyle: 'compressed', | ||
importer: moduleImporter() | ||
importer: moduleImporter({ | ||
basedir: path.join(__dirname, 'fixtures'), | ||
}), | ||
}, (err, res) => err ? reject(err) : resolve(res.css.toString())); | ||
}); | ||
} | ||
@@ -27,69 +24,111 @@ | ||
describe('sass-module-importer', () => { | ||
it('should import npm module', (done) => { | ||
getCSS('npm-module.scss').then((css) => { | ||
expect(css).to.exist | ||
.and.equal('body{transition-timing-function:cubic-bezier(0.215, 0.61, 0.355, 1)}\n'); | ||
it('should import a local file', (done) => { | ||
getCSS(null, '@import "fixtures/dummy";').then((css) => { | ||
const expected = 'body{content:"local"}\n'; | ||
expect(css).to.exist.and.equal(expected); | ||
done(); | ||
}); | ||
}); | ||
it('should import bower module', (done) => { | ||
getCSS('bower-module.scss').then((css) => { | ||
expect(css).to.exist | ||
.and.equal('body{background-color:#e51c23}\n'); | ||
it('should import nested files and dependencies', (done) => { | ||
getCSS(null, '@import "test-npm-nested";').then((css) => { | ||
const expected = `*,*:after,*:before{box-sizing:border-box}html,body{margin:0;padding:0}.test{content:"SCSS from 'npm' and from 'style' field."}.child{content:'I am being imported by another file'}.test{content:"SCSS from 'npm' and from 'main' field."}\n`; | ||
expect(css).to.exist.and.equal(expected); | ||
done(); | ||
}); | ||
}); | ||
it('should import a local file', (done) => { | ||
getCSS('local-file.scss').then((css) => { | ||
expect(css).to.exist.and.equal('body{content:"local"}\n'); | ||
it('should fail to import non-existing module', (done) => { | ||
getCSS(null, '@import "unicorn";').catch((err) => { | ||
const expected = { | ||
message: 'File to import not found or unreadable: unicorn\nParent style sheet: stdin', | ||
}; | ||
expect(err.message).to.exist.and.equal(expected.message); | ||
done(); | ||
}); | ||
}); | ||
describe('npm', () => { | ||
it('should import contents of CSS from npm module using the "main" field', (done) => { | ||
getCSS(null, '@import "test-npm-main-css";').then((css) => { | ||
const expected = `.test{content:"CSS from 'npm' and from 'main' field."}\n`; | ||
expect(css).to.exist.and.equal(expected); | ||
done(); | ||
}); | ||
}); | ||
it('should import npm, bower and local file', (done) => { | ||
it('should import SCSS from npm module using the "main" field', (done) => { | ||
getCSS(null, '@import "test-npm-main-scss";').then((css) => { | ||
const expected = `.test{content:"SCSS from 'npm' and from 'main' field."}\n`; | ||
expect(css).to.exist.and.equal(expected); | ||
done(); | ||
}); | ||
}); | ||
getCSS('all.scss').then((css) => { | ||
it('should import contents of CSS from npm module using the "style" field', (done) => { | ||
getCSS(null, '@import "test-npm-style-css";').then((css) => { | ||
const expected = `.test{content:"CSS from 'npm' and from 'style' field."}\n`; | ||
expect(css).to.exist.and.equal(expected); | ||
done(); | ||
}); | ||
}); | ||
expect(css).to.exist.and.equal('body{content:"local"}body{transition-timing-function:cubic-bezier(0.215, 0.61, 0.355, 1);background-color:#e51c23}\n'); | ||
it('should import SCSS from npm module using the "style" field', (done) => { | ||
getCSS(null, '@import "test-npm-style-scss";').then((css) => { | ||
const expected = `.test{content:"SCSS from 'npm' and from 'style' field."}\n`; | ||
expect(css).to.exist.and.equal(expected); | ||
done(); | ||
}); | ||
}); | ||
done(); | ||
it('should import "index.css" if the "main" and "style" are undefined', (done) => { | ||
getCSS(null, '@import "test-npm-index-css";').then((css) => { | ||
const expected = `.test{content:"CSS from 'npm' as index.css fallback."}\n`; | ||
expect(css).to.exist.and.equal(expected); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
describe('bower', () => { | ||
it('should import contents of CSS from bower module using the "main" field', (done) => { | ||
getCSS(null, '@import "test-bower-main-css";').then((css) => { | ||
const expected = `.test{content:"CSS from 'bower' and from 'main' field."}\n`; | ||
expect(css).to.exist.and.equal(expected); | ||
done(); | ||
}); | ||
}); | ||
it('should throw error when importing inexistent module', (done) => { | ||
it('should import SCSS from bower module using the "main" field', (done) => { | ||
getCSS(null, '@import "test-bower-main-scss";').then((css) => { | ||
const expected = `.test{content:"SCSS from 'bower' and from 'main' field."}\n`; | ||
expect(css).to.exist.and.equal(expected); | ||
done(); | ||
}); | ||
}); | ||
getCSS('no-module.scss').catch((err) => { | ||
it('should import contents of CSS from bower module using the "style" field', (done) => { | ||
getCSS(null, '@import "test-bower-style-css";').then((css) => { | ||
const expected = `.test{content:"CSS from 'bower' and from 'style' field."}\n`; | ||
expect(css).to.exist.and.equal(expected); | ||
done(); | ||
}); | ||
}); | ||
expect(err).to.be.instanceof(Error); | ||
it('should import SCSS from bower module using the "style" field', (done) => { | ||
getCSS(null, '@import "test-bower-style-scss";').then((css) => { | ||
const expected = `.test{content:"SCSS from 'bower' and from 'style' field."}\n`; | ||
expect(css).to.exist.and.equal(expected); | ||
done(); | ||
}); | ||
}); | ||
done(); | ||
it('should import "index.css" if the "main" and "style" are undefined', (done) => { | ||
getCSS(null, '@import "test-bower-index-css";').then((css) => { | ||
const expected = `.test{content:"CSS from 'bower' as index.css fallback."}\n`; | ||
expect(css).to.exist.and.equal(expected); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
}); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
39
95%252
75%93
20.78%15573
-26.56%4
33.33%11
37.5%1
Infinity%1
Infinity%+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
Updated
Updated