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 1 commit
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"
262 changes: 135 additions & 127 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:

if (file.isStream()) {
return cb(new PluginError(PLUGIN_NAME, 'Streaming not supported'));
}
const sass = require('gulp-sass')(require('sass'));
`;

if (path.basename(file.path).startsWith('_')) {
return cb();
}
/*
Main Gulp Sass function
*/

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

const opts = clonedeep(options || {});
opts.data = file.contents.toString();
// eslint-disable-next-line arrow-body-style
const gulpSass = (options, sync) => {
// eslint-disable-next-line consistent-return
return transfob((file, enc, cb) => {
if (file.isNull()) {
return cb(null, file);
}

// we set the file path here so that libsass can correctly resolve import paths
opts.file = file.path;
if (file.isStream()) {
return cb(new PluginError(PLUGIN_NAME, 'Streaming not supported'));
}

// Ensure `indentedSyntax` is true if a `.sass` file
if (path.extname(file.path) === '.sass') {
opts.indentedSyntax = true;
}
if (path.basename(file.path).startsWith('_')) {
return cb();
}

// Ensure file's parent directory in the include path
if (opts.includePaths) {
if (typeof opts.includePaths === 'string') {
opts.includePaths = [opts.includePaths];
if (!file.contents.length) {
file.path = replaceExtension(file.path, '.css');
return cb(null, file);
}
} else {
opts.includePaths = [];
}

opts.includePaths.unshift(path.dirname(file.path));
const opts = clonedeep(options || {});
opts.data = file.contents.toString();

// Generate Source Maps if plugin source-map present
if (file.sourceMap) {
opts.sourceMap = file.path;
opts.omitSourceMapUrl = true;
opts.sourceMapContents = true;
}
// We set the file path here so that libsass can correctly resolve import paths
opts.file = file.path;

// Ensure `indentedSyntax` is true if a `.sass` file
if (path.extname(file.path) === '.sass') {
opts.indentedSyntax = true;
}

/// ///////////////////////////
// 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);
});
// Ensure file's parent directory in the include path
if (opts.includePaths) {
if (typeof opts.includePaths === 'string') {
opts.includePaths = [opts.includePaths];
}
} else {
opts.includePaths = [];
}

// Remove 'stdin' from souces and replace with filenames!
sassMap.sources = sassMap.sources.filter((src) => src !== 'stdin' && src);
opts.includePaths.unshift(path.dirname(file.path));

// Replace the map file with the original file name (but new extension)
sassMap.file = replaceExtension(sassFileSrc, '.css');
// Apply the map
applySourceMap(file, sassMap);
// Generate Source Maps if the source-map plugin is present
if (file.sourceMap) {
opts.sourceMap = file.path;
opts.omitSourceMapUrl = true;
opts.sourceMapContents = true;
}

file.contents = sassObj.css; // eslint-disable-line no-param-reassign
file.path = replaceExtension(file.path, '.css'); // eslint-disable-line no-param-reassign
/*
Handles returning the file to the stream
*/
const filePush = (sassObj) => {
// Build Source Maps!
if (sassObj.map) {
// Transform map into JSON
const sassMap = JSON.parse(sassObj.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)
));
}

// Remove 'stdin' from souces and replace with filenames!
sassMap.sources = sassMap.sources.filter((src) => src !== 'stdin' && src);

// Replace the map file with the original filename (but new extension)
sassMap.file = replaceExtension(sassFileSrc, '.css');
// Apply the map
applySourceMap(file, sassMap);
}

if (file.stat) {
file.stat.atime = file.stat.mtime = file.stat.ctime = new Date(); // eslint-disable-line
}
file.contents = sassObj.css;
file.path = replaceExtension(file.path, '.css');

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 (file.stat) {
file.stat.atime = file.stat.mtime = file.stat.ctime = new Date();
}
filePush(obj);

cb(null, file);
};

gulpSass.compiler.render(opts, callback);
} else {
/// ///////////////////////////
// Sync Sass render
/// ///////////////////////////
try {
filePush(gulpSass.compiler.renderSync(opts));
} catch (error) {
return errorM(error);
/*
Handles error message
*/
const handleError = (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;
error.messageOriginal = error.message;
error.message = stripAnsi(message);
error.relativePath = relativePath;

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

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

filePush(obj);
});
} else {
/*
Sync Sass render
*/
try {
filePush(gulpSass.compiler.renderSync(opts));
} catch (error) {
return handleError(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