Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Minor tweaks and cleanup #822

Merged
merged 4 commits into from Oct 12, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
12 changes: 10 additions & 2 deletions .eslintrc
Expand Up @@ -4,9 +4,17 @@ env:
mocha: true
node: true

extends: "airbnb-base"

parserOptions:
sourceType: "script"

rules:
max-len:
- 2
- 120

extends: "airbnb-base"
no-multi-assign: "off"
xzyfer marked this conversation as resolved.
Show resolved Hide resolved
no-param-reassign: "off"
strict:
- "error"
- "safe"
260 changes: 134 additions & 126 deletions index.js
@@ -1,3 +1,5 @@
'use strict';

const path = require('path');
const chalk = require('chalk');
const PluginError = require('plugin-error');
Expand All @@ -9,151 +11,161 @@ const applySourceMap = require('vinyl-sourcemaps-apply');

const PLUGIN_NAME = 'gulp-sass';

/// ///////////////////////////
// Main Gulp Sass function
/// ///////////////////////////
const gulpSass = (options, sync) => transfob((file, enc, cb) => { // eslint-disable-line consistent-return
if (file.isNull()) {
return cb(null, file);
}
const MISSING_COMPILER_MESSAGE = `
gulp-sass 5 does not have a default Sass compiler; please set one yourself.
Both the "sass" and "node-sass" packages are permitted.
For example, in your gulpfile:

const sass = require('gulp-sass')(require('sass'));
`;

/**
* Handles returning the file to the stream
*/
const filePush = (file, sassObject, callback) => {
// Build Source Maps!
if (sassObject.map) {
// Transform map into JSON
const sassMap = JSON.parse(sassObject.map.toString());
// Grab the stdout and transform it into stdin
const sassMapFile = sassMap.file.replace(/^stdout$/, 'stdin');
// Grab the base filename that's being worked on
const sassFileSrc = file.relative;
// Grab the path portion of the file that's being worked on
const sassFileSrcPath = path.dirname(sassFileSrc);

if (sassFileSrcPath) {
const sourceFileIndex = sassMap.sources.indexOf(sassMapFile);
// Prepend the path to all files in the sources array except the file that's being worked on
sassMap.sources = sassMap.sources.map((source, index) => (
index === sourceFileIndex
? source
: path.join(sassFileSrcPath, source)
));
}

if (file.isStream()) {
return cb(new PluginError(PLUGIN_NAME, 'Streaming not supported'));
}
// Remove 'stdin' from souces and replace with filenames!
sassMap.sources = sassMap.sources.filter((src) => src !== 'stdin' && src);

if (path.basename(file.path).startsWith('_')) {
return cb();
// Replace the map file with the original filename (but new extension)
sassMap.file = replaceExtension(sassFileSrc, '.css');
// Apply the map
applySourceMap(file, sassMap);
}

if (!file.contents.length) {
file.path = replaceExtension(file.path, '.css'); // eslint-disable-line no-param-reassign
return cb(null, file);
file.contents = sassObject.css;
file.path = replaceExtension(file.path, '.css');

if (file.stat) {
file.stat.atime = file.stat.mtime = file.stat.ctime = new Date();
}

const opts = clonedeep(options || {});
opts.data = file.contents.toString();
callback(null, file);
};

/**
* Handles error message
*/
const handleError = (error, file, callback) => {
const filePath = (error.file === 'stdin' ? file.path : error.file) || file.path;
const relativePath = path.relative(process.cwd(), filePath);
const message = [chalk.underline(relativePath), error.formatted].join('\n');

// we set the file path here so that libsass can correctly resolve import paths
opts.file = file.path;
error.messageFormatted = message;
error.messageOriginal = error.message;
error.message = stripAnsi(message);
error.relativePath = relativePath;

// Ensure `indentedSyntax` is true if a `.sass` file
if (path.extname(file.path) === '.sass') {
opts.indentedSyntax = true;
}
return callback(new PluginError(PLUGIN_NAME, error));
};

// Ensure file's parent directory in the include path
if (opts.includePaths) {
if (typeof opts.includePaths === 'string') {
opts.includePaths = [opts.includePaths];
/**
* Main Gulp Sass function
*/

// eslint-disable-next-line arrow-body-style
const gulpSass = (options, sync) => {
// eslint-disable-next-line consistent-return
return transfob((file, encoding, callback) => {
if (file.isNull()) {
return callback(null, file);
}

if (file.isStream()) {
return callback(new PluginError(PLUGIN_NAME, 'Streaming not supported'));
}
} else {
opts.includePaths = [];
}

opts.includePaths.unshift(path.dirname(file.path));
if (path.basename(file.path).startsWith('_')) {
return callback();
}

// Generate Source Maps if plugin source-map present
if (file.sourceMap) {
opts.sourceMap = file.path;
opts.omitSourceMapUrl = true;
opts.sourceMapContents = true;
}
if (!file.contents.length) {
file.path = replaceExtension(file.path, '.css');
return callback(null, file);
}

/// ///////////////////////////
// Handles returning the file to the stream
/// ///////////////////////////
const filePush = (sassObj) => {
let sassMap;
let sassMapFile;
let sassFileSrc;
let sassFileSrcPath;
let sourceFileIndex;

// Build Source Maps!
if (sassObj.map) {
// Transform map into JSON
sassMap = JSON.parse(sassObj.map.toString());
// Grab the stdout and transform it into stdin
sassMapFile = sassMap.file.replace(/^stdout$/, 'stdin');
// Grab the base file name that's being worked on
sassFileSrc = file.relative;
// Grab the path portion of the file that's being worked on
sassFileSrcPath = path.dirname(sassFileSrc);
if (sassFileSrcPath) {
// Prepend the path to all files in the sources array except the file that's being worked on
sourceFileIndex = sassMap.sources.indexOf(sassMapFile);
sassMap.sources = sassMap.sources.map((source, index) => { // eslint-disable-line arrow-body-style
return index === sourceFileIndex ? source : path.join(sassFileSrcPath, source);
});
}
const opts = clonedeep(options || {});
opts.data = file.contents.toString();

// We set the file path here so that libsass can correctly resolve import paths
opts.file = file.path;

// Remove 'stdin' from souces and replace with filenames!
sassMap.sources = sassMap.sources.filter((src) => src !== 'stdin' && src);
// Ensure `indentedSyntax` is true if a `.sass` file
if (path.extname(file.path) === '.sass') {
opts.indentedSyntax = true;
}

// Replace the map file with the original file name (but new extension)
sassMap.file = replaceExtension(sassFileSrc, '.css');
// Apply the map
applySourceMap(file, sassMap);
// Ensure file's parent directory in the include path
if (opts.includePaths) {
if (typeof opts.includePaths === 'string') {
opts.includePaths = [opts.includePaths];
}
} else {
opts.includePaths = [];
}

file.contents = sassObj.css; // eslint-disable-line no-param-reassign
file.path = replaceExtension(file.path, '.css'); // eslint-disable-line no-param-reassign
opts.includePaths.unshift(path.dirname(file.path));

if (file.stat) {
file.stat.atime = file.stat.mtime = file.stat.ctime = new Date(); // eslint-disable-line
// Generate Source Maps if the source-map plugin is present
if (file.sourceMap) {
opts.sourceMap = file.path;
opts.omitSourceMapUrl = true;
opts.sourceMapContents = true;
}

cb(null, file);
};

/// ///////////////////////////
// Handles error message
/// ///////////////////////////
const errorM = (error) => {
const filePath = (error.file === 'stdin' ? file.path : error.file) || file.path;
const relativePath = path.relative(process.cwd(), filePath);
const message = [chalk.underline(relativePath), error.formatted].join('\n');

error.messageFormatted = message; // eslint-disable-line no-param-reassign
error.messageOriginal = error.message; // eslint-disable-line no-param-reassign
error.message = stripAnsi(message); // eslint-disable-line no-param-reassign
error.relativePath = relativePath; // eslint-disable-line no-param-reassign

return cb(new PluginError(PLUGIN_NAME, error));
};

if (sync !== true) {
/// ///////////////////////////
// Async Sass render
/// ///////////////////////////
const callback = (error, obj) => { // eslint-disable-line consistent-return
if (error) {
return errorM(error);
if (sync !== true) {
/**
* Async Sass render
*/
// eslint-disable-next-line consistent-return
gulpSass.compiler.render(opts, (error, obj) => {
if (error) {
return handleError(error, file, callback);
}

filePush(file, obj, callback);
});
} else {
/**
* Sync Sass render
*/
try {
filePush(file, gulpSass.compiler.renderSync(opts), callback);
} catch (error) {
return handleError(error, file, callback);
}
filePush(obj);
};

gulpSass.compiler.render(opts, callback);
} else {
/// ///////////////////////////
// Sync Sass render
/// ///////////////////////////
try {
filePush(gulpSass.compiler.renderSync(opts));
} catch (error) {
return errorM(error);
}
}
});
});
};

/// ///////////////////////////
// Sync Sass render
/// ///////////////////////////
/**
* Sync Sass render
*/
gulpSass.sync = (options) => gulpSass(options, true);

/// ///////////////////////////
// Log errors nicely
/// ///////////////////////////
/**
* Log errors nicely
*/
gulpSass.logError = function logError(error) {
const message = new PluginError('sass', error.messageFormatted).toString();
process.stderr.write(`${message}\n`);
Expand All @@ -164,17 +176,13 @@ module.exports = (compiler) => {
if (!compiler || !compiler.render) {
const message = new PluginError(
PLUGIN_NAME,
'\n'
+ 'gulp-sass 5 does not have a default Sass compiler; please set one yourself.\n'
+ 'Both the `sass` and `node-sass` packages are permitted.\n'

+ 'For example, in your gulpfile:\n\n'
+ ' var sass = require(\'gulp-sass\')(require(\'sass\'));\n',
MISSING_COMPILER_MESSAGE,
{ showProperties: false },
).toString();
process.stderr.write(`${message}\n`);
process.exit(1);
}

gulpSass.compiler = compiler;
return gulpSass;
};
2 changes: 2 additions & 0 deletions test/main.js
@@ -1,3 +1,5 @@
'use strict';

const fs = require('fs');
const path = require('path');
const should = require('should');
Expand Down