提交 56debcb7 编写于 作者: M maguohua

updata

上级 fd457d76
## v3.10.1
https://github.com/sass/node-sass/releases/tag/v3.10.1
## v3.10.0
https://github.com/sass/node-sass/releases/tag/v3.10.0
## v3.9.3
https://github.com/sass/node-sass/releases/tag/v3.9.3
## v3.9.2
(removed)
## v3.9.1
(removed)
## v3.9.0
https://github.com/sass/node-sass/releases/tag/v3.9.0
## v3.8.0
https://github.com/sass/node-sass/releases/tag/v3.8.0
## v3.7.0
https://github.com/sass/node-sass/releases/tag/v3.7.0
## v3.6.0
https://github.com/sass/node-sass/releases/tag/v3.6.0
## v3.5.3
https://github.com/sass/node-sass/releases/tag/v3.5.3
## v3.5.2
https://github.com/sass/node-sass/releases/tag/v3.5.2
## v3.5.1
https://github.com/sass/node-sass/releases/tag/v3.5.1
## v3.5.0
(removed)
## v3.4.2
https://github.com/sass/node-sass/releases/tag/v3.4.2
## v3.4.1
https://github.com/sass/node-sass/releases/tag/v3.4.1
## v3.4.0
https://github.com/sass/node-sass/releases/tag/v3.4.0
## v3.3.3
https://github.com/sass/node-sass/releases/tag/v3.3.3
## v3.3.2
https://github.com/sass/node-sass/releases/tag/v3.3.2
## v3.3.1
https://github.com/sass/node-sass/releases/tag/v3.3.1
## v3.3.0
https://github.com/sass/node-sass/releases/tag/v3.3.0
## v3.2.0
https://github.com/sass/node-sass/releases/tag/v3.2.0
## v3.1.2
https://github.com/sass/node-sass/releases/tag/v3.1.2
## v3.1.1
https://github.com/sass/node-sass/releases/tag/v3.1.1
## v3.1.0
https://github.com/sass/node-sass/releases/tag/v3.1.0
## v3.0.0
https://github.com/sass/node-sass/releases/tag/v3.0.0
Copyright (c) 2013-2016 Andrew Nesbitt
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
此差异已折叠。
#!/usr/bin/env node
var Emitter = require('events').EventEmitter,
forEach = require('async-foreach').forEach,
Gaze = require('gaze'),
grapher = require('sass-graph'),
meow = require('meow'),
util = require('util'),
path = require('path'),
glob = require('glob'),
sass = require('../lib'),
render = require('../lib/render'),
stdin = require('get-stdin'),
fs = require('fs');
/**
* Initialize CLI
*/
var cli = meow({
pkg: '../package.json',
version: sass.info,
help: [
'Usage:',
' node-sass [options] <input.scss>',
' cat <input.scss> | node-sass [options] > output.css',
'',
'Example: Compile foobar.scss to foobar.css',
' node-sass --output-style compressed foobar.scss > foobar.css',
' cat foobar.scss | node-sass --output-style compressed > foobar.css',
'',
'Example: Watch the sass directory for changes, compile with sourcemaps to the css directory',
' node-sass --watch --recursive --output css',
' --source-map true --source-map-contents sass',
'',
'Options',
' -w, --watch Watch a directory or file',
' -r, --recursive Recursively watch directories or files',
' -o, --output Output directory',
' -x, --omit-source-map-url Omit source map URL comment from output',
' -i, --indented-syntax Treat data from stdin as sass code (versus scss)',
' -q, --quiet Suppress log output except on error',
' -v, --version Prints version info',
' --output-style CSS output style (nested | expanded | compact | compressed)',
' --indent-type Indent type for output CSS (space | tab)',
' --indent-width Indent width; number of spaces or tabs (maximum value: 10)',
' --linefeed Linefeed style (cr | crlf | lf | lfcr)',
' --source-comments Include debug info in output',
' --source-map Emit source map',
' --source-map-contents Embed include contents in map',
' --source-map-embed Embed sourceMappingUrl as data URI',
' --source-map-root Base path, will be emitted in source-map as is',
' --include-path Path to look for imported files',
' --follow Follow symlinked directories',
' --precision The amount of precision allowed in decimal numbers',
' --error-bell Output a bell character on errors',
' --importer Path to .js file containing custom importer',
' --functions Path to .js file containing custom functions',
' --help Print usage info'
].join('\n')
}, {
boolean: [
'error-bell',
'follow',
'indented-syntax',
'omit-source-map-url',
'quiet',
'recursive',
'source-map-embed',
'source-map-contents',
'source-comments',
'watch'
],
string: [
'functions',
'importer',
'include-path',
'indent-type',
'linefeed',
'output',
'output-style',
'precision',
'source-map-root'
],
alias: {
c: 'source-comments',
i: 'indented-syntax',
q: 'quiet',
o: 'output',
r: 'recursive',
x: 'omit-source-map-url',
v: 'version',
w: 'watch'
},
default: {
'include-path': process.cwd(),
'indent-type': 'space',
'indent-width': 2,
linefeed: 'lf',
'output-style': 'nested',
precision: 5,
quiet: false,
recursive: true
}
});
/**
* Is a Directory
*
* @param {String} filePath
* @returns {Boolean}
* @api private
*/
function isDirectory(filePath) {
var isDir = false;
try {
var absolutePath = path.resolve(filePath);
isDir = fs.statSync(absolutePath).isDirectory();
} catch (e) {
isDir = e.code === 'ENOENT';
}
return isDir;
}
/**
* Get correct glob pattern
*
* @param {Object} options
* @returns {String}
* @api private
*/
function globPattern(options) {
return options.recursive ? '**/*.{sass,scss}' : '*.{sass,scss}';
}
/**
* Create emitter
*
* @api private
*/
function getEmitter() {
var emitter = new Emitter();
emitter.on('error', function(err) {
if (options.errorBell) {
err += '\x07';
}
console.error(err);
if (!options.watch) {
process.exit(1);
}
});
emitter.on('warn', function(data) {
if (!options.quiet) {
console.warn(data);
}
});
emitter.on('log', function(data) {
console.log(data);
});
emitter.on('done', function() {
if (!options.watch && !options.directory) {
process.exit();
}
});
return emitter;
}
/**
* Construct options
*
* @param {Array} arguments
* @param {Object} options
* @api private
*/
function getOptions(args, options) {
var cssDir, sassDir, file, mapDir;
options.src = args[0];
if (args[1]) {
options.dest = path.resolve(args[1]);
} else if (options.output) {
options.dest = path.join(
path.resolve(options.output),
[path.basename(options.src, path.extname(options.src)), '.css'].join('')); // replace ext.
}
if (options.directory) {
sassDir = path.resolve(options.directory);
file = path.relative(sassDir, args[0]);
cssDir = path.resolve(options.output);
options.dest = path.join(cssDir, file).replace(path.extname(file), '.css');
}
if (options.sourceMap) {
if(!options.sourceMapOriginal) {
options.sourceMapOriginal = options.sourceMap;
}
// check if sourceMap path ends with .map to avoid isDirectory false-positive
var sourceMapIsDirectory = options.sourceMapOriginal.indexOf('.map', options.sourceMapOriginal.length - 4) === -1 && isDirectory(options.sourceMapOriginal);
if (options.sourceMapOriginal === 'true') {
options.sourceMap = options.dest + '.map';
} else if (!sourceMapIsDirectory) {
options.sourceMap = path.resolve(options.sourceMapOriginal);
} else if (sourceMapIsDirectory) {
if (!options.directory) {
options.sourceMap = path.resolve(options.sourceMapOriginal, path.basename(options.dest) + '.map');
} else {
sassDir = path.resolve(options.directory);
file = path.relative(sassDir, args[0]);
mapDir = path.resolve(options.sourceMapOriginal);
options.sourceMap = path.join(mapDir, file).replace(path.extname(file), '.css.map');
}
}
}
return options;
}
/**
* Watch
*
* @param {Object} options
* @param {Object} emitter
* @api private
*/
function watch(options, emitter) {
var buildGraph = function(options) {
var graph;
var graphOptions = {
loadPaths: options.includePath,
extensions: ['scss', 'sass', 'css']
};
if (options.directory) {
graph = grapher.parseDir(options.directory, graphOptions);
} else {
graph = grapher.parseFile(options.src, graphOptions);
}
return graph;
};
var watch = [];
var graph = buildGraph(options);
// Add all files to watch list
for (var i in graph.index) {
watch.push(i);
}
var gaze = new Gaze();
gaze.add(watch);
gaze.on('error', emitter.emit.bind(emitter, 'error'));
gaze.on('changed', function(file) {
var files = [file];
// descendents may be added, so we need a new graph
graph = buildGraph(options);
graph.visitAncestors(file, function(parent) {
files.push(parent);
});
// Add children to watcher
graph.visitDescendents(file, function(child) {
gaze.add(child);
});
files.forEach(function(file) {
if (path.basename(file)[0] !== '_') {
renderFile(file, options, emitter);
}
});
});
gaze.on('added', function() {
graph = buildGraph(options);
});
gaze.on('deleted', function() {
graph = buildGraph(options);
});
}
/**
* Run
*
* @param {Object} options
* @param {Object} emitter
* @api private
*/
function run(options, emitter) {
if (!Array.isArray(options.includePath)) {
options.includePath = [options.includePath];
}
if (options.directory) {
if (!options.output) {
emitter.emit('error', 'An output directory must be specified when compiling a directory');
}
if (!isDirectory(options.output)) {
emitter.emit('error', 'An output directory must be specified when compiling a directory');
}
}
if (options.sourceMapOriginal && options.directory && !isDirectory(options.sourceMapOriginal) && options.sourceMapOriginal !== 'true') {
emitter.emit('error', 'The --source-map option must be either a boolean or directory when compiling a directory');
}
if (options.importer) {
if ((path.resolve(options.importer) === path.normalize(options.importer).replace(/(.+)([\/|\\])$/, '$1'))) {
options.importer = require(options.importer);
} else {
options.importer = require(path.resolve(options.importer));
}
}
if (options.functions) {
if ((path.resolve(options.functions) === path.normalize(options.functions).replace(/(.+)([\/|\\])$/, '$1'))) {
options.functions = require(options.functions);
} else {
options.functions = require(path.resolve(options.functions));
}
}
if (options.watch) {
watch(options, emitter);
} else if (options.directory) {
renderDir(options, emitter);
} else {
render(options, emitter);
}
}
/**
* Render a file
*
* @param {String} file
* @param {Object} options
* @param {Object} emitter
* @api private
*/
function renderFile(file, options, emitter) {
options = getOptions([path.resolve(file)], options);
if (options.watch) {
emitter.emit('warn', util.format('=> changed: %s', file));
}
render(options, emitter);
}
/**
* Render all sass files in a directory
*
* @param {Object} options
* @param {Object} emitter
* @api private
*/
function renderDir(options, emitter) {
var globPath = path.resolve(options.directory, globPattern(options));
glob(globPath, { ignore: '**/_*', follow: options.follow }, function(err, files) {
if (err) {
return emitter.emit('error', util.format('You do not have permission to access this path: %s.', err.path));
} else if (!files.length) {
return emitter.emit('error', 'No input file was found.');
}
forEach(files, function(subject) {
emitter.once('done', this.async());
renderFile(subject, options, emitter);
}, function(successful, arr) {
var outputDir = path.join(process.cwd(), options.output);
emitter.emit('warn', util.format('Wrote %s CSS files to %s', arr.length, outputDir));
process.exit();
});
});
}
/**
* Arguments and options
*/
var options = getOptions(cli.input, cli.flags);
var emitter = getEmitter();
/**
* Show usage if no arguments are supplied
*/
if (!options.src && process.stdin.isTTY) {
emitter.emit('error', [
'Provide a Sass file to render',
'',
'Example: Compile foobar.scss to foobar.css',
' node-sass --output-style compressed foobar.scss > foobar.css',
' cat foobar.scss | node-sass --output-style compressed > foobar.css',
'',
'Example: Watch the sass directory for changes, compile with sourcemaps to the css directory',
' node-sass --watch --recursive --output css',
' --source-map true --source-map-contents sass',
].join('\n'));
}
/**
* Apply arguments
*/
if (options.src) {
if (isDirectory(options.src)) {
options.directory = options.src;
}
run(options, emitter);
} else if (!process.stdin.isTTY) {
stdin(function(data) {
options.data = data;
options.stdin = true;
run(options, emitter);
});
}
return emitter;
{
'variables': {
'libsass_ext%': '',
},
'targets': [
{
'target_name': 'binding',
'win_delay_load_hook': 'true',
'sources': [
'src/binding.cpp',
'src/create_string.cpp',
'src/custom_function_bridge.cpp',
'src/custom_importer_bridge.cpp',
'src/sass_context_wrapper.cpp',
'src/sass_types/boolean.cpp',
'src/sass_types/color.cpp',
'src/sass_types/error.cpp',
'src/sass_types/factory.cpp',
'src/sass_types/list.cpp',
'src/sass_types/map.cpp',
'src/sass_types/null.cpp',
'src/sass_types/number.cpp',
'src/sass_types/string.cpp'
],
'msvs_settings': {
'VCLinkerTool': {
'SetChecksum': 'true'
}
},
'xcode_settings': {
'OTHER_CPLUSPLUSFLAGS': [
'-std=c++11'
],
'OTHER_LDFLAGS': [],
'GCC_ENABLE_CPP_EXCEPTIONS': 'NO',
'MACOSX_DEPLOYMENT_TARGET': '10.7'
},
'include_dirs': [
'<!(node -e "require(\'nan\')")',
],
'conditions': [
['libsass_ext == "" or libsass_ext == "no"', {
'dependencies': [
'src/libsass.gyp:libsass',
]
}],
['libsass_ext == "auto"', {
'cflags_cc': [
'<!(pkg-config --cflags libsass)',
],
'link_settings': {
'ldflags': [
'<!(pkg-config --libs-only-other --libs-only-L libsass)',
],
'libraries': [
'<!(pkg-config --libs-only-l libsass)',
],
}
}],
['libsass_ext == "yes"', {
'cflags_cc': [
'<(libsass_cflags)',
],
'link_settings': {
'ldflags': [
'<(libsass_ldflags)',
],
'libraries': [
'<(libsass_library)',
],
}
}],
['OS=="win" and MSVS_VERSION == "2015"', {
'msvs_settings': {
'VCCLCompilerTool': {
'AdditionalOptions': [
# disable Thread-Safe "Magic" for local static variables
'/Zc:threadSafeInit-',
],
},
},
}],
['OS!="win"', {
'cflags_cc+': [
'-std=c++0x'
]
}]
]
}
]
}
/*!
* node-sass: lib/binding.js
*/
var errors = require('./errors');
/**
* Require binding
*/
module.exports = function(ext) {
if (!ext.hasBinary(ext.getBinaryPath())) {
if (!ext.isSupportedEnvironment()) {
throw new Error(errors.unsupportedEnvironment());
} else {
throw new Error(errors.missingBinary());
}
}
return require(ext.getBinaryPath());
};
/*!
* node-sass: lib/errors.js
*/
var sass = require('./extensions'),
pkg = require('../package.json');
function humanEnvironment() {
return sass.getHumanEnvironment(sass.getBinaryName());
}
function foundBinaries() {
return [
'Found bindings for the following environments:',
foundBinariesList(),
].join('\n');
}
function foundBinariesList() {
return sass.getInstalledBinaries().map(function(env) {
return ' - ' + sass.getHumanEnvironment(env);
}).join('\n');
}
function missingBinaryFooter() {
return [
'This usually happens because your environment has changed since running `npm install`.',
'Run `npm rebuild node-sass` to build the binding for your current environment.',
].join('\n');
}
module.exports.unsupportedEnvironment = function() {
return [
'Node Sass does not yet support your current environment: ' + humanEnvironment(),
'For more information on which environments are supported please see:',
'https://github.com/sass/node-sass/releases/tag/v' + pkg.version
].join('\n');
};
module.exports.missingBinary = function() {
return [
'Missing binding ' + sass.getBinaryPath(),
'Node Sass could not find a binding for your current environment: ' + humanEnvironment(),
'',
foundBinaries(),
'',
missingBinaryFooter(),
].join('\n');
};
/*!
* node-sass: lib/extensions.js
*/
var eol = require('os').EOL,
fs = require('fs'),
pkg = require('../package.json'),
mkdir = require('mkdirp'),
path = require('path'),
defaultBinaryPath = path.join(__dirname, '..', 'vendor');
/**
* Get the human readable name of the Platform that is running
*
* @param {string} platform - An OS platform to match, or null to fallback to
* the current process platform
* @return {Object} The name of the platform if matched, false otherwise
*
* @api public
*/
function getHumanPlatform(platform) {
switch (platform || process.platform) {
case 'darwin': return 'OS X';
case 'freebsd': return 'FreeBSD';
case 'linux': return 'Linux';
case 'win32': return 'Windows';
default: return false;
}
}
/**
* Provides a more readable version of the architecture
*
* @param {string} arch - An instruction architecture name to match, or null to
* lookup the current process architecture
* @return {Object} The value of the process architecture, or false if unknown
*
* @api public
*/
function getHumanArchitecture(arch) {
switch (arch || process.arch) {
case 'ia32': return '32-bit';
case 'x86': return '32-bit';
case 'x64': return '64-bit';
default: return false;
}
}
/**
* Get the friendly name of the Node environment being run
*
* @param {Object} abi - A Node Application Binary Interface value, or null to
* fallback to the current Node ABI
* @return {Object} Returns a string name of the Node environment or false if
* unmatched
*
* @api public
*/
function getHumanNodeVersion(abi) {
switch (parseInt(abi || process.versions.modules, 10)) {
case 11: return 'Node 0.10.x';
case 14: return 'Node 0.12.x';
case 42: return 'io.js 1.x';
case 43: return 'io.js 1.1.x';
case 44: return 'io.js 2.x';
case 45: return 'io.js 3.x';
case 46: return 'Node.js 4.x';
case 47: return 'Node.js 5.x';
case 48: return 'Node.js 6.x';
case 51: return 'Node.js 7.x';
default: return false;
}
}
/**
* Get a human readable description of where node-sass is running to support
* user error reporting when something goes wrong
*
* @param {string} env - The name of the native bindings that is to be parsed
* @return {string} A description of what os, architecture, and Node version
* that is being run
*
* @api public
*/
function getHumanEnvironment(env) {
var binding = env.replace(/_binding\.node$/, ''),
parts = binding.split('-'),
platform = getHumanPlatform(parts[0]),
arch = getHumanArchitecture(parts[1]),
runtime = getHumanNodeVersion(parts[2]);
if (parts.length !== 3) {
return 'Unknown environment (' + binding + ')';
}
if (!platform) {
platform = 'Unsupported platform (' + parts[0] + ')';
}
if (!arch) {
arch = 'Unsupported architecture (' + parts[1] + ')';
}
if (!runtime) {
runtime = 'Unsupported runtime (' + parts[2] + ')';
}
return [
platform, arch, 'with', runtime,
].join(' ');
}
/**
* Get the value of the binaries under the default path
*
* @return {Array} The currently installed node-sass bindings
*
* @api public
*/
function getInstalledBinaries() {
return fs.readdirSync(defaultBinaryPath);
}
/**
* Check that an environment matches the whitelisted values or the current
* environment if no parameters are passed
*
* @param {string} platform - The name of the OS platform(darwin, win32, etc...)
* @param {string} arch - The instruction set architecture of the Node environment
* @param {string} abi - The Node Application Binary Interface
* @return {Boolean} True, if node-sass supports the current platform, false otherwise
*
* @api public
*/
function isSupportedEnvironment(platform, arch, abi) {
return (
false !== getHumanPlatform(platform) &&
false !== getHumanArchitecture(arch) &&
false !== getHumanNodeVersion(abi)
);
}
/**
* Get the value of a CLI argument
*
* @param {String} name
* @param {Array} args
* @api private
*/
function getArgument(name, args) {
var flags = args || process.argv.slice(2),
index = flags.lastIndexOf(name);
if (index === -1 || index + 1 >= flags.length) {
return null;
}
return flags[index + 1];
}
/**
* Get binary name.
* If environment variable SASS_BINARY_NAME,
* .npmrc variable sass_binary_name or
* process argument --binary-name is provided,
* return it as is, otherwise make default binary
* name: {platform}-{arch}-{v8 version}.node
*
* @api public
*/
function getBinaryName() {
var binaryName;
if (getArgument('--sass-binary-name')) {
binaryName = getArgument('--sass-binary-name');
} else if (process.env.SASS_BINARY_NAME) {
binaryName = process.env.SASS_BINARY_NAME;
} else if (process.env.npm_config_sass_binary_name) {
binaryName = process.env.npm_config_sass_binary_name;
} else if (pkg.nodeSassConfig && pkg.nodeSassConfig.binaryName) {
binaryName = pkg.nodeSassConfig.binaryName;
} else {
binaryName = [
process.platform, '-',
process.arch, '-',
process.versions.modules
].join('');
}
return [binaryName, 'binding.node'].join('_');
}
/**
* Determine the URL to fetch binary file from.
* By default fetch from the node-sass distribution
* site on GitHub.
*
* The default URL can be overriden using
* the environment variable SASS_BINARY_SITE,
* .npmrc variable sass_binary_site or
* or a command line option --sass-binary-site:
*
* node scripts/install.js --sass-binary-site http://example.com/
*
* The URL should to the mirror of the repository
* laid out as follows:
*
* SASS_BINARY_SITE/
*
* v3.0.0
* v3.0.0/freebsd-x64-14_binding.node
* ....
* v3.0.0
* v3.0.0/freebsd-ia32-11_binding.node
* v3.0.0/freebsd-x64-42_binding.node
* ... etc. for all supported versions and platforms
*
* @api public
*/
function getBinaryUrl() {
var site = getArgument('--sass-binary-site') ||
process.env.SASS_BINARY_SITE ||
process.env.npm_config_sass_binary_site ||
(pkg.nodeSassConfig && pkg.nodeSassConfig.binarySite) ||
'https://github.com/sass/node-sass/releases/download';
return [site, 'v' + pkg.version, getBinaryName()].join('/');
}
/**
* Get binary path.
* If environment variable SASS_BINARY_PATH,
* .npmrc variable sass_binary_path or
* process argument --sass-binary-path is provided,
* select it by appending binary name, otherwise
* make default binary path using binary name.
* Once the primary selection is made, check if
* callers wants to throw if file not exists before
* returning.
*
* @api public
*/
function getBinaryPath() {
var binaryPath;
if (getArgument('--sass-binary-path')) {
binaryPath = getArgument('--sass-binary-path');
} else if (process.env.SASS_BINARY_PATH) {
binaryPath = process.env.SASS_BINARY_PATH;
} else if (process.env.npm_config_sass_binary_path) {
binaryPath = process.env.npm_config_sass_binary_path;
} else if (pkg.nodeSassConfig && pkg.nodeSassConfig.binaryPath) {
binaryPath = pkg.nodeSassConfig.binaryPath;
} else {
binaryPath = path.join(defaultBinaryPath, getBinaryName().replace(/_/, '/'));
}
return binaryPath;
}
/**
* An array of paths suitable for use as a local disk cache of the binding.
*
* @return {[]String} an array of paths
* @api public
*/
function getCachePathCandidates() {
return [
process.env.npm_config_sass_binary_cache,
process.env.npm_config_cache,
].filter(function(_) { return _; });
}
/**
* The most suitable location for caching the binding on disk.
*
* Given the candidates directories provided by `getCachePathCandidates()` this
* returns the first writable directory. By treating the candidate directories
* as a prioritised list this method is deterministic, assuming no change to the
* local environment.
*
* @return {String} directory to cache binding
* @api public
*/
function getBinaryCachePath() {
var i,
cachePath,
cachePathCandidates = getCachePathCandidates();
for (i = 0; i < cachePathCandidates.length; i++) {
cachePath = path.join(cachePathCandidates[i], pkg.name, pkg.version);
try {
mkdir.sync(cachePath);
return cachePath;
} catch (e) {
// Directory is not writable, try another
}
}
return '';
}
/**
* The cached binding
*
* Check the candidates directories provided by `getCachePathCandidates()` for
* the binding file, if it exists. By treating the candidate directories
* as a prioritised list this method is deterministic, assuming no change to the
* local environment.
*
* @return {String} path to cached binary
* @api public
*/
function getCachedBinary() {
var i,
cachePath,
cacheBinary,
cachePathCandidates = getCachePathCandidates(),
binaryName = getBinaryName();
for (i = 0; i < cachePathCandidates.length; i++) {
cachePath = path.join(cachePathCandidates[i], pkg.name, pkg.version);
cacheBinary = path.join(cachePath, binaryName);
if (fs.existsSync(cacheBinary)) {
return cacheBinary;
}
}
return '';
}
/**
* Does the supplied binary path exist
*
* @param {String} binaryPath
* @api public
*/
function hasBinary(binaryPath) {
return fs.existsSync(binaryPath);
}
/**
* Get Sass version information
*
* @api public
*/
function getVersionInfo(binding) {
return [
['node-sass', pkg.version, '(Wrapper)', '[JavaScript]'].join('\t'),
['libsass ', binding.libsassVersion(), '(Sass Compiler)', '[C/C++]'].join('\t'),
].join(eol);
}
module.exports.hasBinary = hasBinary;
module.exports.getBinaryUrl = getBinaryUrl;
module.exports.getBinaryName = getBinaryName;
module.exports.getBinaryPath = getBinaryPath;
module.exports.getBinaryCachePath = getBinaryCachePath;
module.exports.getCachedBinary = getCachedBinary;
module.exports.getCachePathCandidates = getCachePathCandidates;
module.exports.getVersionInfo = getVersionInfo;
module.exports.getHumanEnvironment = getHumanEnvironment;
module.exports.getInstalledBinaries = getInstalledBinaries;
module.exports.isSupportedEnvironment = isSupportedEnvironment;
/*!
* node-sass: lib/index.js
*/
var path = require('path'),
clonedeep = require('lodash.clonedeep'),
assign = require('lodash.assign'),
sass = require('./extensions');
/**
* Require binding
*/
var binding = require('./binding')(sass);
/**
* Get input file
*
* @param {Object} options
* @api private
*/
function getInputFile(options) {
return options.file ? path.resolve(options.file) : null;
}
/**
* Get output file
*
* @param {Object} options
* @api private
*/
function getOutputFile(options) {
var outFile = options.outFile;
if (!outFile || typeof outFile !== 'string' || (!options.data && !options.file)) {
return null;
}
return path.resolve(outFile);
}
/**
* Get source map
*
* @param {Object} options
* @api private
*/
function getSourceMap(options) {
var sourceMap = options.sourceMap;
if (sourceMap && typeof sourceMap !== 'string' && options.outFile) {
sourceMap = options.outFile + '.map';
}
return sourceMap && typeof sourceMap === 'string' ? path.resolve(sourceMap) : null;
}
/**
* Get stats
*
* @param {Object} options
* @api private
*/
function getStats(options) {
var stats = {};
stats.entry = options.file || 'data';
stats.start = Date.now();
return stats;
}
/**
* End stats
*
* @param {Object} stats
* @param {Object} sourceMap
* @api private
*/
function endStats(stats) {
stats.end = Date.now();
stats.duration = stats.end - stats.start;
return stats;
}
/**
* Get style
*
* @param {Object} options
* @api private
*/
function getStyle(options) {
var styles = {
nested: 0,
expanded: 1,
compact: 2,
compressed: 3
};
return styles[options.outputStyle] || 0;
}
/**
* Get indent width
*
* @param {Object} options
* @api private
*/
function getIndentWidth(options) {
var width = parseInt(options.indentWidth) || 2;
return width > 10 ? 2 : width;
}
/**
* Get indent type
*
* @param {Object} options
* @api private
*/
function getIndentType(options) {
var types = {
space: 0,
tab: 1
};
return types[options.indentType] || 0;
}
/**
* Get linefeed
*
* @param {Object} options
* @api private
*/
function getLinefeed(options) {
var feeds = {
cr: '\r',
crlf: '\r\n',
lf: '\n',
lfcr: '\n\r'
};
return feeds[options.linefeed] || '\n';
}
/**
* Build an includePaths string
* from the options.includePaths array and the SASS_PATH environment variable
*
* @param {Object} options
* @api private
*/
function buildIncludePaths(options) {
options.includePaths = options.includePaths || [];
if (process.env.hasOwnProperty('SASS_PATH')) {
options.includePaths = options.includePaths.concat(
process.env.SASS_PATH.split(path.delimiter)
);
}
return options.includePaths.join(path.delimiter);
}
/**
* Get options
*
* @param {Object} options
* @api private
*/
function getOptions(opts, cb) {
var options = clonedeep(opts || {});
options.sourceComments = options.sourceComments || false;
if (options.hasOwnProperty('file')) {
options.file = getInputFile(options);
}
options.outFile = getOutputFile(options);
options.includePaths = buildIncludePaths(options);
options.precision = parseInt(options.precision) || 5;
options.sourceMap = getSourceMap(options);
options.style = getStyle(options);
options.indentWidth = getIndentWidth(options);
options.indentType = getIndentType(options);
options.linefeed = getLinefeed(options);
// context object represents node-sass environment
options.context = { options: options, callback: cb };
options.result = {
stats: getStats(options)
};
return options;
}
/**
* Executes a callback and transforms any exception raised into a sass error
*
* @param {Function} callback
* @param {Array} arguments
* @api private
*/
function tryCallback(callback, args) {
try {
return callback.apply(this, args);
} catch (e) {
if (typeof e === 'string') {
return new binding.types.Error(e);
} else if (e instanceof Error) {
return new binding.types.Error(e.message);
} else {
return new binding.types.Error('An unexpected error occurred');
}
}
}
/**
* Normalizes the signature of custom functions to make it possible to just supply the
* function name and have the signature default to `fn(...)`. The callback is adjusted
* to transform the input sass list into discrete arguments.
*
* @param {String} signature
* @param {Function} callback
* @return {Object}
* @api private
*/
function normalizeFunctionSignature(signature, callback) {
if (!/^\*|@warn|@error|@debug|\w+\(.*\)$/.test(signature)) {
if (!/\w+/.test(signature)) {
throw new Error('Invalid function signature format "' + signature + '"');
}
return {
signature: signature + '(...)',
callback: function() {
var args = Array.prototype.slice.call(arguments),
list = args.shift(),
i;
for (i = list.getLength() - 1; i >= 0; i--) {
args.unshift(list.getValue(i));
}
return callback.apply(this, args);
}
};
}
return {
signature: signature,
callback: callback
};
}
/**
* Render
*
* @param {Object} options
* @api public
*/
module.exports.render = function(opts, cb) {
var options = getOptions(opts, cb);
// options.error and options.success are for libsass binding
options.error = function(err) {
var payload = assign(new Error(), JSON.parse(err));
if (cb) {
options.context.callback.call(options.context, payload, null);
}
};
options.success = function() {
var result = options.result;
var stats = endStats(result.stats);
var payload = {
css: result.css,
map: result.map,
stats: stats
};
if (cb) {
options.context.callback.call(options.context, null, payload);
}
};
var importer = options.importer;
if (importer) {
if (Array.isArray(importer)) {
options.importer = [];
importer.forEach(function(subject, index) {
options.importer[index] = function(file, prev, bridge) {
function done(result) {
bridge.success(result === module.exports.NULL ? null : result);
}
var result = subject.call(options.context, file, prev, done);
if (result !== undefined) {
done(result);
}
};
});
} else {
options.importer = function(file, prev, bridge) {
function done(result) {
bridge.success(result === module.exports.NULL ? null : result);
}
var result = importer.call(options.context, file, prev, done);
if (result !== undefined) {
done(result);
}
};
}
}
var functions = clonedeep(options.functions);
if (functions) {
options.functions = {};
Object.keys(functions).forEach(function(subject) {
var cb = normalizeFunctionSignature(subject, functions[subject]);
options.functions[cb.signature] = function() {
var args = Array.prototype.slice.call(arguments),
bridge = args.pop();
function done(data) {
bridge.success(data);
}
var result = tryCallback(cb.callback.bind(options.context), args.concat(done));
if (result) {
done(result);
}
};
});
}
if (options.data) {
binding.render(options);
} else if (options.file) {
binding.renderFile(options);
} else {
cb({status: 3, message: 'No input specified: provide a file name or a source string to process' });
}
};
/**
* Render sync
*
* @param {Object} options
* @api public
*/
module.exports.renderSync = function(opts) {
var options = getOptions(opts);
var importer = options.importer;
if (importer) {
if (Array.isArray(importer)) {
options.importer = [];
importer.forEach(function(subject, index) {
options.importer[index] = function(file, prev) {
var result = subject.call(options.context, file, prev);
return result === module.exports.NULL ? null : result;
};
});
} else {
options.importer = function(file, prev) {
var result = importer.call(options.context, file, prev);
return result === module.exports.NULL ? null : result;
};
}
}
var functions = clonedeep(options.functions);
if (options.functions) {
options.functions = {};
Object.keys(functions).forEach(function(signature) {
var cb = normalizeFunctionSignature(signature, functions[signature]);
options.functions[cb.signature] = function() {
return tryCallback(cb.callback.bind(options.context), arguments);
};
});
}
var status;
if (options.data) {
status = binding.renderSync(options);
} else if (options.file) {
status = binding.renderFileSync(options);
} else {
throw new Error('No input specified: provide a file name or a source string to process');
}
var result = options.result;
if (status) {
result.stats = endStats(result.stats);
return result;
}
throw assign(new Error(), JSON.parse(result.error));
};
/**
* API Info
*
* @api public
*/
module.exports.info = sass.getVersionInfo(binding);
/**
* Expose sass types
*/
module.exports.types = binding.types;
module.exports.TRUE = binding.types.Boolean.TRUE;
module.exports.FALSE = binding.types.Boolean.FALSE;
module.exports.NULL = binding.types.Null.NULL;
/**
* Polyfill the old API
*
* TODO: remove for 4.0
*/
function processSassDeprecationMessage() {
console.log('Deprecation warning: `process.sass` is an undocumented internal that will be removed in future versions of Node Sass.');
}
process.sass = process.sass || {
get versionInfo() { processSassDeprecationMessage(); return module.exports.info; },
get binaryName() { processSassDeprecationMessage(); return sass.getBinaryName(); },
get binaryUrl() { processSassDeprecationMessage(); return sass.getBinaryUrl(); },
get binaryPath() { processSassDeprecationMessage(); return sass.getBinaryPath(); },
get getBinaryPath() { processSassDeprecationMessage(); return sass.getBinaryPath; },
};
/*!
* node-sass: lib/render.js
*/
var chalk = require('chalk'),
fs = require('fs'),
mkdirp = require('mkdirp'),
path = require('path'),
sass = require('./');
/**
* Render
*
* @param {Object} options
* @param {Object} emitter
* @api public
*/
module.exports = function(options, emitter) {
var renderOptions = {
includePaths: options.includePath,
omitSourceMapUrl: options.omitSourceMapUrl,
indentedSyntax: options.indentedSyntax,
outFile: options.dest,
outputStyle: options.outputStyle,
precision: options.precision,
sourceComments: options.sourceComments,
sourceMapEmbed: options.sourceMapEmbed,
sourceMapContents: options.sourceMapContents,
sourceMap: options.sourceMap,
sourceMapRoot: options.sourceMapRoot,
importer: options.importer,
functions: options.functions,
indentWidth: options.indentWidth,
indentType: options.indentType,
linefeed: options.linefeed
};
if (options.data) {
renderOptions.data = options.data;
} else if (options.src) {
renderOptions.file = options.src;
}
var sourceMap = options.sourceMap;
var destination = options.dest;
var stdin = options.stdin;
var success = function(result) {
var todo = 1;
var done = function() {
if (--todo <= 0) {
emitter.emit('done');
}
};
if (!destination || stdin) {
emitter.emit('log', result.css.toString());
if (sourceMap && !options.sourceMapEmbed) {
emitter.emit('log', result.map.toString());
}
return done();
}
emitter.emit('warn', chalk.green('Rendering Complete, saving .css file...'));
mkdirp(path.dirname(destination), function(err) {
if (err) {
return emitter.emit('error', chalk.red(err));
}
fs.writeFile(destination, result.css.toString(), function(err) {
if (err) {
return emitter.emit('error', chalk.red(err));
}
emitter.emit('warn', chalk.green('Wrote CSS to ' + destination));
emitter.emit('write', err, destination, result.css.toString());
done();
});
});
if (sourceMap) {
todo++;
mkdirp(path.dirname(sourceMap), function(err) {
if (err) {
return emitter.emit('error', chalk.red(err));
}
fs.writeFile(sourceMap, result.map, function(err) {
if (err) {
return emitter.emit('error', chalk.red('Error' + err));
}
emitter.emit('warn', chalk.green('Wrote Source Map to ' + sourceMap));
emitter.emit('write-source-map', err, sourceMap, result.map);
done();
});
});
}
emitter.emit('render', result.css.toString());
};
var error = function(error) {
emitter.emit('error', chalk.red(JSON.stringify(error, null, 2)));
};
var renderCallback = function(err, result) {
if (err) {
error(err);
}
else {
success(result);
}
};
sass.render(renderOptions, renderCallback);
};
{
"_args": [
[
{
"raw": "node-sass",
"scope": null,
"escapedName": "node-sass",
"name": "node-sass",
"rawSpec": "",
"spec": "latest",
"type": "tag"
},
"/project/ptshequ/ptbbs"
]
],
"_cnpm_publish_time": 1479253519365,
"_from": "node-sass@latest",
"_id": "node-sass@3.13.0",
"_inCache": true,
"_location": "/node-sass",
"_nodeVersion": "6.5.0",
"_npmOperationalInternal": {
"host": "packages-12-west.internal.npmjs.com",
"tmp": "tmp/node-sass-3.13.0.tgz_1479253519023_0.3307026196271181"
},
"_npmUser": {
"name": "xzyfer",
"email": "xzyfer@gmail.com"
},
"_npmVersion": "3.10.3",
"_phantomChildren": {
"fs.realpath": "1.0.0",
"inflight": "1.0.5",
"inherits": "2.0.1",
"minimatch": "3.0.3",
"once": "1.3.3",
"path-is-absolute": "1.0.0"
},
"_requested": {
"raw": "node-sass",
"scope": null,
"escapedName": "node-sass",
"name": "node-sass",
"rawSpec": "",
"spec": "latest",
"type": "tag"
},
"_requiredBy": [
"#DEV:/",
"#USER"
],
"_resolved": "https://registry.npm.taobao.org/node-sass/download/node-sass-3.13.0.tgz",
"_shasum": "d08b95bdebf40941571bd2c16a9334b980f8924f",
"_shrinkwrap": null,
"_spec": "node-sass",
"_where": "/project/ptshequ/ptbbs",
"author": {
"name": "Andrew Nesbitt",
"email": "andrewnez@gmail.com",
"url": "http://andrew.github.com"
},
"bin": {
"node-sass": "bin/node-sass"
},
"bugs": {
"url": "https://github.com/sass/node-sass/issues"
},
"dependencies": {
"async-foreach": "^0.1.3",
"chalk": "^1.1.1",
"cross-spawn": "^3.0.0",
"gaze": "^1.0.0",
"get-stdin": "^4.0.1",
"glob": "^7.0.3",
"in-publish": "^2.0.0",
"lodash.assign": "^4.2.0",
"lodash.clonedeep": "^4.3.2",
"meow": "^3.7.0",
"mkdirp": "^0.5.1",
"nan": "^2.3.2",
"node-gyp": "^3.3.1",
"npmlog": "^4.0.0",
"request": "^2.61.0",
"sass-graph": "^2.1.1"
},
"description": "Wrapper around libsass",
"devDependencies": {
"coveralls": "^2.11.8",
"eslint": "^3.4.0",
"istanbul": "^0.4.2",
"mocha": "^3.1.2",
"mocha-lcov-reporter": "^1.2.0",
"object-merge": "^2.5.1",
"read-yaml": "^1.0.0",
"rimraf": "^2.5.2",
"sass-spec": "^3.3.6-3"
},
"directories": {},
"dist": {
"shasum": "d08b95bdebf40941571bd2c16a9334b980f8924f",
"size": 349695,
"noattachment": false,
"tarball": "http://registry.npm.taobao.org/node-sass/download/node-sass-3.13.0.tgz"
},
"engines": {
"node": ">=0.10.0"
},
"files": [
"bin",
"binding.gyp",
"lib",
"scripts",
"src",
"test",
"vendor"
],
"gitHead": "2e7f37084a1b30e93b142674cfed1fcd05c79e82",
"gypfile": true,
"homepage": "https://github.com/sass/node-sass",
"keywords": [
"css",
"libsass",
"preprocessor",
"sass",
"scss",
"style"
],
"libsass": "3.3.6",
"license": "MIT",
"main": "lib/index.js",
"maintainers": [
{
"name": "am11",
"email": "adeelbm@outlook.com"
},
{
"name": "andrewnez",
"email": "andrewnez@gmail.com"
},
{
"name": "deanmao",
"email": "deanmao@gmail.com"
},
{
"name": "keithamus",
"email": "npm@keithcirkel.co.uk"
},
{
"name": "laurentgoderre",
"email": "laurent.goderre@gmail.com"
},
{
"name": "saperski",
"email": "npm@saper.info"
},
{
"name": "xzyfer",
"email": "xzyfer@gmail.com"
}
],
"name": "node-sass",
"nodeSassConfig": {
"binarySite": "https://github.com/sass/node-sass/releases/download"
},
"optionalDependencies": {},
"publish_time": 1479253519365,
"readme": "ERROR: No README data found!",
"repository": {
"type": "git",
"url": "git+https://github.com/sass/node-sass.git"
},
"scripts": {
"build": "node scripts/build.js --force",
"coverage": "node scripts/coverage.js",
"install": "node scripts/install.js",
"lint": "eslint bin/node-sass lib scripts test",
"postinstall": "node scripts/build.js",
"prepublish": "not-in-install && node scripts/prepublish.js || in-install",
"test": "mocha test/{*,**/**}.js"
},
"version": "3.13.0"
}
/*!
* node-sass: scripts/build.js
*/
var pkg = require('../package.json'),
fs = require('fs'),
mkdir = require('mkdirp'),
path = require('path'),
spawn = require('cross-spawn'),
sass = require('../lib/extensions');
/**
* After build
*
* @param {Object} options
* @api private
*/
function afterBuild(options) {
var install = sass.getBinaryPath();
var target = path.join(__dirname, '..', 'build',
options.debug ? 'Debug' :
process.config.target_defaults
? process.config.target_defaults.default_configuration
: 'Release',
'binding.node');
mkdir(path.dirname(install), function(err) {
if (err && err.code !== 'EEXIST') {
console.error(err.message);
return;
}
fs.stat(target, function(err) {
if (err) {
console.error('Build succeeded but target not found');
return;
}
fs.rename(target, install, function(err) {
if (err) {
console.error(err.message);
return;
}
console.log('Installed to', install);
});
});
});
}
/**
* manageProcess
*
* @param {ChildProcess} proc
* @param {Function} cb
* @api private
*/
function manageProcess(proc, cb) {
var errorMsg = '';
proc.stderr.on('data', function(data) {
errorMsg += data.toString();
});
proc.on('close', function(code) {
cb(code === 0 ? null : { message: errorMsg });
});
}
/**
* initSubmodules
*
* @param {Function} cb
* @api private
*/
function initSubmodules(cb) {
console.log('Detected a git install');
console.log('Cloning LibSass into src/libsass');
var clone = spawn('git', ['clone', 'https://github.com/sass/libsass.git', './src/libsass']);
manageProcess(clone, function(err) {
if (err) {
cb(err);
return;
}
console.log('Checking out LibSass to', pkg.libsass);
var checkout = spawn('git', ['checkout', pkg.libsass], { cwd: './src/libsass' });
manageProcess(checkout, function(err) {
cb(err);
});
});
}
/**
* installGitDependencies
*
* @param {Function} cb
* @api private
*/
function installGitDependencies(options, cb) {
var libsassPath = './src/libsass';
if (process.env.LIBSASS_EXT || options.libsassExt) {
cb();
} else if (fs.access) { // node 0.12+, iojs 1.0.0+
fs.access(libsassPath, fs.R_OK, function(err) {
err && err.code === 'ENOENT' ? initSubmodules(cb) : cb();
});
} else { // node < 0.12
fs.exists(libsassPath, function(exists) {
exists ? cb() : initSubmodules(cb);
});
}
}
/**
* Build
*
* @param {Object} options
* @api private
*/
function build(options) {
installGitDependencies(options, function(err) {
if (err) {
console.error(err.message);
process.exit(1);
}
var args = [require.resolve(path.join('node-gyp', 'bin', 'node-gyp.js')), 'rebuild', '--verbose'].concat(
['libsass_ext', 'libsass_cflags', 'libsass_ldflags', 'libsass_library'].map(function(subject) {
return ['--', subject, '=', process.env[subject.toUpperCase()] || ''].join('');
})).concat(options.args);
console.log('Building:', [process.execPath].concat(args).join(' '));
var proc = spawn(process.execPath, args, {
stdio: [0, 1, 2]
});
proc.on('exit', function(errorCode) {
if (!errorCode) {
afterBuild(options);
return;
}
if (errorCode === 127 ) {
console.error('node-gyp not found!');
} else {
console.error('Build failed with error code:', errorCode);
}
process.exit(1);
});
});
}
/**
* Parse arguments
*
* @param {Array} args
* @api private
*/
function parseArgs(args) {
var options = {
arch: process.arch,
platform: process.platform
};
options.args = args.filter(function(arg) {
if (arg === '-f' || arg === '--force') {
options.force = true;
return false;
} else if (arg.substring(0, 13) === '--target_arch') {
options.arch = arg.substring(14);
} else if (arg === '-d' || arg === '--debug') {
options.debug = true;
} else if (arg.substring(0, 13) === '--libsass_ext' && arg.substring(14) !== 'no') {
options.libsassExt = true;
}
return true;
});
return options;
}
/**
* Test for pre-built library
*
* @param {Object} options
* @api private
*/
function testBinary(options) {
if (options.force || process.env.SASS_FORCE_BUILD) {
return build(options);
}
if (!sass.hasBinary(sass.getBinaryPath())) {
return build(options);
}
console.log('Binary found at', sass.getBinaryPath());
console.log('Testing binary');
try {
require('../').renderSync({
data: 's { a: ss }'
});
console.log('Binary is fine');
} catch (e) {
console.log('Binary has a problem:', e);
console.log('Building the binary locally');
return build(options);
}
}
/**
* Apply arguments and run
*/
testBinary(parseArgs(process.argv.slice(2)));
/*!
* node-sass: scripts/coverage.js
*/
var Mocha = require('mocha'),
fs = require('fs'),
path = require('path'),
mkdirp = require('mkdirp'),
coveralls = require('coveralls'),
istanbul = require('istanbul'),
sourcefiles = ['index.js', 'extensions.js', 'render.js', 'errors.js'],
summary= istanbul.Report.create('text-summary'),
lcov = istanbul.Report.create('lcovonly', { dir: path.join('coverage') }),
html = istanbul.Report.create('html', { dir: path.join('coverage', 'html') });
function coverage() {
var mocha = new Mocha();
var rep = function(runner) {
runner.on('end', function(){
var cov = global.__coverage__,
collector = new istanbul.Collector();
if (cov) {
mkdirp(path.join('coverage', 'html'), function(err) {
if (err) { throw err; }
collector.add(cov);
summary.writeReport(collector, true);
html.writeReport(collector, true);
lcov.on('done', function() {
fs.readFile(path.join('coverage', 'lcov.info'), function(err, data) {
if (err) { console.error(err); }
coveralls.handleInput(data.toString(),
function (err) { if (err) { console.error(err); } });
});
});
lcov.writeReport(collector, true);
});
} else {
console.warn('No coverage');
}
});
};
var instrumenter = new istanbul.Instrumenter();
var instrumentedfiles = [];
var processfile = function(source) {
fs.readFile(path.join('lib', source), function(err, data) {
if (err) { throw err; }
mkdirp('lib-cov', function(err) {
if (err) { throw err; }
fs.writeFile(path.join('lib-cov', source),
instrumenter.instrumentSync(data.toString(),
path.join('lib', source)),
function(err) {
if (err) { throw err; }
instrumentedfiles.push(source);
if (instrumentedfiles.length === sourcefiles.length) {
fs.readdirSync('test').filter(function(file){
return file.substr(-6) === 'api.js' ||
file.substr(-11) === 'runtime.js' ||
file.substr(-7) === 'spec.js';
}).forEach(function(file){
mocha.addFile(
path.join('test', file)
);
});
process.env.NODESASS_COV = 1;
mocha.reporter(rep).run(function(failures) {
process.on('exit', function () {
process.exit(failures);
});
});
}
});
});
});
};
for (var i in sourcefiles) {
processfile(sourcefiles[i]);
}
}
/**
* Run
*/
coverage();
/*!
* node-sass: scripts/install.js
*/
var fs = require('fs'),
eol = require('os').EOL,
mkdir = require('mkdirp'),
path = require('path'),
sass = require('../lib/extensions'),
request = require('request'),
log = require('npmlog'),
downloadOptions = require('./util/downloadoptions');
/**
* Download file, if succeeds save, if not delete
*
* @param {String} url
* @param {String} dest
* @param {Function} cb
* @api private
*/
function download(url, dest, cb) {
var reportError = function(err) {
var timeoutMessge;
if (err.code === 'ETIMEDOUT') {
if (err.connect === true) {
// timeout is hit while your client is attempting to establish a connection to a remote machine
timeoutMessge = 'Timed out attemping to establish a remote connection';
} else {
timeoutMessge = 'Timed out whilst downloading the prebuilt binary';
// occurs any time the server is too slow to send back a part of the response
}
}
cb(['Cannot download "', url, '": ', eol, eol,
typeof err.message === 'string' ? err.message : err, eol, eol,
timeoutMessge ? timeoutMessge + eol + eol : timeoutMessge,
'Hint: If github.com is not accessible in your location', eol,
' try setting a proxy via HTTP_PROXY, e.g. ', eol, eol,
' export HTTP_PROXY=http://example.com:1234',eol, eol,
'or configure npm proxy via', eol, eol,
' npm config set proxy http://example.com:8080'].join(''));
};
var successful = function(response) {
return response.statusCode >= 200 && response.statusCode < 300;
};
console.log('Downloading binary from', url);
try {
request(url, downloadOptions(), function(err, response) {
if (err) {
reportError(err);
} else if (!successful(response)) {
reportError(['HTTP error', response.statusCode, response.statusMessage].join(' '));
} else {
console.log('Download complete');
cb();
}
})
.on('response', function(response) {
var length = parseInt(response.headers['content-length'], 10);
var progress = log.newItem('', length);
if (successful(response)) {
response.pipe(fs.createWriteStream(dest));
}
// The `progress` is true by default. However if it has not
// been explicitly set it's `undefined` which is considered
// as far as npm is concerned.
if (process.env.npm_config_progress === 'true') {
log.enableProgress();
response.on('data', function(chunk) {
progress.completeWork(chunk.length);
})
.on('end', progress.finish);
}
});
} catch (err) {
cb(err);
}
}
/**
* Check and download binary
*
* @api private
*/
function checkAndDownloadBinary() {
if (process.env.SKIP_SASS_BINARY_DOWNLOAD_FOR_CI) {
console.log('Skipping downloading binaries on CI builds');
return;
}
var cachedBinary = sass.getCachedBinary(),
cachePath = sass.getBinaryCachePath(),
binaryPath = sass.getBinaryPath();
if (sass.hasBinary(binaryPath)) {
console.log('node-sass build', 'Binary found at', binaryPath);
return;
}
try {
mkdir.sync(path.dirname(binaryPath));
} catch (err) {
console.error('Unable to save binary', path.dirname(binaryPath), ':', err);
return;
}
if (cachedBinary) {
console.log('Cached binary found at', cachedBinary);
fs.createReadStream(cachedBinary).pipe(fs.createWriteStream(binaryPath));
return;
}
download(sass.getBinaryUrl(), binaryPath, function(err) {
if (err) {
console.error(err);
return;
}
console.log('Binary saved to', binaryPath);
cachedBinary = path.join(cachePath, sass.getBinaryName());
if (cachePath) {
console.log('Caching binary to', cachedBinary);
try {
mkdir.sync(path.dirname(cachedBinary));
fs.createReadStream(binaryPath)
.pipe(fs.createWriteStream(cachedBinary))
.on('error', function (err) {
console.log('Failed to cache binary:', err);
});
} catch (err) {
console.log('Failed to cache binary:', err);
}
}
});
}
/**
* If binary does not exist, download it
*/
checkAndDownloadBinary();
/*!
* node-sass: scripts/install.js
*/
var path = require('path'),
rimraf = require('rimraf');
function prepublish() {
var vendorPath = path.resolve(__dirname, '..', 'vendor');
rimraf.sync(vendorPath);
}
/**
* Run
*/
prepublish();
var proxy = require('./proxy'),
userAgent = require('./useragent');
/**
* The options passed to request when downloading the bibary
*
* There some nuance to how request handles options. Specifically
* we've been caught by their usage of `hasOwnProperty` rather than
* falsey checks. By moving the options generation into a util helper
* we can test for regressions.
*
* @return {Object} an options object for request
* @api private
*/
module.exports = function() {
var options = {
rejectUnauthorized: false,
timeout: 60000,
headers: {
'User-Agent': userAgent(),
}
};
var proxyConfig = proxy();
if (proxyConfig) {
options.proxy = proxyConfig;
}
return options;
};
/**
* Determine the proxy settings configured by npm
*
* It's possible to configure npm to use a proxy different
* from the system defined proxy. This can be done via the
* `npm config` CLI or the `.npmrc` config file.
*
* If a proxy has been configured in this way we must
* tell request explicitly to use it.
*
* Otherwise we can trust request to the right thing.
*
* @return {String} the proxy configured by npm or an empty string
* @api private
*/
module.exports = function() {
return process.env.npm_config_https_proxy ||
process.env.npm_config_proxy ||
process.env.npm_config_http_proxy ||
'';
};
var pkg = require('../../package.json');
/**
* A custom user agent use for binary downloads.
*
* @api private
*/
module.exports = function() {
return [
'node/', process.version, ' ',
'node-sass-installer/', pkg.version
].join('');
};
#include <nan.h>
#include <vector>
#include "sass_context_wrapper.h"
#include "custom_function_bridge.h"
#include "create_string.h"
#include "sass_types/factory.h"
Sass_Import_List sass_importer(const char* cur_path, Sass_Importer_Entry cb, struct Sass_Compiler* comp)
{
void* cookie = sass_importer_get_cookie(cb);
struct Sass_Import* previous = sass_compiler_get_last_import(comp);
const char* prev_path = sass_import_get_abs_path(previous);
CustomImporterBridge& bridge = *(static_cast<CustomImporterBridge*>(cookie));
std::vector<void*> argv;
argv.push_back((void*)cur_path);
argv.push_back((void*)prev_path);
return bridge(argv);
}
union Sass_Value* sass_custom_function(const union Sass_Value* s_args, Sass_Function_Entry cb, struct Sass_Compiler* comp)
{
void* cookie = sass_function_get_cookie(cb);
CustomFunctionBridge& bridge = *(static_cast<CustomFunctionBridge*>(cookie));
std::vector<void*> argv;
for (unsigned l = sass_list_get_length(s_args), i = 0; i < l; i++) {
argv.push_back((void*)sass_list_get_value(s_args, i));
}
return bridge(argv);
}
int ExtractOptions(v8::Local<v8::Object> options, void* cptr, sass_context_wrapper* ctx_w, bool is_file, bool is_sync) {
Nan::HandleScope scope;
struct Sass_Context* ctx;
v8::Local<v8::Value> result_ = Nan::Get(
options,
Nan::New("result").ToLocalChecked()
).ToLocalChecked();
if (!result_->IsObject()) {
Nan::ThrowTypeError("\"result\" element is not an object");
return -1;
}
ctx_w->result.Reset(result_.As<v8::Object>());
if (is_file) {
ctx_w->fctx = (struct Sass_File_Context*) cptr;
ctx = sass_file_context_get_context(ctx_w->fctx);
}
else {
ctx_w->dctx = (struct Sass_Data_Context*) cptr;
ctx = sass_data_context_get_context(ctx_w->dctx);
}
struct Sass_Options* sass_options = sass_context_get_options(ctx);
ctx_w->is_sync = is_sync;
if (!is_sync) {
ctx_w->request.data = ctx_w;
// async (callback) style
v8::Local<v8::Function> success_callback = v8::Local<v8::Function>::Cast(Nan::Get(options, Nan::New("success").ToLocalChecked()).ToLocalChecked());
v8::Local<v8::Function> error_callback = v8::Local<v8::Function>::Cast(Nan::Get(options, Nan::New("error").ToLocalChecked()).ToLocalChecked());
ctx_w->success_callback = new Nan::Callback(success_callback);
ctx_w->error_callback = new Nan::Callback(error_callback);
}
if (!is_file) {
ctx_w->file = create_string(Nan::Get(options, Nan::New("file").ToLocalChecked()));
sass_option_set_input_path(sass_options, ctx_w->file);
}
int indent_len = Nan::To<int32_t>(
Nan::Get(
options,
Nan::New("indentWidth").ToLocalChecked()
).ToLocalChecked()).FromJust();
ctx_w->indent = (char*)malloc(indent_len + 1);
strcpy(ctx_w->indent, std::string(
indent_len,
Nan::To<int32_t>(
Nan::Get(
options,
Nan::New("indentType").ToLocalChecked()
).ToLocalChecked()).FromJust() == 1 ? '\t' : ' '
).c_str());
ctx_w->linefeed = create_string(Nan::Get(options, Nan::New("linefeed").ToLocalChecked()));
ctx_w->include_path = create_string(Nan::Get(options, Nan::New("includePaths").ToLocalChecked()));
ctx_w->out_file = create_string(Nan::Get(options, Nan::New("outFile").ToLocalChecked()));
ctx_w->source_map = create_string(Nan::Get(options, Nan::New("sourceMap").ToLocalChecked()));
ctx_w->source_map_root = create_string(Nan::Get(options, Nan::New("sourceMapRoot").ToLocalChecked()));
sass_option_set_output_path(sass_options, ctx_w->out_file);
sass_option_set_output_style(sass_options, (Sass_Output_Style)Nan::To<int32_t>(Nan::Get(options, Nan::New("style").ToLocalChecked()).ToLocalChecked()).FromJust());
sass_option_set_is_indented_syntax_src(sass_options, Nan::To<bool>(Nan::Get(options, Nan::New("indentedSyntax").ToLocalChecked()).ToLocalChecked()).FromJust());
sass_option_set_source_comments(sass_options, Nan::To<bool>(Nan::Get(options, Nan::New("sourceComments").ToLocalChecked()).ToLocalChecked()).FromJust());
sass_option_set_omit_source_map_url(sass_options, Nan::To<bool>(Nan::Get(options, Nan::New("omitSourceMapUrl").ToLocalChecked()).ToLocalChecked()).FromJust());
sass_option_set_source_map_embed(sass_options, Nan::To<bool>(Nan::Get(options, Nan::New("sourceMapEmbed").ToLocalChecked()).ToLocalChecked()).FromJust());
sass_option_set_source_map_contents(sass_options, Nan::To<bool>(Nan::Get(options, Nan::New("sourceMapContents").ToLocalChecked()).ToLocalChecked()).FromJust());
sass_option_set_source_map_file(sass_options, ctx_w->source_map);
sass_option_set_source_map_root(sass_options, ctx_w->source_map_root);
sass_option_set_include_path(sass_options, ctx_w->include_path);
sass_option_set_precision(sass_options, Nan::To<int32_t>(Nan::Get(options, Nan::New("precision").ToLocalChecked()).ToLocalChecked()).FromJust());
sass_option_set_indent(sass_options, ctx_w->indent);
sass_option_set_linefeed(sass_options, ctx_w->linefeed);
v8::Local<v8::Value> importer_callback = Nan::Get(options, Nan::New("importer").ToLocalChecked()).ToLocalChecked();
if (importer_callback->IsFunction()) {
v8::Local<v8::Function> importer = importer_callback.As<v8::Function>();
CustomImporterBridge *bridge = new CustomImporterBridge(importer, ctx_w->is_sync);
ctx_w->importer_bridges.push_back(bridge);
Sass_Importer_List c_importers = sass_make_importer_list(1);
c_importers[0] = sass_make_importer(sass_importer, 0, bridge);
sass_option_set_c_importers(sass_options, c_importers);
}
else if (importer_callback->IsArray()) {
v8::Local<v8::Array> importers = importer_callback.As<v8::Array>();
Sass_Importer_List c_importers = sass_make_importer_list(importers->Length());
for (size_t i = 0; i < importers->Length(); ++i) {
v8::Local<v8::Function> callback = v8::Local<v8::Function>::Cast(Nan::Get(importers, static_cast<uint32_t>(i)).ToLocalChecked());
CustomImporterBridge *bridge = new CustomImporterBridge(callback, ctx_w->is_sync);
ctx_w->importer_bridges.push_back(bridge);
c_importers[i] = sass_make_importer(sass_importer, importers->Length() - i - 1, bridge);
}
sass_option_set_c_importers(sass_options, c_importers);
}
v8::Local<v8::Value> custom_functions = Nan::Get(options, Nan::New("functions").ToLocalChecked()).ToLocalChecked();
if (custom_functions->IsObject()) {
v8::Local<v8::Object> functions = custom_functions.As<v8::Object>();
v8::Local<v8::Array> signatures = Nan::GetOwnPropertyNames(functions).ToLocalChecked();
unsigned num_signatures = signatures->Length();
Sass_Function_List fn_list = sass_make_function_list(num_signatures);
for (unsigned i = 0; i < num_signatures; i++) {
v8::Local<v8::String> signature = v8::Local<v8::String>::Cast(Nan::Get(signatures, Nan::New(i)).ToLocalChecked());
v8::Local<v8::Function> callback = v8::Local<v8::Function>::Cast(Nan::Get(functions, signature).ToLocalChecked());
CustomFunctionBridge *bridge = new CustomFunctionBridge(callback, ctx_w->is_sync);
ctx_w->function_bridges.push_back(bridge);
Sass_Function_Entry fn = sass_make_function(create_string(signature), sass_custom_function, bridge);
sass_function_set_list_entry(fn_list, i, fn);
}
sass_option_set_c_functions(sass_options, fn_list);
}
return 0;
}
void GetStats(sass_context_wrapper* ctx_w, Sass_Context* ctx) {
Nan::HandleScope scope;
char** included_files = sass_context_get_included_files(ctx);
v8::Local<v8::Array> arr = Nan::New<v8::Array>();
if (included_files) {
for (int i = 0; included_files[i] != nullptr; ++i) {
Nan::Set(arr, i, Nan::New<v8::String>(included_files[i]).ToLocalChecked());
}
}
v8::Local<v8::Object> result = Nan::New(ctx_w->result);
assert(result->IsObject());
v8::Local<v8::Value> stats = Nan::Get(
result,
Nan::New("stats").ToLocalChecked()
).ToLocalChecked();
if (stats->IsObject()) {
Nan::Set(
stats.As<v8::Object>(),
Nan::New("includedFiles").ToLocalChecked(),
arr
);
} else {
Nan::ThrowTypeError("\"result.stats\" element is not an object");
}
}
int GetResult(sass_context_wrapper* ctx_w, Sass_Context* ctx, bool is_sync = false) {
Nan::HandleScope scope;
v8::Local<v8::Object> result;
int status = sass_context_get_error_status(ctx);
result = Nan::New(ctx_w->result);
assert(result->IsObject());
if (status == 0) {
const char* css = sass_context_get_output_string(ctx);
const char* map = sass_context_get_source_map_string(ctx);
Nan::Set(result, Nan::New("css").ToLocalChecked(), Nan::CopyBuffer(css, static_cast<uint32_t>(strlen(css))).ToLocalChecked());
GetStats(ctx_w, ctx);
if (map) {
Nan::Set(result, Nan::New("map").ToLocalChecked(), Nan::CopyBuffer(map, static_cast<uint32_t>(strlen(map))).ToLocalChecked());
}
}
else if (is_sync) {
Nan::Set(result, Nan::New("error").ToLocalChecked(), Nan::New<v8::String>(sass_context_get_error_json(ctx)).ToLocalChecked());
}
return status;
}
void MakeCallback(uv_work_t* req) {
Nan::HandleScope scope;
Nan::TryCatch try_catch;
sass_context_wrapper* ctx_w = static_cast<sass_context_wrapper*>(req->data);
struct Sass_Context* ctx;
if (ctx_w->dctx) {
ctx = sass_data_context_get_context(ctx_w->dctx);
}
else {
ctx = sass_file_context_get_context(ctx_w->fctx);
}
int status = GetResult(ctx_w, ctx);
if (status == 0 && ctx_w->success_callback) {
// if no error, do callback(null, result)
ctx_w->success_callback->Call(0, 0);
}
else if (ctx_w->error_callback) {
// if error, do callback(error)
const char* err = sass_context_get_error_json(ctx);
v8::Local<v8::Value> argv[] = {
Nan::New<v8::String>(err).ToLocalChecked()
};
ctx_w->error_callback->Call(1, argv);
}
if (try_catch.HasCaught()) {
Nan::FatalException(try_catch);
}
sass_free_context_wrapper(ctx_w);
}
NAN_METHOD(render) {
v8::Local<v8::Object> options = Nan::To<v8::Object>(info[0]).ToLocalChecked();
char* source_string = create_string(Nan::Get(options, Nan::New("data").ToLocalChecked()));
struct Sass_Data_Context* dctx = sass_make_data_context(source_string);
sass_context_wrapper* ctx_w = sass_make_context_wrapper();
if (ExtractOptions(options, dctx, ctx_w, false, false) >= 0) {
int status = uv_queue_work(uv_default_loop(), &ctx_w->request, compile_it, (uv_after_work_cb)MakeCallback);
assert(status == 0);
}
}
NAN_METHOD(render_sync) {
v8::Local<v8::Object> options = Nan::To<v8::Object>(info[0]).ToLocalChecked();
char* source_string = create_string(Nan::Get(options, Nan::New("data").ToLocalChecked()));
struct Sass_Data_Context* dctx = sass_make_data_context(source_string);
struct Sass_Context* ctx = sass_data_context_get_context(dctx);
sass_context_wrapper* ctx_w = sass_make_context_wrapper();
int result = -1;
if ((result = ExtractOptions(options, dctx, ctx_w, false, true)) >= 0) {
compile_data(dctx);
result = GetResult(ctx_w, ctx, true);
}
sass_free_context_wrapper(ctx_w);
info.GetReturnValue().Set(result == 0);
}
NAN_METHOD(render_file) {
v8::Local<v8::Object> options = Nan::To<v8::Object>(info[0]).ToLocalChecked();
char* input_path = create_string(Nan::Get(options, Nan::New("file").ToLocalChecked()));
struct Sass_File_Context* fctx = sass_make_file_context(input_path);
sass_context_wrapper* ctx_w = sass_make_context_wrapper();
if (ExtractOptions(options, fctx, ctx_w, true, false) >= 0) {
int status = uv_queue_work(uv_default_loop(), &ctx_w->request, compile_it, (uv_after_work_cb)MakeCallback);
assert(status == 0);
}
}
NAN_METHOD(render_file_sync) {
v8::Local<v8::Object> options = Nan::To<v8::Object>(info[0]).ToLocalChecked();
char* input_path = create_string(Nan::Get(options, Nan::New("file").ToLocalChecked()));
struct Sass_File_Context* fctx = sass_make_file_context(input_path);
struct Sass_Context* ctx = sass_file_context_get_context(fctx);
sass_context_wrapper* ctx_w = sass_make_context_wrapper();
int result = -1;
if ((result = ExtractOptions(options, fctx, ctx_w, true, true)) >= 0) {
compile_file(fctx);
result = GetResult(ctx_w, ctx, true);
};
free(input_path);
sass_free_context_wrapper(ctx_w);
info.GetReturnValue().Set(result == 0);
}
NAN_METHOD(libsass_version) {
info.GetReturnValue().Set(Nan::New<v8::String>(libsass_version()).ToLocalChecked());
}
NAN_MODULE_INIT(RegisterModule) {
Nan::SetMethod(target, "render", render);
Nan::SetMethod(target, "renderSync", render_sync);
Nan::SetMethod(target, "renderFile", render_file);
Nan::SetMethod(target, "renderFileSync", render_file_sync);
Nan::SetMethod(target, "libsassVersion", libsass_version);
SassTypes::Factory::initExports(target);
}
NODE_MODULE(binding, RegisterModule);
#ifndef CALLBACK_BRIDGE_H
#define CALLBACK_BRIDGE_H
#include <vector>
#include <nan.h>
#include <algorithm>
#include <uv.h>
#define COMMA ,
template <typename T, typename L = void*>
class CallbackBridge {
public:
CallbackBridge(v8::Local<v8::Function>, bool);
virtual ~CallbackBridge();
// Executes the callback
T operator()(std::vector<void*>);
protected:
// We will expose a bridge object to the JS callback that wraps this instance so we don't loose context.
// This is the V8 constructor for such objects.
static Nan::MaybeLocal<v8::Function> get_wrapper_constructor();
static void async_gone(uv_handle_t *handle);
static NAN_METHOD(New);
static NAN_METHOD(ReturnCallback);
static Nan::Persistent<v8::Function> wrapper_constructor;
Nan::Persistent<v8::Object> wrapper;
// The callback that will get called in the main thread after the worker thread used for the sass
// compilation step makes a call to uv_async_send()
static void dispatched_async_uv_callback(uv_async_t*);
// The V8 values sent to our ReturnCallback must be read on the main thread not the sass worker thread.
// This gives a chance to specialized subclasses to transform those values into whatever makes sense to
// sass before we resume the worker thread.
virtual T post_process_return_value(v8::Local<v8::Value>) const =0;
virtual std::vector<v8::Local<v8::Value>> pre_process_args(std::vector<L>) const =0;
Nan::Callback* callback;
bool is_sync;
uv_mutex_t cv_mutex;
uv_cond_t condition_variable;
uv_async_t *async;
std::vector<L> argv;
bool has_returned;
T return_value;
};
template <typename T, typename L>
Nan::Persistent<v8::Function> CallbackBridge<T, L>::wrapper_constructor;
template <typename T, typename L>
CallbackBridge<T, L>::CallbackBridge(v8::Local<v8::Function> callback, bool is_sync) : callback(new Nan::Callback(callback)), is_sync(is_sync) {
/*
* This is invoked from the main JavaScript thread.
* V8 context is available.
*/
Nan::HandleScope scope;
uv_mutex_init(&this->cv_mutex);
uv_cond_init(&this->condition_variable);
if (!is_sync) {
this->async = new uv_async_t;
this->async->data = (void*) this;
uv_async_init(uv_default_loop(), this->async, (uv_async_cb) dispatched_async_uv_callback);
}
v8::Local<v8::Function> func = CallbackBridge<T, L>::get_wrapper_constructor().ToLocalChecked();
wrapper.Reset(Nan::NewInstance(func).ToLocalChecked());
Nan::SetInternalFieldPointer(Nan::New(wrapper), 0, this);
}
template <typename T, typename L>
CallbackBridge<T, L>::~CallbackBridge() {
delete this->callback;
this->wrapper.Reset();
uv_cond_destroy(&this->condition_variable);
uv_mutex_destroy(&this->cv_mutex);
if (!is_sync) {
uv_close((uv_handle_t*)this->async, &async_gone);
}
}
template <typename T, typename L>
T CallbackBridge<T, L>::operator()(std::vector<void*> argv) {
// argv.push_back(wrapper);
if (this->is_sync) {
/*
* This is invoked from the main JavaScript thread.
* V8 context is available.
*
* Establish Local<> scope for all functions
* from types invoked by pre_process_args() and
* post_process_args().
*/
Nan::HandleScope scope;
Nan::TryCatch try_catch;
std::vector<v8::Local<v8::Value>> argv_v8 = pre_process_args(argv);
if (try_catch.HasCaught()) {
Nan::FatalException(try_catch);
}
argv_v8.push_back(Nan::New(wrapper));
return this->post_process_return_value(
this->callback->Call(argv_v8.size(), &argv_v8[0])
);
} else {
/*
* This is invoked from the worker thread.
* No V8 context and functions available.
* Just wait for response from asynchronously
* scheduled JavaScript code
*
* XXX Issue #1048: We block here even if the
* event loop stops and the callback
* would never be executed.
* XXX Issue #857: By waiting here we occupy
* one of the threads taken from the
* uv threadpool. Might deadlock if
* async I/O executed from JavaScript callbacks.
*/
this->argv = argv;
uv_mutex_lock(&this->cv_mutex);
this->has_returned = false;
uv_async_send(this->async);
while (!this->has_returned) {
uv_cond_wait(&this->condition_variable, &this->cv_mutex);
}
uv_mutex_unlock(&this->cv_mutex);
return this->return_value;
}
}
template <typename T, typename L>
void CallbackBridge<T, L>::dispatched_async_uv_callback(uv_async_t *req) {
CallbackBridge* bridge = static_cast<CallbackBridge*>(req->data);
/*
* Function scheduled via uv_async mechanism, therefore
* it is invoked from the main JavaScript thread.
* V8 context is available.
*
* Establish Local<> scope for all functions
* from types invoked by pre_process_args() and
* post_process_args().
*/
Nan::HandleScope scope;
Nan::TryCatch try_catch;
std::vector<v8::Local<v8::Value>> argv_v8 = bridge->pre_process_args(bridge->argv);
if (try_catch.HasCaught()) {
Nan::FatalException(try_catch);
}
argv_v8.push_back(Nan::New(bridge->wrapper));
bridge->callback->Call(argv_v8.size(), &argv_v8[0]);
if (try_catch.HasCaught()) {
Nan::FatalException(try_catch);
}
}
template <typename T, typename L>
NAN_METHOD(CallbackBridge<T COMMA L>::ReturnCallback) {
/*
* Callback function invoked by the user code.
* It is invoked from the main JavaScript thread.
* V8 context is available.
*
* Implicit Local<> handle scope created by NAN_METHOD(.)
*/
CallbackBridge<T, L>* bridge = static_cast<CallbackBridge<T, L>*>(Nan::GetInternalFieldPointer(info.This(), 0));
Nan::TryCatch try_catch;
bridge->return_value = bridge->post_process_return_value(info[0]);
{
uv_mutex_lock(&bridge->cv_mutex);
bridge->has_returned = true;
uv_mutex_unlock(&bridge->cv_mutex);
}
uv_cond_broadcast(&bridge->condition_variable);
if (try_catch.HasCaught()) {
Nan::FatalException(try_catch);
}
}
template <typename T, typename L>
Nan::MaybeLocal<v8::Function> CallbackBridge<T, L>::get_wrapper_constructor() {
/* Uses handle scope created in the CallbackBridge<T, L> constructor */
if (wrapper_constructor.IsEmpty()) {
v8::Local<v8::FunctionTemplate> tpl = Nan::New<v8::FunctionTemplate>(New);
tpl->SetClassName(Nan::New("CallbackBridge").ToLocalChecked());
tpl->InstanceTemplate()->SetInternalFieldCount(1);
Nan::SetPrototypeTemplate(tpl, "success",
Nan::New<v8::FunctionTemplate>(ReturnCallback)
);
wrapper_constructor.Reset(Nan::GetFunction(tpl).ToLocalChecked());
}
return Nan::New(wrapper_constructor);
}
template <typename T, typename L>
NAN_METHOD(CallbackBridge<T COMMA L>::New) {
info.GetReturnValue().Set(info.This());
}
template <typename T, typename L>
void CallbackBridge<T, L>::async_gone(uv_handle_t *handle) {
delete (uv_async_t *)handle;
}
#endif
#include <nan.h>
#include <stdlib.h>
#include <string.h>
#include "create_string.h"
char* create_string(Nan::MaybeLocal<v8::Value> maybevalue) {
v8::Local<v8::Value> value;
if (maybevalue.ToLocal(&value)) {
if (value->IsNull() || !value->IsString()) {
return 0;
}
} else {
return 0;
}
v8::String::Utf8Value string(value);
char *str = (char *)malloc(string.length() + 1);
strcpy(str, *string);
return str;
}
#ifndef CREATE_STRING_H
#define CREATE_STRING_H
#include <nan.h>
char* create_string(Nan::MaybeLocal<v8::Value>);
#endif
#include <nan.h>
#include <stdexcept>
#include "custom_function_bridge.h"
#include "sass_types/factory.h"
#include "sass_types/value.h"
Sass_Value* CustomFunctionBridge::post_process_return_value(v8::Local<v8::Value> val) const {
SassTypes::Value *v_;
if ((v_ = SassTypes::Factory::unwrap(val))) {
return v_->get_sass_value();
} else {
return sass_make_error("A SassValue object was expected.");
}
}
std::vector<v8::Local<v8::Value>> CustomFunctionBridge::pre_process_args(std::vector<void*> in) const {
std::vector<v8::Local<v8::Value>> argv = std::vector<v8::Local<v8::Value>>();
for (void* value : in) {
argv.push_back(SassTypes::Factory::create(static_cast<Sass_Value*>(value))->get_js_object());
}
return argv;
}
#ifndef CUSTOM_FUNCTION_BRIDGE_H
#define CUSTOM_FUNCTION_BRIDGE_H
#include <nan.h>
#include <sass/values.h>
#include <sass/functions.h>
#include "callback_bridge.h"
class CustomFunctionBridge : public CallbackBridge<Sass_Value*> {
public:
CustomFunctionBridge(v8::Local<v8::Function> cb, bool is_sync) : CallbackBridge<Sass_Value*>(cb, is_sync) {}
private:
Sass_Value* post_process_return_value(v8::Local<v8::Value>) const;
std::vector<v8::Local<v8::Value>> pre_process_args(std::vector<void*>) const;
};
#endif
#include <nan.h>
#include <stdexcept>
#include "custom_importer_bridge.h"
#include "create_string.h"
SassImportList CustomImporterBridge::post_process_return_value(v8::Local<v8::Value> returned_value) const {
SassImportList imports = 0;
Nan::HandleScope scope;
if (returned_value->IsArray()) {
v8::Local<v8::Array> array = returned_value.As<v8::Array>();
imports = sass_make_import_list(array->Length());
for (size_t i = 0; i < array->Length(); ++i) {
v8::Local<v8::Value> value = Nan::Get(array, static_cast<uint32_t>(i)).ToLocalChecked();
if (!value->IsObject()) {
auto entry = sass_make_import_entry(0, 0, 0);
sass_import_set_error(entry, "returned array must only contain object literals", -1, -1);
continue;
}
v8::Local<v8::Object> object = value.As<v8::Object>();
if (value->IsNativeError()) {
char* message = create_string(Nan::Get(object, Nan::New<v8::String>("message").ToLocalChecked()));
imports[i] = sass_make_import_entry(0, 0, 0);
sass_import_set_error(imports[i], message, -1, -1);
}
else {
imports[i] = get_importer_entry(object);
}
}
}
else if (returned_value->IsNativeError()) {
imports = sass_make_import_list(1);
v8::Local<v8::Object> object = returned_value.As<v8::Object>();
char* message = create_string(Nan::Get(object, Nan::New<v8::String>("message").ToLocalChecked()));
imports[0] = sass_make_import_entry(0, 0, 0);
sass_import_set_error(imports[0], message, -1, -1);
}
else if (returned_value->IsObject()) {
imports = sass_make_import_list(1);
imports[0] = get_importer_entry(returned_value.As<v8::Object>());
}
return imports;
}
Sass_Import* CustomImporterBridge::check_returned_string(Nan::MaybeLocal<v8::Value> value, const char *msg) const
{
v8::Local<v8::Value> checked;
if (value.ToLocal(&checked)) {
if (!checked->IsUndefined() && !checked->IsString()) {
goto err;
} else {
return nullptr;
}
}
err:
auto entry = sass_make_import_entry(0, 0, 0);
sass_import_set_error(entry, msg, -1, -1);
return entry;
}
Sass_Import* CustomImporterBridge::get_importer_entry(const v8::Local<v8::Object>& object) const {
auto returned_file = Nan::Get(object, Nan::New<v8::String>("file").ToLocalChecked());
auto returned_contents = Nan::Get(object, Nan::New<v8::String>("contents").ToLocalChecked()).ToLocalChecked();
auto returned_map = Nan::Get(object, Nan::New<v8::String>("map").ToLocalChecked());
Sass_Import *err;
if ((err = check_returned_string(returned_file, "returned value of `file` must be a string")))
return err;
if ((err = check_returned_string(returned_contents, "returned value of `contents` must be a string")))
return err;
if ((err = check_returned_string(returned_map, "returned value of `returned_map` must be a string")))
return err;
char* path = create_string(returned_file);
char* contents = create_string(returned_contents);
char* srcmap = create_string(returned_map);
return sass_make_import_entry(path, contents, srcmap);
}
std::vector<v8::Local<v8::Value>> CustomImporterBridge::pre_process_args(std::vector<void*> in) const {
std::vector<v8::Local<v8::Value>> out;
for (void* ptr : in) {
out.push_back(Nan::New<v8::String>((char const*)ptr).ToLocalChecked());
}
return out;
}
#ifndef CUSTOM_IMPORTER_BRIDGE_H
#define CUSTOM_IMPORTER_BRIDGE_H
#include <nan.h>
#include <sass/functions.h>
#include <sass/values.h>
#include "callback_bridge.h"
typedef Sass_Import_List SassImportList;
class CustomImporterBridge : public CallbackBridge<SassImportList> {
public:
CustomImporterBridge(v8::Local<v8::Function> cb, bool is_sync) : CallbackBridge<SassImportList>(cb, is_sync) {}
private:
SassImportList post_process_return_value(v8::Local<v8::Value>) const;
Sass_Import* check_returned_string(Nan::MaybeLocal<v8::Value> value, const char *msg) const;
Sass_Import* get_importer_entry(const v8::Local<v8::Object>&) const;
std::vector<v8::Local<v8::Value>> pre_process_args(std::vector<void*>) const;
};
#endif
{
'targets': [
{
'target_name': 'libsass',
'win_delay_load_hook': 'false',
'type': 'static_library',
'defines': [
'LIBSASS_VERSION="<!(node -e "process.stdout.write(require(\'../package.json\').libsass)")"'
],
'defines!': [
'DEBUG'
],
'sources': [
'libsass/src/ast.cpp',
'libsass/src/base64vlq.cpp',
'libsass/src/bind.cpp',
'libsass/src/cencode.c',
'libsass/src/color_maps.cpp',
'libsass/src/constants.cpp',
'libsass/src/context.cpp',
'libsass/src/cssize.cpp',
'libsass/src/emitter.cpp',
'libsass/src/environment.cpp',
'libsass/src/error_handling.cpp',
'libsass/src/eval.cpp',
'libsass/src/expand.cpp',
'libsass/src/extend.cpp',
'libsass/src/file.cpp',
'libsass/src/functions.cpp',
'libsass/src/inspect.cpp',
'libsass/src/json.cpp',
'libsass/src/lexer.cpp',
'libsass/src/listize.cpp',
'libsass/src/memory_manager.cpp',
'libsass/src/node.cpp',
'libsass/src/output.cpp',
'libsass/src/parser.cpp',
'libsass/src/plugins.cpp',
'libsass/src/position.cpp',
'libsass/src/prelexer.cpp',
'libsass/src/remove_placeholders.cpp',
'libsass/src/sass.cpp',
'libsass/src/sass2scss.cpp',
'libsass/src/sass_context.cpp',
'libsass/src/sass_functions.cpp',
'libsass/src/sass_util.cpp',
'libsass/src/sass_values.cpp',
'libsass/src/source_map.cpp',
'libsass/src/to_c.cpp',
'libsass/src/to_value.cpp',
'libsass/src/units.cpp',
'libsass/src/utf8_string.cpp',
'libsass/src/util.cpp',
'libsass/src/values.cpp'
],
'cflags!': [
'-fno-rtti',
'-fno-exceptions'
],
'cflags_cc!': [
'-fno-rtti',
'-fno-exceptions'
],
'cflags_cc': [
'-fexceptions',
'-frtti',
],
'include_dirs': [ 'libsass/include' ],
'direct_dependent_settings': {
'include_dirs': [ 'libsass/include' ],
},
'conditions': [
['OS=="mac"', {
'xcode_settings': {
'CLANG_CXX_LANGUAGE_STANDARD': 'c++11',
'CLANG_CXX_LIBRARY': 'libc++',
'OTHER_LDFLAGS': [],
'GCC_ENABLE_CPP_EXCEPTIONS': 'YES',
'GCC_ENABLE_CPP_RTTI': 'YES',
'MACOSX_DEPLOYMENT_TARGET': '10.7'
}
}],
['OS=="win"', {
'msvs_settings': {
'VCCLCompilerTool': {
'AdditionalOptions': [
'/GR',
'/EHsc'
]
}
},
'conditions': [
['MSVS_VERSION < "2015"', {
'sources': [
'libsass/src/c99func.c'
]
}]
]
}],
['OS!="win"', {
'cflags_cc+': [
'-std=c++0x'
]
}]
]
}
]
}
# This file is for unifying the coding style for different editors and IDEs
# editorconfig.org
root = true
[*]
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
indent_style = spaces
indent_size = 2
[{Makefile, GNUmakefile.am}]
indent_style = tab
indent_size = 4
# Auto detect text files and perform LF normalization
* text=auto
# Miscellaneous stuff
/sassc
/sass-spec
VERSION
.DS_Store
.sass-cache
*.gem
*.gcno
.svn/*
.cproject
.project
.settings/
# Configuration stuff
GNUmakefile.in
GNUmakefile
/aclocal.m4
/autom4te.cache/
/src/config.h
/config.h.in
/config.log
/config.status
/configure
/libtool
/m4/libtool.m4
/m4/ltoptions.m4
/m4/ltsugar.m4
/m4/ltversion.m4
/m4/lt~obsolete.m4
/script/ar-lib
/script/compile
/script/config.guess
/script/config.sub
/script/depcomp
/script/install-sh
/script/ltmain.sh
/script/missing
/script/test-driver
/src/stamp-h1
/src/Makefile.in
/src/Makefile
libsass/*
# Build stuff
*.o
*.lo
*.so
*.dll
*.a
*.suo
*.sdf
*.opendb
*.opensdf
a.out
libsass.js
tester
tester.exe
build/
config.h.in*
lib/pkgconfig/
bin/*
.deps/
.libs/
win/bin
*.user
# Final results
sassc++
libsass.la
src/support/libsass.pc
# Cloned testing dirs
sassc/
sass-spec/
installer/
language: cpp
sudo: false
os:
- linux
- osx
compiler:
- gcc
- clang
# don't create redundant code coverage reports
# - AUTOTOOLS=yes COVERAGE=yes BUILD=static
# - AUTOTOOLS=no COVERAGE=yes BUILD=shared
# - AUTOTOOLS=no COVERAGE=no BUILD=static
# further speed up day by day travis-ci builds
# re-enable this if you change the makefiles
# this will still catch all coding errors!
# - AUTOTOOLS=yes COVERAGE=no BUILD=static
env:
- AUTOTOOLS=no COVERAGE=no BUILD=shared
- AUTOTOOLS=no COVERAGE=yes BUILD=static
- AUTOTOOLS=yes COVERAGE=no BUILD=shared
# currenty there are various issues when
# built with coverage, clang and autotools
# - AUTOTOOLS=yes COVERAGE=yes BUILD=shared
matrix:
exclude:
- compiler: clang
env: AUTOTOOLS=yes COVERAGE=yes BUILD=static
- os: linux
env: AUTOTOOLS=no COVERAGE=no BUILD=shared
- os: osx
compiler: gcc
- os: osx
env: AUTOTOOLS=no BUILD=static
script: ./script/ci-build-libsass
before_install: ./script/ci-install-deps
install: ./script/ci-install-compiler
after_success: ./script/ci-report-coverage
Copyright (C) 2012 by Hampton Catlin
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
The following files in the spec were taken from the original Ruby Sass project which
is copyright Hampton Catlin, Nathan Weizenbaum, and Chris Eppstein and under
the same license.
ACLOCAL_AMFLAGS = ${ACLOCAL_FLAGS} -I m4 -I script
AM_COPT = -Wall -O2
AM_COVLDFLAGS =
if ENABLE_COVERAGE
AM_COPT = -O0 --coverage
AM_COVLDFLAGS += -lgcov
endif
AM_CPPFLAGS = -I$(top_srcdir)/include
AM_CFLAGS = $(AM_COPT)
AM_CXXFLAGS = $(AM_COPT)
AM_LDFLAGS = $(AM_COPT) $(AM_COVLDFLAGS)
# only needed to support old source tree
# we have moved the files to src folder
AM_CPPFLAGS += -I$(top_srcdir)
RESOURCES =
if COMPILER_IS_MINGW32
RESOURCES += res/libsass.rc
AM_CXXFLAGS += -std=gnu++0x
else
AM_CXXFLAGS += -std=c++0x
endif
if ENABLE_TESTS
noinst_PROGRAMS = tester
tester_LDADD = src/libsass.la
tester_SOURCES = $(SASS_SASSC_PATH)/sassc.c
tester_VERSION ?= `cd "$(SASS_SASSC_PATH)" && ./version.sh`
tester_CFLAGS = $(AM_CFLAGS) -DSASSC_VERSION="\"$(tester_VERSION)\""
tester_CXXFLAGS = $(AM_CXXFLAGS) -DSASSC_VERSION="\"$(tester_VERSION)\""
tester_LDFLAGS = $(AM_LDFLAGS)
if ENABLE_COVERAGE
nodist_EXTRA_tester_SOURCES = non-existent-file-to-force-CXX-linking.cxx
endif
SASS_SASSC_PATH ?= $(top_srcdir)/sassc
SASS_SPEC_PATH ?= $(top_srcdir)/sass-spec
TESTS = \
$(SASS_SPEC_PATH)/spec/basic \
$(SASS_SPEC_PATH)/spec/css \
$(SASS_SPEC_PATH)/spec/extend-tests \
$(SASS_SPEC_PATH)/spec/extends \
$(SASS_SPEC_PATH)/spec/libsass \
$(SASS_SPEC_PATH)/spec/libsass-closed-issues \
$(SASS_SPEC_PATH)/spec/maps \
$(SASS_SPEC_PATH)/spec/misc \
$(SASS_SPEC_PATH)/spec/regressions \
$(SASS_SPEC_PATH)/spec/scss \
$(SASS_SPEC_PATH)/spec/scss-tests \
$(SASS_SPEC_PATH)/spec/types
SASS_TEST_FLAGS = -V 3.4 --impl libsass
LOG_DRIVER = env AM_TAP_AWK='$(AWK)' $(SHELL) ./script/tap-driver
AM_LOG_FLAGS = -c ./tester $(LOG_FLAGS)
if USE_TAP
AM_LOG_FLAGS += -t
SASS_TEST_FLAGS += -t | tapout
LOG_COMPILER = ./script/tap-runner $(RUBY) $(SASS_SPEC_PATH)/sass-spec.rb
else
LOG_COMPILER = $(RUBY) $(SASS_SPEC_PATH)/sass-spec.rb
endif
SASS_TESTER = $(RUBY) $(SASS_SPEC_PATH)/sass-spec.rb
SASS_TESTER += -c $(SASS_LIBSASS_PATH)/tester$(EXEEXT)
test:
$(SASS_TESTER) $(LOG_FLAGS) $(SASS_SPEC_PATH) $(SASS_TEST_FLAGS)
test_build:
$(SASS_TESTER) $(LOG_FLAGS) $(SASS_SPEC_PATH) $(SASS_TEST_FLAGS)
test_full:
$(SASS_TESTER) --run-todo $(LOG_FLAGS) $(SASS_SPEC_PATH) $(SASS_TEST_FLAGS)
test_probe:
$(SASS_TESTER) --probe-todo $(LOG_FLAGS) $(SASS_SPEC_PATH) $(SASS_TEST_FLAGS)
endif
SUBDIRS = src
// Autotools requires us to have this file. Boo.
Copyright (C) 2012-2016 by the Sass Open Source Foundation
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
The following files in the spec were taken from the original Ruby Sass project which
is copyright Hampton Catlin, Nathan Weizenbaum, and Chris Eppstein and under
the same license.
OS ?= $(shell uname -s)
CC ?= gcc
CXX ?= g++
RM ?= rm -f
CP ?= cp -a
MKDIR ?= mkdir
RMDIR ?= rmdir
WINDRES ?= windres
# Solaris/Illumos flavors
# ginstall from coreutils
ifeq ($(OS),SunOS)
INSTALL ?= ginstall
endif
INSTALL ?= install
CFLAGS ?= -Wall
CXXFLAGS ?= -Wall
LDFLAGS ?= -Wall
ifneq "$(COVERAGE)" "yes"
CFLAGS += -O2
CXXFLAGS += -O2
LDFLAGS += -O2
endif
LDFLAGS += -Wl,-undefined,error
CAT ?= $(if $(filter $(OS),Windows_NT),type,cat)
ifneq (,$(findstring /cygdrive/,$(PATH)))
UNAME := Cygwin
else
ifneq (,$(findstring Windows_NT,$(OS)))
UNAME := Windows
else
ifneq (,$(findstring mingw32,$(MAKE)))
UNAME := Windows
else
ifneq (,$(findstring MINGW32,$(shell uname -s)))
UNAME = Windows
else
UNAME := $(shell uname -s)
endif
endif
endif
endif
ifeq ($(SASS_LIBSASS_PATH),)
SASS_LIBSASS_PATH = $(abspath $(CURDIR))
endif
ifeq ($(LIBSASS_VERSION),)
ifneq ($(wildcard ./.git/ ),)
LIBSASS_VERSION ?= $(shell git describe --abbrev=4 --dirty --always --tags)
endif
endif
ifeq ($(LIBSASS_VERSION),)
ifneq ($(wildcard VERSION),)
LIBSASS_VERSION ?= $(shell $(CAT) VERSION)
endif
endif
ifneq ($(LIBSASS_VERSION),)
CFLAGS += -DLIBSASS_VERSION="\"$(LIBSASS_VERSION)\""
CXXFLAGS += -DLIBSASS_VERSION="\"$(LIBSASS_VERSION)\""
endif
# enable mandatory flag
ifeq (Windows,$(UNAME))
ifneq ($(BUILD),shared)
STATIC_ALL ?= 1
endif
STATIC_LIBGCC ?= 1
STATIC_LIBSTDCPP ?= 1
CXXFLAGS += -std=gnu++0x
LDFLAGS += -std=gnu++0x
else
STATIC_ALL ?= 0
STATIC_LIBGCC ?= 0
STATIC_LIBSTDCPP ?= 0
CXXFLAGS += -std=c++0x
LDFLAGS += -std=c++0x
endif
ifneq ($(SASS_LIBSASS_PATH),)
CFLAGS += -I $(SASS_LIBSASS_PATH)/include
CXXFLAGS += -I $(SASS_LIBSASS_PATH)/include
else
# this is needed for mingw
CFLAGS += -I include
CXXFLAGS += -I include
endif
ifneq ($(EXTRA_CFLAGS),)
CFLAGS += $(EXTRA_CFLAGS)
endif
ifneq ($(EXTRA_CXXFLAGS),)
CXXFLAGS += $(EXTRA_CXXFLAGS)
endif
ifneq ($(EXTRA_LDFLAGS),)
LDFLAGS += $(EXTRA_LDFLAGS)
endif
LDLIBS = -lm
ifneq ($(BUILD),shared)
LDLIBS += -lstdc++
endif
# link statically into lib
# makes it a lot more portable
# increases size by about 50KB
ifeq ($(STATIC_ALL),1)
LDFLAGS += -static
endif
ifeq ($(STATIC_LIBGCC),1)
LDFLAGS += -static-libgcc
endif
ifeq ($(STATIC_LIBSTDCPP),1)
LDFLAGS += -static-libstdc++
endif
ifeq ($(UNAME),Darwin)
CFLAGS += -stdlib=libc++
CXXFLAGS += -stdlib=libc++
LDFLAGS += -stdlib=libc++
endif
ifneq (Windows,$(UNAME))
ifneq (FreeBSD,$(UNAME))
LDFLAGS += -ldl
LDLIBS += -ldl
endif
endif
ifneq ($(BUILD),shared)
BUILD = static
endif
ifeq (,$(TRAVIS_BUILD_DIR))
ifeq ($(OS),SunOS)
PREFIX ?= /opt/local
else
PREFIX ?= /usr/local
endif
else
PREFIX ?= $(TRAVIS_BUILD_DIR)
endif
SASS_SASSC_PATH ?= sassc
SASS_SPEC_PATH ?= sass-spec
SASS_SPEC_SPEC_DIR ?= spec
SASSC_BIN = $(SASS_SASSC_PATH)/bin/sassc
RUBY_BIN = ruby
LIB_STATIC = $(SASS_LIBSASS_PATH)/lib/libsass.a
LIB_SHARED = $(SASS_LIBSASS_PATH)/lib/libsass.so
ifeq (Windows,$(UNAME))
ifeq (shared,$(BUILD))
CFLAGS += -D ADD_EXPORTS
CXXFLAGS += -D ADD_EXPORTS
LIB_SHARED = $(SASS_LIBSASS_PATH)/lib/libsass.dll
endif
else
ifneq (Cygwin,$(UNAME))
CFLAGS += -fPIC
CXXFLAGS += -fPIC
LDFLAGS += -fPIC
endif
endif
ifeq (Windows,$(UNAME))
SASSC_BIN = $(SASS_SASSC_PATH)/bin/sassc.exe
endif
include Makefile.conf
RESOURCES =
STATICLIB = lib/libsass.a
SHAREDLIB = lib/libsass.so
ifeq (Windows,$(UNAME))
RESOURCES += res/resource.rc
SHAREDLIB = lib/libsass.dll
ifeq (shared,$(BUILD))
CFLAGS += -D ADD_EXPORTS
CXXFLAGS += -D ADD_EXPORTS
endif
else
ifneq (Cygwin,$(UNAME))
CFLAGS += -fPIC
CXXFLAGS += -fPIC
LDFLAGS += -fPIC
endif
endif
OBJECTS = $(addprefix src/,$(SOURCES:.cpp=.o))
COBJECTS = $(addprefix src/,$(CSOURCES:.c=.o))
RCOBJECTS = $(RESOURCES:.rc=.o)
DEBUG_LVL ?= NONE
CLEANUPS ?=
CLEANUPS += $(RCOBJECTS)
CLEANUPS += $(COBJECTS)
CLEANUPS += $(OBJECTS)
CLEANUPS += $(LIBSASS_LIB)
all: $(BUILD)
debug: $(BUILD)
debug-static: LDFLAGS := -g $(filter-out -O2,$(LDFLAGS))
debug-static: CFLAGS := -g -DDEBUG -DDEBUG_LVL="$(DEBUG_LVL)" $(filter-out -O2,$(CFLAGS))
debug-static: CXXFLAGS := -g -DDEBUG -DDEBUG_LVL="$(DEBUG_LVL)" $(filter-out -O2,$(CXXFLAGS))
debug-static: static
debug-shared: LDFLAGS := -g $(filter-out -O2,$(LDFLAGS))
debug-shared: CFLAGS := -g -DDEBUG -DDEBUG_LVL="$(DEBUG_LVL)" $(filter-out -O2,$(CFLAGS))
debug-shared: CXXFLAGS := -g -DDEBUG -DDEBUG_LVL="$(DEBUG_LVL)" $(filter-out -O2,$(CXXFLAGS))
debug-shared: shared
lib:
$(MKDIR) lib
lib/libsass.a: lib $(COBJECTS) $(OBJECTS)
$(AR) rcvs $@ $(COBJECTS) $(OBJECTS)
lib/libsass.so: lib $(COBJECTS) $(OBJECTS)
$(CXX) -shared $(LDFLAGS) -o $@ $(COBJECTS) $(OBJECTS) $(LDLIBS)
lib/libsass.dll: lib $(COBJECTS) $(OBJECTS) $(RCOBJECTS)
$(CXX) -shared $(LDFLAGS) -o $@ $(COBJECTS) $(OBJECTS) $(RCOBJECTS) $(LDLIBS) -s -Wl,--subsystem,windows,--out-implib,lib/libsass.a
%.o: %.c
$(CC) $(CFLAGS) -c -o $@ $<
%.o: %.rc
$(WINDRES) -i $< -o $@
%.o: %.cpp
$(CXX) $(CXXFLAGS) -c -o $@ $<
%: %.o static
$(CXX) $(CXXFLAGS) -o $@ $+ $(LDFLAGS) $(LDLIBS)
install: install-$(BUILD)
static: $(STATICLIB)
shared: $(SHAREDLIB)
$(DESTDIR)$(PREFIX):
$(MKDIR) $(DESTDIR)$(PREFIX)
$(DESTDIR)$(PREFIX)/lib: $(DESTDIR)$(PREFIX)
$(MKDIR) $(DESTDIR)$(PREFIX)/lib
$(DESTDIR)$(PREFIX)/include: $(DESTDIR)$(PREFIX)
$(MKDIR) $(DESTDIR)$(PREFIX)/include
$(DESTDIR)$(PREFIX)/include/sass: $(DESTDIR)$(PREFIX)/include
$(MKDIR) $(DESTDIR)$(PREFIX)/include/sass
$(DESTDIR)$(PREFIX)/include/%.h: include/%.h \
$(DESTDIR)$(PREFIX)/include \
$(DESTDIR)$(PREFIX)/include/sass
$(INSTALL) -v -m0644 "$<" "$@"
install-headers: $(DESTDIR)$(PREFIX)/include/sass.h \
$(DESTDIR)$(PREFIX)/include/sass2scss.h \
$(DESTDIR)$(PREFIX)/include/sass/base.h \
$(DESTDIR)$(PREFIX)/include/sass/version.h \
$(DESTDIR)$(PREFIX)/include/sass/values.h \
$(DESTDIR)$(PREFIX)/include/sass/context.h \
$(DESTDIR)$(PREFIX)/include/sass/functions.h
$(DESTDIR)$(PREFIX)/lib/%.a: lib/%.a \
$(DESTDIR)$(PREFIX)/lib
@$(INSTALL) -v -m0755 "$<" "$@"
$(DESTDIR)$(PREFIX)/lib/%.so: lib/%.so \
$(DESTDIR)$(PREFIX)/lib
@$(INSTALL) -v -m0755 "$<" "$@"
$(DESTDIR)$(PREFIX)/lib/%.dll: lib/%.dll \
$(DESTDIR)$(PREFIX)/lib
@$(INSTALL) -v -m0755 "$<" "$@"
install-static: $(DESTDIR)$(PREFIX)/lib/libsass.a
install-shared: $(DESTDIR)$(PREFIX)/lib/libsass.so \
install-headers
$(SASSC_BIN): $(BUILD)
$(MAKE) -C $(SASS_SASSC_PATH)
sassc: $(SASSC_BIN)
$(SASSC_BIN) -v
version: $(SASSC_BIN)
$(SASSC_BIN) -h
$(SASSC_BIN) -v
test: $(SASSC_BIN)
$(RUBY_BIN) $(SASS_SPEC_PATH)/sass-spec.rb -V 3.4 -c $(SASSC_BIN) --impl libsass $(LOG_FLAGS) $(SASS_SPEC_PATH)/$(SASS_SPEC_SPEC_DIR)
test_build: $(SASSC_BIN)
$(RUBY_BIN) $(SASS_SPEC_PATH)/sass-spec.rb -V 3.4 -c $(SASSC_BIN) --impl libsass $(LOG_FLAGS) $(SASS_SPEC_PATH)/$(SASS_SPEC_SPEC_DIR)
test_full: $(SASSC_BIN)
$(RUBY_BIN) $(SASS_SPEC_PATH)/sass-spec.rb -V 3.4 -c $(SASSC_BIN) --impl libsass --run-todo $(LOG_FLAGS) $(SASS_SPEC_PATH)/$(SASS_SPEC_SPEC_DIR)
test_probe: $(SASSC_BIN)
$(RUBY_BIN) $(SASS_SPEC_PATH)/sass-spec.rb -V 3.4 -c $(SASSC_BIN) --impl libsass --probe-todo $(LOG_FLAGS) $(SASS_SPEC_PATH)/$(SASS_SPEC_SPEC_DIR)
clean-objects: lib
-$(RM) lib/*.a lib/*.so lib/*.dll lib/*.la
-$(RMDIR) lib
clean: clean-objects
$(RM) $(CLEANUPS)
clean-all:
$(MAKE) -C $(SASS_SASSC_PATH) clean
lib-file: lib-file-$(BUILD)
lib-opts: lib-opts-$(BUILD)
lib-file-static:
@echo $(LIB_STATIC)
lib-file-shared:
@echo $(LIB_SHARED)
lib-opts-static:
@echo -L"$(SASS_LIBSASS_PATH)/lib"
lib-opts-shared:
@echo -L"$(SASS_LIBSASS_PATH)/lib -lsass"
.PHONY: all static shared sassc \
version install-headers \
clean clean-all clean-objects \
debug debug-static debug-shared \
install install-static install-shared \
lib-opts lib-opts-shared lib-opts-static \
lib-file lib-file-shared lib-file-static
.DELETE_ON_ERROR:
# this is merely a common Makefile multiple implementers can use
SOURCES = \
ast.cpp \
base64vlq.cpp \
bind.cpp \
color_maps.cpp \
constants.cpp \
context.cpp \
cssize.cpp \
emitter.cpp \
environment.cpp \
error_handling.cpp \
eval.cpp \
expand.cpp \
extend.cpp \
file.cpp \
functions.cpp \
inspect.cpp \
json.cpp \
lexer.cpp \
listize.cpp \
memory_manager.cpp \
node.cpp \
output.cpp \
parser.cpp \
plugins.cpp \
position.cpp \
prelexer.cpp \
remove_placeholders.cpp \
sass.cpp \
sass_util.cpp \
sass_values.cpp \
sass_context.cpp \
sass_functions.cpp \
sass2scss.cpp \
source_map.cpp \
to_c.cpp \
to_value.cpp \
units.cpp \
utf8_string.cpp \
values.cpp \
util.cpp
CSOURCES = cencode.c
LibSass
=======
by Aaron Leung ([@akhleung]), Hampton Catlin ([@hcatlin]), Marcel Greter ([@mgreter]) and Michael Mifsud ([@xzyfer])
[![Linux CI](https://travis-ci.org/sass/libsass.svg?branch=master)](https://travis-ci.org/sass/libsass)
[![Windows CI](https://ci.appveyor.com/api/projects/status/github/sass/libsass?svg=true)](https://ci.appveyor.com/project/sass/libsass/branch/master)
[![Bountysource](https://www.bountysource.com/badge/tracker?tracker_id=283068)](https://www.bountysource.com/trackers/283068-libsass?utm_source=283068&utm_medium=shield&utm_campaign=TRACKER_BADGE)
[![Coverage Status](https://img.shields.io/coveralls/sass/libsass.svg)](https://coveralls.io/r/sass/libsass?branch=feature%2Ftest-travis-ci-3)
[![Join us](https://libsass-slack.herokuapp.com/badge.svg)](https://libsass-slack.herokuapp.com/)
https://github.com/sass/libsass
LibSass is just a library, but if you want to RUN LibSass,
then go to https://github.com/sass/sassc or
https://github.com/sass/sassc-ruby or
[find your local implementer](docs/implementations.md).
LibSass requires GCC 4.6+ or Clang/LLVM. If your OS is older, this version may not compile.
On Windows, you need MinGW with GCC 4.6+ or VS 2013 Update 4+. It is also possible to build LibSass with Clang/LLVM on Windows.
About
-----
LibSass is a C/C++ port of the Sass CSS precompiler. The original version was written in Ruby, but this version is meant for efficiency and portability.
This library strives to be light, simple, and easy to build and integrate with a variety of platforms and languages.
Developing
----------
As you may have noticed, the LibSass repo itself has
no executables and no tests. Oh noes! How can you develop???
Well, luckily, [SassC](http://github.com/sass/sassc) is the official binary wrapper for
LibSass and is *always* kept in sync. SassC uses a git submodule
to include LibSass. When developing LibSass, its best to actually
check out SassC and develop in that directory with the SassC spec
and tests there.
We even run Travis tests for SassC!
Tests
-------
Since LibSass is a pure library, tests are run through the [SassSpec](https://github.com/sass/sass-spec) project using the [SassC](http://github.com/sass/sassc) driver.
To run tests against LibSass while developing, you can run `./script/spec`. This will clone SassC and Sass-Spec under the project folder and then run the Sass-Spec test suite. You may want to update the clones to ensure you have the latest version.
Library Usage
-------------
While LibSass is a library primarily written in C++, it provides a simple
C interface which should be used by most implementers. LibSass does not do
much on its own without an implementer. This can be a command line tool, like
[sassc](https://github.com/sass/sassc) or a [binding](docs/implementations.md)
to your favorite programing language.
If you want to build or interface with LibSass, we recommend to check out the
documentation pages about [building LibSass](docs/build.md) and
the [C-API documentation](docs/api-doc.md).
About Sass
----------
Sass is a CSS pre-processor language to add on exciting, new,
awesome features to CSS. Sass was the first language of its kind
and by far the most mature and up to date codebase.
Sass was originally concieved of by the co-creator of this library,
Hampton Catlin ([@hcatlin]). Most of the language has been the result of years
of work by Natalie Weizenbaum ([@nex3]) and Chris Eppstein ([@chriseppstein]).
For more information about Sass itself, please visit http://sass-lang.com
Initial development of libsass by Aaron Leung and Hampton Catlin was supported by [Moovweb](http://www.moovweb.com).
Licensing
---------
Our MIT license is designed to be as simple, and liberal as possible.
[@hcatlin]: https://github.com/hcatlin
[@akhleung]: https://github.com/akhleung
[@chriseppstein]: https://github.com/chriseppstein
[@nex3]: https://github.com/nex3
[@mgreter]: https://github.com/mgreter
[@xzyfer]: https://github.com/xzyfer
sass2scss was originally written by [Marcel Greter](@mgreter)
and he happily agreed to have it merged into the project.
Serious about security
======================
The LibSass team recognizes the important contributions the security research
community can make. We therefore encourage reporting security issues with the
code contained in this repository.
If you believe you have discovered a security vulnerability, please report it at
https://hackerone.com/libsass instead of GitHub.
os: Visual Studio 2013
environment:
CTEST_OUTPUT_ON_FAILURE: 1
ruby_version: 22-x64
TargetPath: sassc/bin/sassc
matrix:
- Compiler: msvc
Config: Release
- Compiler: msvc
Config: Debug
- Compiler: mingw
Build: static
- Compiler: mingw
Build: shared
cache:
- C:\Ruby%ruby_version%\lib\ruby\gems
- C:\mingw64
install:
- git clone https://github.com/sass/sassc.git
- git clone https://github.com/sass/sass-spec.git
- set PATH=C:\Ruby%ruby_version%\bin;%PATH%
- ps: |
if(!(gem which minitest 2>$nul)) { gem install minitest --no-ri --no-rdoc }
if ($env:Compiler -eq "mingw" -AND -Not (Test-Path "C:\mingw64")) {
# Install MinGW.
$file = "x86_64-4.9.2-release-win32-seh-rt_v4-rev3.7z"
wget https://bintray.com/artifact/download/drewwells/generic/$file -OutFile $file
&7z x -oC:\ $file > $null
}
- set PATH=C:\mingw64\bin;%PATH%
- set CC=gcc
build_script:
- ps: |
if ($env:Compiler -eq "mingw") {
mingw32-make -j4 sassc
} else {
msbuild /m:4 /p:Configuration=$env:Config sassc\win\sassc.sln
}
# print the branding art
mv script/branding script/branding.ps1
script/branding.ps1
# print the version info
&$env:TargetPath -v
ruby -v
test_script:
- ps: |
$PRNR = $env:APPVEYOR_PULL_REQUEST_NUMBER
if ($PRNR) {
echo "Fetching info for PR $PRNR"
wget https://api.github.com/repos/sass/libsass/pulls/$PRNR -OutFile pr.json
$json = cat pr.json -Raw
$SPEC_PR = [regex]::match($json,'sass\/sass-spec(#|\/pull\/)([0-9]+)').Groups[2].Value
if ($SPEC_PR) {
echo "Checkout sass spec PR $SPEC_PR"
git -C sass-spec fetch -q -u origin pull/$SPEC_PR/head:ci-spec-pr-$SPEC_PR
git -C sass-spec checkout -q --force ci-spec-pr-$SPEC_PR
}
}
ruby sass-spec/sass-spec.rb -V 3.4 --probe-todo --impl libsass -c $env:TargetPath -s sass-spec/spec
if(-not($?)) {
echo "sass-spec tests failed"
exit 1
}
Write-Host "Explicitly testing the case when cwd has Cyrillic characters: " -nonewline
# See comments in gh-1774 for details.
$env:TargetPath = Join-Path $pwd.Path $env:TargetPath
cd sass-spec/spec/libsass/Sáss-UŢF8/
&$env:TargetPath ./input.scss 2>&1>$null
if(-not($?)) {
echo "Failed!"
exit 1
} else {
echo "Success!"
}
# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
AC_PREREQ([2.61])
AC_INIT([libsass], m4_esyscmd_s([./version.sh]), [support@moovweb.com])
AC_CONFIG_SRCDIR([src/ast.hpp])
AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_HEADERS([src/config.h])
AC_CONFIG_FILES([include/sass/version.h])
AC_CONFIG_AUX_DIR([script])
# These are flags passed to automake
# Though they look like gcc flags!
AM_INIT_AUTOMAKE([foreign parallel-tests -Wall])
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([no])])
# would fail with mingw otherwise
# m4_pattern_allow([AM_PROG_AR])
# Checks for programs.
AC_PROG_CC
AC_PROG_CXX
AC_LANG_PUSH([C])
AC_LANG_PUSH([C++])
AC_GNU_SOURCE
# Check fails on Travis, but it works fine
# AX_CXX_COMPILE_STDCXX_11([ext],[optional])
AC_CHECK_TOOL([AR], [ar], [false])
if test "x$is_mingw32" != "xyes"; then
AC_CHECK_TOOL([DLLTOOL], [dlltool], [false])
AC_CHECK_TOOL([DLLWRAP], [dllwrap], [false])
AC_CHECK_TOOL([WINDRES], [windres], [false])
fi
LT_INIT([dlopen])
# Checks for header files.
AC_CHECK_HEADERS([unistd.h])
# Checks for typedefs, structures, and compiler characteristics.
AC_TYPE_SIZE_T
# Checks for library functions.
AC_FUNC_MALLOC
AC_CHECK_FUNCS([floor getcwd strtol])
# Checks for testing.
AC_ARG_ENABLE(tests, AS_HELP_STRING([--enable-tests], [enable testing the build]),
[enable_tests="$enableval"], [enable_tests=no])
AS_CASE([$target], [*-*-mingw32], [is_mingw32=yes], [is_mingw32=no])
AM_CONDITIONAL(COMPILER_IS_MINGW32, test "x$is_mingw32" = "xyes")
dnl The dlopen() function is in the C library for *BSD and in
dnl libdl on GLIBC-based systems
if test "x$is_mingw32" != "xyes"; then
AC_SEARCH_LIBS([dlopen], [dl dld], [], [
AC_MSG_ERROR([unable to find the dlopen() function])
])
fi
if test "x$enable_tests" = "xyes"; then
AC_PROG_CC
AC_PROG_AWK
# test need minitest gem
AC_PATH_PROG(RUBY, [ruby])
AC_PATH_PROG(TAPOUT, [tapout])
AC_REQUIRE_AUX_FILE([tap-driver])
AC_REQUIRE_AUX_FILE([tap-runner])
AC_ARG_WITH(sassc-dir,
AS_HELP_STRING([--with-sassc-dir=<dir>], [specify directory of sassc sources for testing (default: sassc)]),
[sassc_dir="$withval"], [sassc_dir="sassc"])
AC_CHECK_FILE([$sassc_dir/sassc.c], [], [
AC_MSG_ERROR([Unable to find sassc directory.
You must clone the sassc repository in this directory or specify
the --with-sassc-dir=<dir> argument.
])
])
SASS_SASSC_PATH=$sassc_dir
AC_SUBST(SASS_SASSC_PATH)
AC_ARG_WITH(sass-spec-dir,
AS_HELP_STRING([--with-sass-spec-dir=<dir>], [specify directory of sass-spec for testing (default: sass-spec)]),
[sass_spec_dir="$withval"], [sass_spec_dir="sass-spec"])
AC_CHECK_FILE([$sass_spec_dir/sass-spec.rb], [], [
AC_MSG_ERROR([Unable to find sass-spec directory.
You must clone the sass-spec repository in this directory or specify
the --with-sass-spec-dir=<dir> argument.
])
])
# Automake doesn't like its tests in an absolute path, so we make it relative.
case $sass_spec_dir in
/*)
SASS_SPEC_PATH=`$RUBY -e "require 'pathname'; puts Pathname.new('$sass_spec_dir').relative_path_from(Pathname.new('$PWD')).to_s"`
;;
*)
SASS_SPEC_PATH="$sass_spec_dir"
;;
esac
AC_SUBST(SASS_SPEC_PATH)
# TODO: Remove this when automake requirements are 1.12+
AC_MSG_CHECKING([whether we can use TAP mode])
tmp=`$AWK '/TEST_LOG_DRIVER/' $srcdir/GNUmakefile.in`
if test "x$tmp" != "x"; then
use_tap=yes
else
use_tap=no
fi
AC_MSG_RESULT([$use_tap])
fi
AM_CONDITIONAL(ENABLE_TESTS, test "x$enable_tests" = "xyes")
AM_CONDITIONAL(USE_TAP, test "x$use_tap" = "xyes")
AC_ARG_ENABLE([coverage],
[AS_HELP_STRING([--enable-coverage],
[enable coverage report for test suite])],
[enable_cov=$enableval],
[enable_cov=no])
if test "x$enable_cov" = "xyes"; then
AC_CHECK_PROG(GCOV, gcov, gcov)
# Remove all optimization flags from C[XX]FLAGS
changequote({,})
CFLAGS=`echo "$CFLAGS" | $SED -e 's/-O[0-9]*//g'`
CXXFLAGS=`echo "$CXXFLAGS" | $SED -e 's/-O[0-9]*//g'`
changequote([,])
AC_SUBST(GCOV)
fi
AM_CONDITIONAL(ENABLE_COVERAGE, test "x$enable_cov" = "xyes")
AC_SUBST(PACKAGE_VERSION)
AC_MSG_NOTICE([Building libsass ($VERSION)])
AC_CONFIG_FILES([GNUmakefile src/GNUmakefile src/support/libsass.pc])
AC_OUTPUT
Name: libsass
Version: %{version}
Release: 1%{?dist}
Summary: A C/C++ implementation of a Sass compiler
License: MIT
URL: http://libsass.org
Source0: %{name}-%{version}.tar.gz
BuildRequires: gcc-c++ >= 4.7
BuildRequires: autoconf
BuildRequires: automake
BuildRequires: libtool
%description
LibSass is a C/C++ port of the Sass engine. The point is to be simple, fast, and easy to integrate.
%package devel
Summary: Development files for %{name}
Requires: %{name}%{?_isa} = %{version}-%{release}
%description devel
The %{name}-devel package contains libraries and header files for
developing applications that use %{name}.
%prep
%setup -q
autoreconf --force --install
%build
%configure --disable-static \
--disable-tests \
--enable-shared
make %{?_smp_mflags}
%install
%make_install
find $RPM_BUILD_ROOT -name '*.la' -exec rm -f {} ';'
%post -p /sbin/ldconfig
%postun -p /sbin/ldconfig
%files
%doc Readme.md LICENSE
%{_libdir}/*.so.*
%files devel
%doc
%{_includedir}/*
%{_libdir}/*.so
%{_libdir}/pkgconfig/*.pc
%changelog
* Tue Feb 10 2015 Gawain Lynch <gawain.lynch@gmail.com> - 3.1.0-1
- Initial SPEC file
#include <cstring>
#include <iostream>
#include <stdint.h>
#include <sass.h>
// gcc: g++ -shared plugin.cpp -o plugin.so -fPIC -Llib -lsass
// mingw: g++ -shared plugin.cpp -o plugin.dll -Llib -lsass
extern "C" const char* ADDCALL libsass_get_version() {
return libsass_version();
}
union Sass_Value* custom_function(const union Sass_Value* s_args, Sass_Function_Entry cb, struct Sass_Compiler* comp)
{
// get context/option struct associated with this compiler
struct Sass_Context* ctx = sass_compiler_get_context(comp);
struct Sass_Options* opts = sass_compiler_get_options(comp);
// get the cookie from function descriptor
void* cookie = sass_function_get_cookie(cb);
// we actually abuse the void* to store an "int"
return sass_make_number((intptr_t)cookie, "px");
}
extern "C" Sass_Function_List ADDCALL libsass_load_functions()
{
// allocate a custom function caller
Sass_Function_Entry c_func =
sass_make_function("foo()", custom_function, (void*)42);
// create list of all custom functions
Sass_Function_List fn_list = sass_make_function_list(1);
// put the only function in this plugin to the list
sass_function_set_list_entry(fn_list, 0, c_func);
// return the list
return fn_list;
}
Sass_Import_List custom_importer(const char* cur_path, Sass_Importer_Entry cb, struct Sass_Compiler* comp)
{
// get the cookie from importer descriptor
void* cookie = sass_importer_get_cookie(cb);
// create a list to hold our import entries
Sass_Import_List incs = sass_make_import_list(1);
// create our only import entry (route path back)
incs[0] = sass_make_import_entry(cur_path, 0, 0);
// return imports
return incs;
}
extern "C" Sass_Importer_List ADDCALL libsass_load_importers()
{
// allocate a custom function caller
Sass_Importer_Entry c_imp =
sass_make_importer(custom_importer, - 99, (void*)42);
// create list of all custom functions
Sass_Importer_List imp_list = sass_make_importer_list(1);
// put the only function in this plugin to the list
sass_importer_set_list_entry(imp_list, 0, c_imp);
// return the list
return imp_list;
}
Welcome to the LibSass documentation!
## First Off
LibSass is just a library. To run the code locally (i.e. to compile your stylesheets), you need an implementer. SassC (get it?) is an implementer written in C. There are a number of other implementations of LibSass - for example Node. We encourage you to write your own port - the whole point of LibSass is that we want to bring Sass to many other languages, not just Ruby!
We're working hard on moving to full parity with Ruby Sass... learn more at the [The-LibSass-Compatibility-Plan](compatibility-plan.md)!
### Implementing LibSass
If you're interested in implementing LibSass in your own project see the [API Documentation](api-doc.md) which now includes implementing
your own [Sass functions](api-function.md). You may wish to [look at other implementations](implementations.md) for your language of choice.
Or make your own!
### Contributing to LibSass
| Issue Tracker | Issue Triage | Community Guidelines |
|-------------------|----------------------------------|-----------------------------|
| We're always needing help, so check out our issue tracker, help some people out, and read our article on [Contributing](contributing.md)! It's got all the details on what to do! | To help understand the process of triaging bugs, have a look at our [Issue-Triage](triage.md) document. | Oh, and don't forget we always follow [[Sass Community Guidelines|http://sass-lang.com/community-guidelines]]. Be nice and everyone else will be nice too! |
Please refer to the steps on [Building LibSass](build.md)
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
require 'mkmf'
# .. more stuff
#$LIBPATH.push(Config::CONFIG['libdir'])
$CFLAGS << " #{ENV["CFLAGS"]}"
$LIBS << " #{ENV["LIBS"]}"
create_makefile("libsass")
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册