From 29b30755021a834e622bf4b5bb9db4d6e5913905 Mon Sep 17 00:00:00 2001 From: Johannes Ewald Date: Mon, 26 Dec 2016 18:13:28 +0100 Subject: [PATCH] Remove node 0.12 support and replace jshint with eslint using eslint-config-peerigon This has been done in one step since eslint can automatically fix a lot issues for us. We're using eslint-config-peerigon as new baseline. --- .eslintignore | 2 + .eslintrc.json | 9 + .jshintignore | 20 --- .jshintrc | 49 ------ index.js | 177 ++++++++++--------- package.json | 6 +- test/.eslintrc.json | 5 + test/bootstrapSass/webpack.config.js | 18 +- test/hmr/entry.js | 12 +- test/hmr/webpack.config.js | 18 +- test/index.test.js | 247 +++++++++++++-------------- test/sourceMap/entry.js | 4 +- test/sourceMap/webpack.config.js | 16 +- test/spec.test.js | 45 +++-- test/tools/createSpec.js | 54 +++--- test/tools/customFunctions.js | 16 +- test/tools/customImporter.js | 17 +- test/tools/runCreateSpec.js | 6 +- test/watch/entry.js | 4 +- test/watch/webpack.config.js | 16 +- 20 files changed, 334 insertions(+), 407 deletions(-) create mode 100644 .eslintignore create mode 100644 .eslintrc.json delete mode 100755 .jshintignore delete mode 100755 .jshintrc create mode 100644 test/.eslintrc.json diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 00000000..4590fad2 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,2 @@ +# Compiled by webpack +test/output diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 00000000..80189d1d --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,9 @@ +{ + "extends": [ + "peerigon/base" + ], + "env": { + "node": true + }, + "root": true +} diff --git a/.jshintignore b/.jshintignore deleted file mode 100755 index 0c9e5d3f..00000000 --- a/.jshintignore +++ /dev/null @@ -1,20 +0,0 @@ -lib-cov -*.seed -*.log -*.csv -*.dat -*.out -*.pid -*.gz - -pids -logs -results - -npm-debug.log -node_modules -coverage -examples -.idea - -test/output diff --git a/.jshintrc b/.jshintrc deleted file mode 100755 index 7a99ec8e..00000000 --- a/.jshintrc +++ /dev/null @@ -1,49 +0,0 @@ -{ - "browser": true, - "node": true, - "expr": true, - "predef": [ // Extra globals. - "describe", - "it", - "before", - "after", - "beforeEach", - "afterEach", - "phantom" - ], - - "curly": true, // Require {} for every new block or scope. - "eqeqeq": true, // Require triple equals i.e. `===`. - "forin": true, // Tolerate `for in` loops without `hasOwnPrototype`. - "immed": true, // Require immediate invocations to be wrapped in parens e.g. `( function(){}() );` - "latedef": false, // Prohibit variable use before definition. - "newcap": false, // Require capitalization of all constructor functions e.g. `new F()`. - "noempty": true, // Prohibit use of empty blocks. - "nonew": false, // Prohibit use of constructors for side-effects. - "plusplus": false, // Prohibit use of `++` & `--`. - "undef": true, // Require all non-global variables be declared before they are used. - "strict": true, // Require `use strict` pragma in every file. - "trailing": true, // Prohibit trailing whitespaces. - "asi": false, // Tolerate Automatic Semicolon Insertion (no semicolons). - "boss": false, // Tolerate assignments inside if, for & while. Usually conditions & loops are for comparison, not assignments. - "debug": false, // Allow debugger statements e.g. browser breakpoints. - "eqnull": false, // Tolerate use of `== null`. - "esnext": false, // Allow ES.next specific features such as `const` and `let`. - "evil": false, // Tolerate use of `eval`. - "funcscope": false, // Tolerate declarations of variables inside of control structures while accessing them later from the outside. - "globalstrict": false, // Allow global "use strict" (also enables 'strict'). - "iterator": false, // Allow usage of __iterator__ property. - "lastsemic": false, // Tolerat missing semicolons when the it is omitted for the last statement in a one-line block. - "laxbreak": false, // Tolerate unsafe line breaks e.g. `return [\n] x` without semicolons. - "laxcomma": false, // Suppress warnings about comma-first coding style. - "loopfunc": false, // Allow functions to be defined within loops. - "multistr": false, // Tolerate multi-line strings. - "quotmark": "single", // Only single quotes for strings. - "proto": false, // Tolerate __proto__ property. This property is deprecated. - "scripturl": false, // Tolerate script-targeted URLs. - "smarttabs": false, // Tolerate mixed tabs and spaces when the latter are used for alignmnent only. - "shadow": false, // Allows re-define variables later in code e.g. `var x=1; x=2;`. - "sub": true, // Tolerate all forms of subscript notation besides dot notation e.g. `dict['key']` instead of `dict.key`. - "supernew": false, // Tolerate `new function () { ... };` and `new Object;`. - "validthis": false // Tolerate strict violations when the code is running in strict mode and you use this in a non-constructor function -} diff --git a/index.js b/index.js index 1a33c26b..69186237 100644 --- a/index.js +++ b/index.js @@ -1,32 +1,32 @@ -'use strict'; +"use strict"; -var utils = require('loader-utils'); -var sass = require('node-sass'); -var path = require('path'); -var os = require('os'); -var fs = require('fs'); -var async = require('async'); -var assign = require('object-assign'); +const utils = require("loader-utils"); +const sass = require("node-sass"); +const path = require("path"); +const os = require("os"); +const fs = require("fs"); +const async = require("async"); +const assign = require("object-assign"); // A typical sass error looks like this -var SassError = { - message: 'invalid property name', +const SassError = { // eslint-disable-line no-unused-vars + message: "invalid property name", column: 14, line: 1, - file: 'stdin', + file: "stdin", status: 1 }; // libsass uses this precedence when importing files without extension -var slice = Array.prototype.slice; -var extPrecedence = ['.scss', '.sass', '.css']; -var matchCss = /\.css$/; +const slice = Array.prototype.slice; +const extPrecedence = [".scss", ".sass", ".css"]; +const matchCss = /\.css$/; // This queue makes sure node-sass leaves one thread available for executing // fs tasks when running the custom importer code. // This can be removed as soon as node-sass implements a fix for this. -var threadPoolSize = process.env.UV_THREADPOOL_SIZE || 4; -var asyncSassJobQueue = async.queue(sass.render, threadPoolSize - 1); +const threadPoolSize = process.env.UV_THREADPOOL_SIZE || 4; +const asyncSassJobQueue = async.queue(sass.render, threadPoolSize - 1); /** * The sass-loader makes node-sass available to webpack modules. @@ -34,11 +34,10 @@ var asyncSassJobQueue = async.queue(sass.render, threadPoolSize - 1); * @param {string} content */ module.exports = function (content) { - var callback = this.async(); - var isSync = typeof callback !== 'function'; - var self = this; - var resourcePath = this.resourcePath; - var sassOptions; + const callback = this.async(); + const isSync = typeof callback !== "function"; + const self = this; + const resourcePath = this.resourcePath; /** * Enhances the sass error with additional information about what actually went wrong. @@ -56,9 +55,9 @@ module.exports = function (content) { return; } - var msg = err.message; + let msg = err.message; - if (err.file === 'stdin') { + if (err.file === "stdin") { err.file = resourcePath; } // node-sass returns UNIX-style paths @@ -66,11 +65,11 @@ module.exports = function (content) { // The 'Current dir' hint of node-sass does not help us, we're providing // additional information by reading the err.file property - msg = msg.replace(/\s*Current dir:\s*/, ''); + msg = msg.replace(/\s*Current dir:\s*/, ""); err.message = getFileExcerptIfPossible(err) + msg.charAt(0).toUpperCase() + msg.slice(1) + os.EOL + - ' in ' + err.file + ' (line ' + err.line + ', column ' + err.column + ')'; + " in " + err.file + " (line " + err.line + ", column " + err.column + ")"; } /** @@ -79,17 +78,14 @@ module.exports = function (content) { * It's important that the returned function has the correct number of arguments * (based on whether the call is sync or async) because otherwise node-sass doesn't exit. * - * @returns {function} + * @returns {Function} */ function getWebpackImporter() { return function asyncWebpackImporter(url, fileContext, done) { - var dirContext; - var request; - // node-sass returns UNIX-style paths fileContext = path.normalize(fileContext); - request = utils.urlToRequest(url, sassOptions.root); - dirContext = fileToDirContext(fileContext); + const request = utils.urlToRequest(url, sassOptions.root); + const dirContext = fileToDirContext(fileContext); resolve(dirContext, url, getImportsToResolve(request), done); }; @@ -102,10 +98,10 @@ module.exports = function (content) { * @param {string} dirContext * @param {string} originalImport * @param {Array} importsToResolve - * @param {function} done + * @param {Function} done */ function resolve(dirContext, originalImport, importsToResolve, done) { - var importToResolve = importsToResolve.shift(); + const importToResolve = importsToResolve.shift(); if (!importToResolve) { // No import possibilities left. Let's pass that one back to libsass... @@ -115,7 +111,7 @@ module.exports = function (content) { return; } - self.resolve(dirContext, importToResolve, function onWebpackResolve(err, resolvedFilename) { + self.resolve(dirContext, importToResolve, (err, resolvedFilename) => { if (err) { resolve(dirContext, originalImport, importsToResolve, done); return; @@ -124,20 +120,20 @@ module.exports = function (content) { // in handy when an error occurs. In this case, we don't get stats.includedFiles from node-sass. addNormalizedDependency(resolvedFilename); // By removing the CSS file extension, we trigger node-sass to include the CSS file instead of just linking it. - resolvedFilename = resolvedFilename.replace(matchCss, ''); + resolvedFilename = resolvedFilename.replace(matchCss, ""); // Use self.loadModule() before calling done() to make imported files available to // other webpack tools like postLoaders etc.? done({ - file: resolvedFilename.replace(matchCss, '') + file: resolvedFilename.replace(matchCss, "") }); }); } function fileToDirContext(fileContext) { // The first file is 'stdin' when we're using the data option - if (fileContext === 'stdin') { + if (fileContext === "stdin") { fileContext = resourcePath; } return path.dirname(fileContext); @@ -153,25 +149,26 @@ module.exports = function (content) { // node-sass returns UNIX-style paths self.dependency(path.normalize(file)); } - + if (isSync) { - throw new Error('Synchronous compilation is not supported anymore. See https://github.com/jtangelder/sass-loader/issues/333'); + throw new Error("Synchronous compilation is not supported anymore. See https://github.com/jtangelder/sass-loader/issues/333"); } this.cacheable(); - sassOptions = getLoaderConfig(this); + const sassOptions = getLoaderConfig(this); + sassOptions.data = sassOptions.data ? (sassOptions.data + os.EOL + content) : content; // Skip empty files, otherwise it will stop webpack, see issue #21 - if (sassOptions.data.trim() === '') { + if (sassOptions.data.trim() === "") { callback(null, content); return; } // opt.outputStyle if (!sassOptions.outputStyle && this.minimize) { - sassOptions.outputStyle = 'compressed'; + sassOptions.outputStyle = "compressed"; } // opt.sourceMap @@ -181,21 +178,21 @@ module.exports = function (content) { // deliberately overriding the sourceMap option // this value is (currently) ignored by libsass when using the data input instead of file input // however, it is still necessary for correct relative paths in result.map.sources. - sassOptions.sourceMap = this.options.context + '/sass.map'; + sassOptions.sourceMap = this.options.context + "/sass.map"; sassOptions.omitSourceMapUrl = true; // If sourceMapContents option is not set, set it to true otherwise maps will be empty/null // when exported by webpack-extract-text-plugin. - if ('sourceMapContents' in sassOptions === false) { + if ("sourceMapContents" in sassOptions === false) { sassOptions.sourceMapContents = true; } } // indentedSyntax is a boolean flag. - var ext = path.extname(resourcePath); + const ext = path.extname(resourcePath); // If we are compiling sass and indentedSyntax isn't set, automatically set it. - if (ext && ext.toLowerCase() === '.sass' && sassOptions.indentedSyntax === undefined) { + if (ext && ext.toLowerCase() === ".sass" && "indentedSyntax" in sassOptions === false) { sassOptions.indentedSyntax = true; } else { sassOptions.indentedSyntax = Boolean(sassOptions.indentedSyntax); @@ -210,7 +207,7 @@ module.exports = function (content) { sassOptions.includePaths.push(path.dirname(resourcePath)); // start the actual rendering - asyncSassJobQueue.push(sassOptions, function onRender(err, result) { + asyncSassJobQueue.push(sassOptions, (err, result) => { if (err) { formatSassError(err); err.file && self.dependency(err.file); @@ -218,7 +215,7 @@ module.exports = function (content) { return; } - if (result.map && result.map !== '{}') { + if (result.map && result.map !== "{}") { result.map = JSON.parse(result.map); result.map.file = resourcePath; // The first source is 'stdin' according to libsass because we've used the data input @@ -244,31 +241,23 @@ module.exports = function (content) { * @returns {string} */ function getFileExcerptIfPossible(err) { - var content; + let content; try { - content = fs.readFileSync(err.file, 'utf8'); + content = fs.readFileSync(err.file, "utf8"); return os.EOL + content.split(os.EOL)[err.line - 1] + os.EOL + - new Array(err.column - 1).join(' ') + '^' + os.EOL + - ' '; + new Array(err.column - 1).join(" ") + "^" + os.EOL + + " "; } catch (err) { // If anything goes wrong here, we don't want any errors to be reported to the user - return ''; + return ""; } } /** - * When libsass tries to resolve an import, it uses this "funny" algorithm: - * - * - Imports with no file extension: - * - Prefer modules starting with '_' - * - File extension precedence: .scss, .sass, .css - * - Imports with file extension: - * - If the file is a CSS-file, do not include it all, but just link it via @import url() - * - The exact file name must match (no auto-resolving of '_'-modules) - * + * When libsass tries to resolve an import, it uses a special algorithm. * Since the sass-loader uses webpack to resolve the modules, we need to simulate that algorithm. This function * returns an array of import paths to try. * @@ -276,20 +265,27 @@ function getFileExcerptIfPossible(err) { * @returns {Array} */ function getImportsToResolve(originalImport) { - var ext = path.extname(originalImport); - var basename = path.basename(originalImport); - var dirname = path.dirname(originalImport); - var startsWithUnderscore = basename.charAt(0) === '_'; - var paths = []; + // libsass' import algorithm works like this: + // In case there is no file extension... + // - Prefer modules starting with '_'. + // - File extension precedence: .scss, .sass, .css. + // In case there is a file extension... + // - If the file is a CSS-file, do not include it all, but just link it via @import url(). + // - The exact file name must match (no auto-resolving of '_'-modules). + const ext = path.extname(originalImport); + const basename = path.basename(originalImport); + const dirname = path.dirname(originalImport); + const startsWithUnderscore = basename.charAt(0) === "_"; + const paths = []; function add(file) { // No path.sep required here, because imports inside SASS are usually with / - paths.push(dirname + '/' + file); + paths.push(dirname + "/" + file); } - if (originalImport.charAt(0) !== '.') { + if (originalImport.charAt(0) !== ".") { // If true: originalImport is a module import like 'bootstrap-sass...' - if (dirname === '.') { + if (dirname === ".") { // If true: originalImport is just a module import without a path like 'bootstrap-sass' // In this case we don't do that auto-resolving dance at all. return [originalImport]; @@ -299,20 +295,20 @@ function getImportsToResolve(originalImport) { // We can't just check for ext being defined because ext can also be something like '.datepicker' // when the true extension is omitted and the filename contains a dot. // @see https://github.com/jtangelder/sass-loader/issues/167 - /*jshint noempty:false */ - if (ext === '.css') { + /* jshint noempty:false */ + if (ext === ".css") { // do not import css files - } else if (ext === '.scss' || ext === '.sass') { - /*jshint noempty:true */ + } else if (ext === ".scss" || ext === ".sass") { + /* jshint noempty:true */ add(basename); } else { if (!startsWithUnderscore) { // Prefer modules starting with '_' first - extPrecedence.forEach(function (ext) { - add('_' + basename + ext); + extPrecedence.forEach((ext) => { + add("_" + basename + ext); }); } - extPrecedence.forEach(function (ext) { + extPrecedence.forEach((ext) => { add(basename + ext); }); } @@ -328,9 +324,9 @@ function getImportsToResolve(originalImport) { * @returns {Object} */ function getLoaderConfig(loaderContext) { - var query = utils.parseQuery(loaderContext.query); - var configKey = query.config || 'sassLoader'; - var config = loaderContext.options[configKey] || {}; + const query = utils.parseQuery(loaderContext.query); + const configKey = query.config || "sassLoader"; + const config = loaderContext.options[configKey] || {}; delete query.config; @@ -341,26 +337,27 @@ function getLoaderConfig(loaderContext) { * Creates new custom importers that use the given `resourcePath` if libsass calls the custom importer with `prev` * being 'stdin'. * - * Why do we need this? + * Why do we need this? We have to use the `data` option of node-sass in order to compile our sass because + * the `resourcePath` might not be an actual file on disk. When using the `data` option, libsass uses the string + * 'stdin' instead of a filename. * - * We have to use the `data` option of node-sass in order to compile our sass because the `resourcePath` might - * not be an actual file on disk. When using the `data` option, libsass uses the string 'stdin' instead of a - * filename. We have to fix this behavior in order to provide a consistent experience to the webpack user. + * We have to fix this behavior in order to provide a consistent experience to the webpack user. * * @param {function|Array} importer * @param {string} resourcePath * @returns {Array} */ function proxyCustomImporters(importer, resourcePath) { - return [].concat(importer).map(function (importer) { + return [].concat(importer).map((importer) => { return function (url, prev, done) { - var args = slice.call(arguments); - - if (args[1] === 'stdin') { + const importerContext = this; // eslint-disable-line no-invalid-this + const args = slice.call(arguments); + + if (args[1] === "stdin") { args[1] = resourcePath; } - - return importer.apply(this, args); + + return importer.apply(importerContext, args); }; }); } diff --git a/package.json b/package.json index 73f46553..c054be39 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "create-spec": "node test/tools/runCreateSpec.js", "pretest": "node test/tools/runCreateSpec.js", "test": "mocha -R spec", - "posttest": "jshint index.js test", + "posttest": "eslint --fix index.js test", "test-bootstrap-sass": "webpack-dev-server --config test/bootstrapSass/webpack.config.js --content-base ./test/bootstrapSass", "test-source-map": "webpack-dev-server --config test/sourceMap/webpack.config.js --content-base ./test/sourceMap", "test-watch": "webpack --config test/watch/webpack.config.js", @@ -38,8 +38,10 @@ "devDependencies": { "bootstrap-sass": "^3.3.5", "css-loader": "^0.24.0", + "eslint": "^3.12.2", + "eslint-config-peerigon": "^9.0.0", + "eslint-plugin-jsdoc": "^2.4.0", "file-loader": "^0.9.0", - "jshint": "^2.9.2", "mocha": "^3.0.2", "node-sass": "^4.0.0", "raw-loader": "^0.5.1", diff --git a/test/.eslintrc.json b/test/.eslintrc.json new file mode 100644 index 00000000..27231149 --- /dev/null +++ b/test/.eslintrc.json @@ -0,0 +1,5 @@ +{ + "extends": [ + "peerigon/tests" + ] +} diff --git a/test/bootstrapSass/webpack.config.js b/test/bootstrapSass/webpack.config.js index 7e8e4249..52fb55a5 100644 --- a/test/bootstrapSass/webpack.config.js +++ b/test/bootstrapSass/webpack.config.js @@ -1,25 +1,25 @@ -'use strict'; +"use strict"; -var path = require('path'); +const path = require("path"); -var pathToSassLoader = path.resolve(__dirname, '../../index.js'); +const pathToSassLoader = path.resolve(__dirname, "../../index.js"); module.exports = { - entry: path.resolve(__dirname, '../scss/bootstrap-sass.scss'), + entry: path.resolve(__dirname, "../scss/bootstrap-sass.scss"), output: { - path: path.resolve(__dirname, '../output'), - filename: 'bundle.bootstrap-sass.js' + path: path.resolve(__dirname, "../output"), + filename: "bundle.bootstrap-sass.js" }, - devtool: 'inline-source-map', + devtool: "inline-source-map", module: { loaders: [ { test: /\.woff2?$|\.ttf$|\.eot$|\.svg$/, - loader: 'file' + loader: "file" }, { test: /\.scss$/, - loader: 'style-loader!css-loader!' + pathToSassLoader + loader: "style-loader!css-loader!" + pathToSassLoader } ] } diff --git a/test/hmr/entry.js b/test/hmr/entry.js index d247587a..e8a2cb6c 100644 --- a/test/hmr/entry.js +++ b/test/hmr/entry.js @@ -1,8 +1,10 @@ -'use strict'; +"use strict"; -require('../scss/language.scss'); -require('./simple.css'); +/* global document */ -setInterval(function () { - document.body.innerHTML += '
Now we just change the DOM, so that we can ensure that webpack is not just reloading the page'; +require("../scss/language.scss"); +require("./simple.css"); + +setInterval(() => { + document.body.innerHTML += "
Now we just change the DOM, so that we can ensure that webpack is not just reloading the page"; }, 2000); diff --git a/test/hmr/webpack.config.js b/test/hmr/webpack.config.js index a02ebfc2..e497cb1b 100644 --- a/test/hmr/webpack.config.js +++ b/test/hmr/webpack.config.js @@ -1,25 +1,25 @@ -'use strict'; +"use strict"; -var path = require('path'); -var webpack = require('webpack'); +const path = require("path"); +const webpack = require("webpack"); -var pathToSassLoader = path.resolve(__dirname, '../../index.js'); +const pathToSassLoader = path.resolve(__dirname, "../../index.js"); module.exports = { - entry: path.resolve(__dirname, './entry.js'), + entry: path.resolve(__dirname, "./entry.js"), output: { - path: path.resolve(__dirname, '../output'), - filename: 'bundle.hmr.js' + path: path.resolve(__dirname, "../output"), + filename: "bundle.hmr.js" }, module: { loaders: [ { test: /\.scss$/, - loader: 'style!css!' + pathToSassLoader + loader: "style!css!" + pathToSassLoader }, { test: /\.css$/, - loader: 'style!css' + loader: "style!css" } ] }, diff --git a/test/index.test.js b/test/index.test.js index d04b296e..0294d0ee 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -1,167 +1,154 @@ -'use strict'; - -Object.assign = Object.assign || require('object-assign'); - -var should = require('should'); -var path = require('path'); -var webpack = require('webpack'); -var fs = require('fs'); -var merge = require('webpack-merge'); -var customImporter = require('./tools/customImporter.js'); -var customFunctions = require('./tools/customFunctions.js'); -var pathToSassLoader = require.resolve('../index.js'); -var sassLoader = require(pathToSassLoader); - -var CR = /\r/g; -var syntaxStyles = ['scss', 'sass']; -var pathToErrorFileNotFound = path.resolve(__dirname, './scss/error-file-not-found.scss'); -var pathToErrorFileNotFound2 = path.resolve(__dirname, './scss/error-file-not-found-2.scss'); -var pathToErrorFile = path.resolve(__dirname, './scss/error.scss'); -var pathToErrorImport = path.resolve(__dirname, './scss/error-import.scss'); - -describe('sass-loader', function () { - - describe('basic', function () { - - testSync('should compile simple sass without errors (sync)', 'language'); - testAsync('should compile simple sass without errors (async)', 'language'); - +"use strict"; + +Object.assign = Object.assign || require("object-assign"); +require("should"); + +const path = require("path"); +const webpack = require("webpack"); +const fs = require("fs"); +const merge = require("webpack-merge"); +const customImporter = require("./tools/customImporter.js"); +const customFunctions = require("./tools/customFunctions.js"); +const pathToSassLoader = require.resolve("../index.js"); +const sassLoader = require(pathToSassLoader); + +const CR = /\r/g; +const syntaxStyles = ["scss", "sass"]; +const pathToErrorFileNotFound = path.resolve(__dirname, "./scss/error-file-not-found.scss"); +const pathToErrorFileNotFound2 = path.resolve(__dirname, "./scss/error-file-not-found-2.scss"); +const pathToErrorFile = path.resolve(__dirname, "./scss/error.scss"); +const pathToErrorImport = path.resolve(__dirname, "./scss/error-import.scss"); + +describe("sass-loader", () => { + describe("basic", () => { + testSync("should compile simple sass without errors (sync)", "language"); + testAsync("should compile simple sass without errors (async)", "language"); }); - describe('config', function () { - + describe("config", () => { // Will be removed with webpack 2 support - it.skip('should override sassLoader config with loader query', function () { - var expectedCss = readCss('sass', 'language'); - var webpackConfig = Object.assign({}, { - entry: 'raw!' + pathToSassLoader + '?indentedSyntax!' + path.join(__dirname, 'sass', 'language.sass'), - sassLoader: { - // Incorrect setting here should be overridden by loader query - indentedSyntax: false - } - }); - var enhancedReq; - var actualCss; - - //enhancedReq = enhancedReqFactory(module, webpackConfig); - actualCss = enhancedReq(webpackConfig.entry); - - fs.writeFileSync(__dirname + '/output/should override sassLoader config with loader query.sass.sync.css', actualCss, 'utf8'); - actualCss.should.eql(expectedCss); + it.skip("should override sassLoader config with loader query", () => { + // const expectedCss = readCss("sass", "language"); + // const webpackConfig = Object.assign({}, { + // entry: "raw!" + pathToSassLoader + "?indentedSyntax!" + path.join(__dirname, "sass", "language.sass"), + // sassLoader: { + // // Incorrect setting here should be overridden by loader query + // indentedSyntax: false + // } + // }); + // let enhancedReq; + // let actualCss; + // + // enhancedReq = enhancedReqFactory(module, webpackConfig); + // const actualCss = enhancedReq(webpackConfig.entry); + // + // fs.writeFileSync(__dirname + "/output/should override sassLoader config with loader query.sass.sync.css", actualCss, "utf8"); + // actualCss.should.eql(expectedCss); }); - }); - describe('imports', function () { - - testSync('should resolve imports correctly (sync)', 'imports'); - testAsync('should resolve imports correctly (async)', 'imports'); + describe("imports", () => { + testSync("should resolve imports correctly (sync)", "imports"); + testAsync("should resolve imports correctly (async)", "imports"); // Test for issue: https://github.com/jtangelder/sass-loader/issues/32 - testSync('should pass with multiple imports (sync)', 'multiple-imports'); - testAsync('should pass with multiple imports (async)', 'multiple-imports'); + testSync("should pass with multiple imports (sync)", "multiple-imports"); + testAsync("should pass with multiple imports (async)", "multiple-imports"); // Test for issue: https://github.com/jtangelder/sass-loader/issues/73 - testSync('should resolve imports from other language style correctly (sync)', 'import-other-style'); - testAsync('should resolve imports from other language style correctly (async)', 'import-other-style'); + testSync("should resolve imports from other language style correctly (sync)", "import-other-style"); + testAsync("should resolve imports from other language style correctly (async)", "import-other-style"); // Test for includePath imports - testSync('should resolve imports from another directory declared by includePaths correctly (sync)', 'import-include-paths', function (ext) { + testSync("should resolve imports from another directory declared by includePaths correctly (sync)", "import-include-paths", (ext) => { return { sassLoader: { - includePaths: [path.join(__dirname, ext, 'from-include-path')] + includePaths: [path.join(__dirname, ext, "from-include-path")] } }; }); - testAsync('should resolve imports from another directory declared by includePaths correctly (async)', 'import-include-paths', function (ext) { + testAsync("should resolve imports from another directory declared by includePaths correctly (async)", "import-include-paths", (ext) => { return { sassLoader: { - includePaths: [path.join(__dirname, ext, 'from-include-path')] + includePaths: [path.join(__dirname, ext, "from-include-path")] } }; }); - testSync('should not resolve CSS imports (sync)', 'import-css'); - testAsync('should not resolve CSS imports (async)', 'import-css'); + testSync("should not resolve CSS imports (sync)", "import-css"); + testAsync("should not resolve CSS imports (async)", "import-css"); - testSync('should compile bootstrap-sass without errors (sync)', 'bootstrap-sass'); - testAsync('should compile bootstrap-sass without errors (async)', 'bootstrap-sass'); + testSync("should compile bootstrap-sass without errors (sync)", "bootstrap-sass"); + testAsync("should compile bootstrap-sass without errors (async)", "bootstrap-sass"); }); - describe('custom importers', function () { - - testSync('should use custom importer', 'custom-importer', function () { + describe("custom importers", () => { + testSync("should use custom importer", "custom-importer", () => { return { sassLoader: { importer: customImporter } }; }); - testAsync('should use custom importer', 'custom-importer', function () { + testAsync("should use custom importer", "custom-importer", () => { return { sassLoader: { importer: customImporter } }; }); - }); - describe('custom functions', function () { - - testSync('should expose custom functions', 'custom-functions', function () { + describe("custom functions", () => { + testSync("should expose custom functions", "custom-functions", () => { return { sassLoader: { functions: customFunctions } }; }); - testAsync('should expose custom functions', 'custom-functions', function () { + testAsync("should expose custom functions", "custom-functions", () => { return { sassLoader: { functions: customFunctions } }; }); - }); - describe('prepending data', function () { - - testSync('should extend the data-option if present', 'prepending-data', function () { + describe("prepending data", () => { + testSync("should extend the data-option if present", "prepending-data", () => { return { sassLoader: { - data: '$prepended-data: hotpink;' + data: "$prepended-data: hotpink;" } }; }); - testAsync('should extend the data-option if present', 'prepending-data', function () { + testAsync("should extend the data-option if present", "prepending-data", () => { return { sassLoader: { - data: '$prepended-data: hotpink;' + data: "$prepended-data: hotpink;" } }; }); - }); - describe('errors', function () { - - it('should throw an error in synchronous loader environments', function () { - try { - sassLoader.call({ - async: Function.prototype - }, ''); + describe("errors", () => { + it("should throw an error in synchronous loader environments", () => { + try { + sassLoader.call({ + async: Function.prototype + }, ""); } catch (err) { // check for file excerpt - err.message.should.equal('Synchronous compilation is not supported anymore. See https://github.com/jtangelder/sass-loader/issues/333'); + err.message.should.equal("Synchronous compilation is not supported anymore. See https://github.com/jtangelder/sass-loader/issues/333"); } }); - it('should output understandable errors in entry files', function (done) { + it("should output understandable errors in entry files", (done) => { runWebpack({ - entry: pathToSassLoader + '!' + pathToErrorFile - }, function (err) { + entry: pathToSassLoader + "!" + pathToErrorFile + }, (err) => { err.message.should.match(/\.syntax-error''/); err.message.should.match(/Invalid CSS after/); err.message.should.match(/\(line 1, column 14\)/); @@ -170,10 +157,10 @@ describe('sass-loader', function () { }); }); - it('should output understandable errors of imported files', function (done) { + it("should output understandable errors of imported files", (done) => { runWebpack({ - entry: pathToSassLoader + '!' + pathToErrorImport - }, function (err) { + entry: pathToSassLoader + "!" + pathToErrorImport + }, (err) => { // check for file excerpt err.message.should.match(/\.syntax-error''/); err.message.should.match(/Invalid CSS after "\.syntax-error''": expected "\{", was ""/); @@ -183,10 +170,10 @@ describe('sass-loader', function () { }); }); - it('should output understandable errors when a file could not be found', function (done) { + it("should output understandable errors when a file could not be found", (done) => { runWebpack({ - entry: pathToSassLoader + '!' + pathToErrorFileNotFound - }, function (err) { + entry: pathToSassLoader + "!" + pathToErrorFileNotFound + }, (err) => { err.message.should.match(/@import "does-not-exist";/); err.message.should.match(/File to import not found or unreadable: does-not-exist/); err.message.should.match(/\(line 1, column 1\)/); @@ -195,10 +182,10 @@ describe('sass-loader', function () { }); }); - it('should not auto-resolve imports with explicit file names', function (done) { + it("should not auto-resolve imports with explicit file names", (done) => { runWebpack({ - entry: pathToSassLoader + '!' + pathToErrorFileNotFound2 - }, function (err) { + entry: pathToSassLoader + "!" + pathToErrorFileNotFound2 + }, (err) => { err.message.should.match(/@import "\.\/another\/_module\.scss";/); err.message.should.match(/File to import not found or unreadable: \.\/another\/_module\.scss/); err.message.should.match(/\(line 1, column 1\)/); @@ -206,38 +193,37 @@ describe('sass-loader', function () { done(); }); }); - }); }); function readCss(ext, id) { - return fs.readFileSync(path.join(__dirname, ext, 'spec', id + '.css'), 'utf8').replace(CR, ''); + return fs.readFileSync(path.join(__dirname, ext, "spec", id + ".css"), "utf8").replace(CR, ""); } function testAsync(name, id, config) { - syntaxStyles.forEach(function forEachSyntaxStyle(ext) { - it(name + ' (' + ext + ')', function (done) { - var expectedCss = readCss(ext, id); - var sassFile = pathToSassFile(ext, id); - var baseConfig = merge({ + syntaxStyles.forEach((ext) => { + it(name + " (" + ext + ")", (done) => { + const expectedCss = readCss(ext, id); + const sassFile = pathToSassFile(ext, id); + const baseConfig = merge({ entry: sassFile, output: { - filename: 'bundle.' + ext + '.js' + filename: "bundle." + ext + ".js" } }, config ? config(ext) : {}); - var actualCss; - - runWebpack(baseConfig, function (err) { + let actualCss; + + runWebpack(baseConfig, (err) => { if (err) { done(err); return; } - - delete require.cache[path.resolve(__dirname, './output/bundle.' + ext + '.js')]; - actualCss = require('./output/bundle.' + ext + '.js'); + delete require.cache[path.resolve(__dirname, "./output/bundle." + ext + ".js")]; + + actualCss = require("./output/bundle." + ext + ".js"); // writing the actual css to output-dir for better debugging - fs.writeFileSync(__dirname + '/output/' + name + '.' + ext + '.async.css', actualCss, 'utf8'); + fs.writeFileSync(path.join(__dirname, "output", Number(name) + "." + ext + ".async.css"), actualCss, "utf8"); actualCss.should.eql(expectedCss); done(); @@ -247,32 +233,31 @@ function testAsync(name, id, config) { } function testSync() { - + } function runWebpack(baseConfig, done) { - var webpackConfig = merge({ + const webpackConfig = merge({ output: { - path: __dirname + '/output', - filename: 'bundle.js', - libraryTarget: 'commonjs2' + path: path.join(__dirname, "output"), + filename: "bundle.js", + libraryTarget: "commonjs2" } }, baseConfig); - webpack(webpackConfig, function onCompilationFinished(err, stats) { - if (err) { - return done(err); - } - if (stats.hasErrors()) { - return done(stats.compilation.errors[0]); - } - if (stats.hasWarnings()) { - return done(stats.compilation.warnings[0]); + webpack(webpackConfig, (err, stats) => { + const notOk = err || + (stats.hasErrors && stats.compilation.errors[0]) || + (stats.hasWarnings && stats.compilation.warnings[0]); + + if (notOk) { + done(notOk); + return; } done(); }); } function pathToSassFile(ext, id) { - return 'raw!' + pathToSassLoader + '!' + path.join(__dirname, ext, id + '.' + ext); + return "raw!" + pathToSassLoader + "!" + path.join(__dirname, ext, id + "." + ext); } diff --git a/test/sourceMap/entry.js b/test/sourceMap/entry.js index a8e55eed..a0ddeb39 100644 --- a/test/sourceMap/entry.js +++ b/test/sourceMap/entry.js @@ -1,3 +1,3 @@ -'use strict'; +"use strict"; -require('../scss/multiple-imports.scss'); +require("../scss/multiple-imports.scss"); diff --git a/test/sourceMap/webpack.config.js b/test/sourceMap/webpack.config.js index 8fee59e5..f2808620 100644 --- a/test/sourceMap/webpack.config.js +++ b/test/sourceMap/webpack.config.js @@ -1,21 +1,21 @@ -'use strict'; +"use strict"; -var path = require('path'); +const path = require("path"); -var pathToSassLoader = path.resolve(__dirname, '../../index.js'); +const pathToSassLoader = path.resolve(__dirname, "../../index.js"); module.exports = { - entry: path.resolve(__dirname, './entry.js'), + entry: path.resolve(__dirname, "./entry.js"), output: { - path: path.resolve(__dirname, '../output'), - filename: 'bundle.sourcemap.js' + path: path.resolve(__dirname, "../output"), + filename: "bundle.sourcemap.js" }, - devtool: 'inline-source-map', + devtool: "inline-source-map", module: { loaders: [ { test: /\.scss$/, - loaders: ['style', 'css-loader?sourceMap', pathToSassLoader + '?sourceMap'] + loaders: ["style", "css-loader?sourceMap", pathToSassLoader + "?sourceMap"] } ] } diff --git a/test/spec.test.js b/test/spec.test.js index c8e787bf..9e10e2c3 100644 --- a/test/spec.test.js +++ b/test/spec.test.js @@ -1,4 +1,4 @@ -'use strict'; +"use strict"; /** * This file can be used to track changes in the spec introduced by newer node-sass versions. @@ -13,21 +13,21 @@ * 5. Run `npm run test-spec` */ -var should = require('should'); -var fs = require('fs'); -var path = require('path'); -var createSpec = require('./tools/createSpec.js'); +require("should"); +const fs = require("fs"); +const path = require("path"); +const createSpec = require("./tools/createSpec.js"); -var testFolder = __dirname; -var matchCss = /\.css$/; +const testFolder = __dirname; +const matchCss = /\.css$/; function readSpec(folder) { - var result = {}; + const result = {}; fs.readdirSync(folder) - .forEach(function (file) { + .forEach((file) => { if (matchCss.test(file)) { - result[file] = fs.readFileSync(path.join(folder, file), 'utf8'); + result[file] = fs.readFileSync(path.join(folder, file), "utf8"); } }); @@ -36,33 +36,30 @@ function readSpec(folder) { function writeSpec(folder, spec) { Object.keys(spec) - .forEach(function (specName) { - fs.writeFileSync(path.resolve(folder, specName), spec[specName], 'utf8'); + .forEach((specName) => { + fs.writeFileSync(path.resolve(folder, specName), spec[specName], "utf8"); }); } -['scss', 'sass'].forEach(function (ext) { +["scss", "sass"].forEach((ext) => { + describe.skip(ext + " spec", () => { + const specFolder = path.resolve(testFolder, ext, "spec"); + const oldSpec = readSpec(specFolder); - describe.skip(ext + ' spec', function () { - var specFolder = path.resolve(testFolder, ext, 'spec'); - var oldSpec; - var newSpec; - - oldSpec = readSpec(specFolder); createSpec(ext); - newSpec = readSpec(specFolder); + + const newSpec = readSpec(specFolder); Object.keys(oldSpec) - .forEach(function (specName) { - it(specName + ' should not have been changed', function () { + .forEach((specName) => { + it(specName + " should not have been changed", () => { oldSpec[specName].should.eql(newSpec[specName]); }); }); - after(function () { + after(() => { // Write old spec back to the folder so that future tests will also fail writeSpec(specFolder, oldSpec); }); }); - }); diff --git a/test/tools/createSpec.js b/test/tools/createSpec.js index ee13aab6..ed0e8e4e 100644 --- a/test/tools/createSpec.js +++ b/test/tools/createSpec.js @@ -1,33 +1,30 @@ -'use strict'; +"use strict"; -var sass = require('node-sass'); -var os = require('os'); -var fs = require('fs'); -var path = require('path'); -var customImporter = require('./customImporter.js'); -var customFunctions = require('./customFunctions.js'); +const sass = require("node-sass"); +const os = require("os"); +const fs = require("fs"); +const path = require("path"); +const customImporter = require("./customImporter.js"); +const customFunctions = require("./customFunctions.js"); -var testFolder = path.resolve(__dirname, '../'); -var error = 'error'; +const testFolder = path.resolve(__dirname, "../"); +const error = "error"; function createSpec(ext) { - var basePath = path.join(testFolder, ext); - var testNodeModules = path.relative(basePath, path.join(testFolder, 'node_modules')) + path.sep; - var pathToBootstrap = path.relative(basePath, path.resolve(testFolder, '..', 'node_modules', 'bootstrap-sass')); + const basePath = path.join(testFolder, ext); + const testNodeModules = path.relative(basePath, path.join(testFolder, "node_modules")) + path.sep; + const pathToBootstrap = path.relative(basePath, path.resolve(testFolder, "..", "node_modules", "bootstrap-sass")); fs.readdirSync(path.join(testFolder, ext)) - .filter(function (file) { - return path.extname(file) === '.' + ext && file.slice(0, error.length) !== error; + .filter((file) => { + return path.extname(file) === "." + ext && file.slice(0, error.length) !== error; }) - .map(function (file) { - var fileName = path.join(basePath, file); - var fileWithoutExt = file.slice(0, -ext.length - 1); - var sassOptions; - var css; - - sassOptions = { - importer: function (url) { - if (url === 'import-with-custom-logic') { + .map((file) => { + const fileName = path.join(basePath, file); + const fileWithoutExt = file.slice(0, -ext.length - 1); + const sassOptions = { + importer(url) { + if (url === "import-with-custom-logic") { return customImporter.returnValue; } if (/\.css$/.test(url) === false) { // Do not transform css imports @@ -41,20 +38,21 @@ function createSpec(ext) { }, functions: customFunctions, includePaths: [ - path.join(testFolder, ext, 'another'), - path.join(testFolder, ext, 'from-include-path') + path.join(testFolder, ext, "another"), + path.join(testFolder, ext, "from-include-path") ] }; if (/prepending-data/.test(fileName)) { - sassOptions.data = '$prepended-data: hotpink;' + os.EOL + fs.readFileSync(fileName, 'utf8'); + sassOptions.data = "$prepended-data: hotpink;" + os.EOL + fs.readFileSync(fileName, "utf8"); sassOptions.indentedSyntax = /\.sass$/.test(fileName); } else { sassOptions.file = fileName; } - css = sass.renderSync(sassOptions).css; - fs.writeFileSync(path.join(basePath, 'spec', fileWithoutExt + '.css'), css, 'utf8'); + const css = sass.renderSync(sassOptions).css; + + fs.writeFileSync(path.join(basePath, "spec", fileWithoutExt + ".css"), css, "utf8"); }); } diff --git a/test/tools/customFunctions.js b/test/tools/customFunctions.js index 2a367621..968321c7 100644 --- a/test/tools/customFunctions.js +++ b/test/tools/customFunctions.js @@ -1,16 +1,16 @@ -'use strict'; +"use strict"; -var sass = require('node-sass'); +const sass = require("node-sass"); module.exports = { - 'headings($from: 0, $to: 6)': function (from, to) { - var f = from.getValue(); - var t = to.getValue(); - var list = new sass.types.List(t - f + 1); - var i; + "headings($from: 0, $to: 6)"(from, to) { + const f = from.getValue(); + const t = to.getValue(); + const list = new sass.types.List(t - f + 1); + let i; for (i = f; i <= t; i++) { - list.setValue(i - f, new sass.types.String('h' + i)); + list.setValue(i - f, new sass.types.String("h" + i)); } return list; diff --git a/test/tools/customImporter.js b/test/tools/customImporter.js index 4fb96429..11c03e94 100644 --- a/test/tools/customImporter.js +++ b/test/tools/customImporter.js @@ -1,19 +1,18 @@ -'use strict'; +"use strict"; -var should = require('should'); +require("should"); function customImporter(path, prev) { - /*jshint validthis: true */ - - path.should.equal('import-with-custom-logic'); + path.should.equal("import-with-custom-logic"); prev.should.match(/(sass|scss)[/\\]custom-importer\.(scss|sass)/); - - this.should.have.property('options'); - + + this.should.have.property("options"); // eslint-disable-line no-invalid-this + return customImporter.returnValue; } + customImporter.returnValue = { - contents: '.custom-imported {}' + contents: ".custom-imported {}" }; module.exports = customImporter; diff --git a/test/tools/runCreateSpec.js b/test/tools/runCreateSpec.js index 6c6916df..437e3f04 100644 --- a/test/tools/runCreateSpec.js +++ b/test/tools/runCreateSpec.js @@ -1,7 +1,7 @@ -'use strict'; +"use strict"; -var createSpec = require('./createSpec.js'); +const createSpec = require("./createSpec.js"); -['scss', 'sass'].forEach(function (ext) { +["scss", "sass"].forEach((ext) => { createSpec(ext); }); diff --git a/test/watch/entry.js b/test/watch/entry.js index e37b0eab..ad32ab60 100644 --- a/test/watch/entry.js +++ b/test/watch/entry.js @@ -1,3 +1,3 @@ -'use strict'; +"use strict"; -require('../scss/imports.scss'); +require("../scss/imports.scss"); diff --git a/test/watch/webpack.config.js b/test/watch/webpack.config.js index ce09e9bb..6646724e 100644 --- a/test/watch/webpack.config.js +++ b/test/watch/webpack.config.js @@ -1,24 +1,24 @@ -'use strict'; +"use strict"; -var path = require('path'); +const path = require("path"); -var pathToSassLoader = path.resolve(__dirname, '../../index.js'); +const pathToSassLoader = path.resolve(__dirname, "../../index.js"); module.exports = { entry: [ - path.resolve(__dirname, '../scss/imports.scss'), - path.resolve(__dirname, '../scss/import-include-paths.scss') + path.resolve(__dirname, "../scss/imports.scss"), + path.resolve(__dirname, "../scss/import-include-paths.scss") ], output: { - path: path.resolve(__dirname, '../output'), - filename: 'bundle.watch.js' + path: path.resolve(__dirname, "../output"), + filename: "bundle.watch.js" }, watch: true, module: { loaders: [ { test: /\.scss$/, - loader: 'css-loader!' + pathToSassLoader + '?includePaths[]=' + encodeURIComponent(path.resolve(__dirname, '../scss/from-include-path')) + loader: "css-loader!" + pathToSassLoader + "?includePaths[]=" + encodeURIComponent(path.resolve(__dirname, "../scss/from-include-path")) } ] }