Merge branch 'rhino' of https://github.com/obecker/less.js into rhino

Conflicts:
	build/build.yml
This commit is contained in:
meri
2013-12-11 11:05:48 +01:00
16 changed files with 939 additions and 64 deletions

3
.gitattributes vendored
View File

@@ -3,7 +3,8 @@ lessc text eol=lf
*.less text eol=lf
*.css text eol=lf
*.htm text eol=lf
gradlew.bat text eol=crlf
*.jpg binary
*.png binary
*.jpeg binary
*.jpeg binary

4
.gitignore vendored
View File

@@ -18,3 +18,7 @@ test/sourcemaps/*.css
# grunt
.grunt
# gradle
.gradle
out

170
build.gradle Normal file
View File

@@ -0,0 +1,170 @@
import groovy.io.FileType
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.eriwen:gradle-js-plugin:1.8.0'
}
}
apply plugin: 'js'
repositories {
mavenCentral()
}
configurations {
rhino
}
dependencies {
rhino 'org.mozilla:rhino:1.7R4'
}
project.ext {
rhinoTestSrc = 'out/rhino-test.js'
testSrc = 'test/less'
testOut = 'out/test'
}
javascript.source {
test {
js {
srcDir '.'
include 'test/rhino/test-header.js'
include 'dist/less-rhino-1.5.0.js'
}
}
}
combineJs {
source = javascript.source.test.js.files
dest = file(rhinoTestSrc)
}
task testRhino {
dependsOn 'testRhinoBase', 'testRhinoErrors', 'testRhinoLegacy', 'testRhinoStaticUrls', 'testRhinoCompression'
}
task testRhinoBase(type: RhinoTest) {
options = [ '--strict-math=true', '--relative-urls' ]
}
task testRhinoErrors(type: RhinoTest) {
options = [ '--strict-math=true', '--strict-units=true' ]
testDir = 'errors/'
expectErrors = true
}
task testRhinoLegacy(type: RhinoTest) {
testDir = 'legacy/'
}
task testRhinoStaticUrls(type: RhinoTest) {
options = [ '--strict-math=true', '--rootpath=folder (1)/' ]
testDir = 'static-urls/'
}
task testRhinoCompression(type: RhinoTest) {
options = [ '--compress=true' ]
testDir = 'compression/'
}
task setupTest {
dependsOn combineJs
doLast {
file(testOut).deleteDir()
}
}
task clean << {
file(rhinoTestSrc).delete()
file(testOut).deleteDir()
}
class RhinoTest extends DefaultTask {
RhinoTest() {
dependsOn 'setupTest'
}
def testDir = ''
def options = []
def expectErrors = false
def stylize(str, style) {
def styles = [
reset : [0, 0],
bold : [1, 22],
inverse : [7, 27],
underline : [4, 24],
yellow : [33, 39],
green : [32, 39],
red : [31, 39],
grey : [90, 39]
];
return '\033[' + styles[style][0] + 'm' + str +
'\033[' + styles[style][1] + 'm';
}
@TaskAction
def runTest() {
int testSuccesses = 0, testFailures = 0, testErrors = 0
project.file('test/less/' + testDir).eachFileMatch(FileType.FILES, ~/.*\.less/) { lessFile ->
print lessFile
if (!project.hasProperty('test') || lessFile.name.startsWith(project.test)) {
def out = new java.io.ByteArrayOutputStream()
def execOptions = {
main = 'org.mozilla.javascript.tools.shell.Main'
// main = 'org.mozilla.javascript.tools.debugger.Main'
classpath = project.configurations.rhino
args = [project.rhinoTestSrc, lessFile] + options
standardOutput = out
ignoreExitValue = true
}
try {
def exec = project.javaexec(execOptions)
def actual = out.toString().trim()
def actualResult = project.file(lessFile.path.replace('test/less', project.testOut).replace('.less', '.css'))
project.file(actualResult.parent).mkdirs()
actualResult << actual
def expected
if (expectErrors) {
assert exec.exitValue != 0
expected = project.file(lessFile.path.replace('.less', '.txt')).text.trim().
replace('{path}', lessFile.parent + '/').
replace('{pathhref}', '').
replace('{404status}', '')
} else {
assert exec.exitValue == 0
expected = project.file(lessFile.path.replace('.less', '.css').replace('/less/', '/css/')).text.trim()
}
assert actual == expected
testSuccesses++
println stylize(' ok', 'green')
actualResult.delete()
}
catch (ex) {
println ex
println()
testErrors++;
}
catch (AssertionError ae) {
println stylize(' failed', 'red')
// println ae
testFailures++
}
} else {
println stylize(' skipped', 'yellow')
}
}
println stylize(testSuccesses + ' ok', 'green')
println stylize(testFailures + ' assertion failed', testFailures == 0 ? 'green' : 'red')
println stylize(testErrors + ' errors', testErrors == 0 ? 'green' : 'red')
// assert testFailures + testErrors == 0
}
}

View File

@@ -20,7 +20,7 @@ lib: lib/less
# =================================
prepend:
browser: ['build/require.js', 'build/browser-header.js']
rhino: ['build/require-rhino.js', 'build/rhino-header.js']
rhino: ['build/require-rhino.js', 'build/rhino-header.js', 'build/rhino-modules.js']
append:
amd: build/amd.js
@@ -89,16 +89,16 @@ rhino:
# core
- <%= build.less.parser %>
- <%= build.less.functions %>
- <%= build.less.colors %>
- <%= build.less.tree %>
- <%= build.less.treedir %> # glob all files
- <%= build.less.env %>
- <%= build.less.visitor %>
- <%= build.less.import_visitor %>
- <%= build.less.join %>
- <%= build.less.to_css_visitor %>
- <%= build.less.extend_visitor %>
- <%= build.less.functions %>
- <%= build.less.colors %>
- <%= build.less.tree %>
- <%= build.less.treedir %> # glob all files
- <%= build.less.source_map_output %>
# append rhino-specific code

View File

@@ -2,6 +2,11 @@
// Stub out `require` in rhino
//
function require(arg) {
return less[arg.split('/')[1]];
};
var split = arg.split('/');
var resultModule = split.length == 1 ? less.modules[split[0]] : less[split[1]];
if (!resultModule) {
throw { message: "Cannot find module '" + arg + "'"};
}
return resultModule;
}

View File

@@ -1,4 +1,4 @@
if (typeof(window) === 'undefined') { less = {} }
else { less = window.less = {} }
tree = less.tree = {};
less.mode = 'rhino';
less.mode = 'rhino';

128
build/rhino-modules.js Normal file
View File

@@ -0,0 +1,128 @@
(function() {
console = function() {
var stdout = java.lang.Systen.out;
var stderr = java.lang.System.err;
function doLog(out, type) {
return function() {
var args = java.lang.reflect.Array.newInstance(java.lang.Object, arguments.length - 1);
var format = arguments[0];
var conversionIndex = 0;
// need to look for %d (integer) conversions because in Javascript all numbers are doubles
for (var i = 1; i < arguments.length; i++) {
var arg = arguments[i];
if (conversionIndex != -1) {
conversionIndex = format.indexOf('%', conversionIndex);
}
if (conversionIndex >= 0 && conversionIndex < format.length) {
var conversion = format.charAt(conversionIndex + 1);
if (conversion === 'd' && typeof arg === 'number') {
arg = new java.lang.Integer(new java.lang.Double(arg).intValue());
}
conversionIndex++;
}
args[i-1] = arg;
}
try {
out.println(type + java.lang.String.format(format, args));
} catch(ex) {
stderr.println(ex);
}
}
}
return {
log: doLog(stdout, ''),
info: doLog(stdout, 'INFO: '),
error: doLog(stderr, 'ERROR: '),
warn: doLog(stderr, 'WARN: ')
};
}();
less.modules = {};
less.modules.path = {
join: function() {
var parts = [];
for (i in arguments) {
parts = parts.concat(arguments[i].split('/'));
}
var result = [];
for (i in parts) {
var part = parts[i];
if (part === '..' && result.length > 0) {
result.pop();
} else if (part === '' && result.length > 0) {
// skip
} else if (part !== '.') {
result.push(part);
}
}
return result.join('/');
},
dirname: function(p) {
var path = p.split('/');
path.pop();
return path.join('/');
},
basename: function(p, ext) {
var base = p.split('/').pop();
if (ext) {
var index = base.lastIndexOf(ext);
if (base.length === index + ext.length) {
base = base.substr(0, index);
}
}
return base;
},
extname: function(p) {
var index = p.lastIndexOf('.');
return index > 0 ? p.substring(index) : '';
}
};
less.modules.fs = {
readFileSync: function(name) {
// read a file into a byte array
var file = new java.io.File(name);
var stream = new java.io.FileInputStream(file);
var buffer = [];
var c;
while ((c = stream.read()) != -1) {
buffer.push(c);
}
stream.close();
return {
length: buffer.length,
toString: function(enc) {
if (enc === 'base64') {
return encodeBase64Bytes(buffer);
} else if (enc) {
return java.lang.String["(byte[],java.lang.String)"](buffer, enc);
} else {
return java.lang.String["(byte[])"](buffer);
}
}
};
}
};
less.encoder = {
encodeBase64: function(str) {
return encodeBase64String(str);
}
};
// ---------------------------------------------------------------------------------------------
// private helper functions
// ---------------------------------------------------------------------------------------------
function encodeBase64Bytes(bytes) {
// requires at least a JRE Platform 6 (or JAXB 1.0 on the classpath)
return javax.xml.bind.DatatypeConverter.printBase64Binary(bytes)
}
function encodeBase64String(str) {
return encodeBase64Bytes(new java.lang.String(str).getBytes());
}
})();

BIN
gradle/wrapper/gradle-wrapper.jar vendored Normal file

Binary file not shown.

View File

@@ -0,0 +1,6 @@
#Sun Oct 27 15:19:43 CET 2013
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=http\://services.gradle.org/distributions/gradle-1.8-bin.zip

164
gradlew vendored Executable file
View File

@@ -0,0 +1,164 @@
#!/usr/bin/env bash
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
echo "$*"
}
die ( ) {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
esac
# For Cygwin, ensure paths are in UNIX format before anything is touched.
if $cygwin ; then
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
fi
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >&-
APP_HOME="`pwd -P`"
cd "$SAVED" >&-
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"

90
gradlew.bat vendored Normal file
View File

@@ -0,0 +1,90 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windowz variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

4
lib/less/encoder.js Normal file
View File

@@ -0,0 +1,4 @@
// base64 encoder implementation for node
exports.encodeBase64 = function(str) {
return new Buffer(str).toString('base64');
};

View File

@@ -394,8 +394,8 @@ tree.functions = {
var mimetype = mimetypeNode.value;
var filePath = (filePathNode && filePathNode.value);
var fs = require("fs"),
path = require("path"),
var fs = require('fs'),
path = require('path'),
useBase64 = false;
if (arguments.length < 2) {
@@ -519,9 +519,8 @@ tree.functions = {
'<rect ' + rectangleDimension + ' fill="url(#gradient)" /></svg>';
if (useBase64) {
// only works in node, needs interface to what is supported in environment
try {
returner = new Buffer(returner).toString('base64');
returner = require('./encoder').encodeBase64(returner); // TODO browser implementation
} catch(e) {
useBase64 = false;
}

View File

@@ -1,34 +1,63 @@
/*jshint rhino:true, unused: false */
/*global name:true, less, loadStyleSheet */
var name;
function error(e, filename) {
if (typeof initRhinoTest === 'function') { // definition of additional test functions (see rhino/test-header.js)
initRhinoTest();
}
var content = "Error : " + filename + "\n";
function formatError(ctx, options) {
options = options || {};
filename = e.filename || filename;
var message = "";
var extract = ctx.extract;
var error = [];
// var stylize = options.color ? require('./lessc_helper').stylize : function (str) { return str; };
var stylize = function (str) { return str; };
if (e.message) {
content += e.message + "\n";
// only output a stack if it isn't a less error
if (ctx.stack && !ctx.type) { return stylize(ctx.stack, 'red'); }
if (!ctx.hasOwnProperty('index') || !extract) {
return ctx.stack || ctx.message;
}
var errorline = function (e, i, classname) {
if (e.extract[i]) {
content +=
String(parseInt(e.line, 10) + (i - 1)) +
":" + e.extract[i] + "\n";
if (typeof(extract[0]) === 'string') {
error.push(stylize((ctx.line - 1) + ' ' + extract[0], 'grey'));
}
if (typeof(extract[1]) === 'string') {
var errorTxt = ctx.line + ' ';
if (extract[1]) {
errorTxt += extract[1].slice(0, ctx.column) +
stylize(stylize(stylize(extract[1][ctx.column], 'bold') +
extract[1].slice(ctx.column + 1), 'red'), 'inverse');
}
};
if (e.stack) {
content += e.stack;
} else if (e.extract) {
content += 'on line ' + e.line + ', column ' + (e.column + 1) + ':\n';
errorline(e, 0);
errorline(e, 1);
errorline(e, 2);
error.push(errorTxt);
}
print(content);
if (typeof(extract[2]) === 'string') {
error.push(stylize((ctx.line + 1) + ' ' + extract[2], 'grey'));
}
error = error.join('\n') + stylize('', 'reset') + '\n';
message += stylize(ctx.type + 'Error: ' + ctx.message, 'red');
ctx.filename && (message += stylize(' in ', 'red') + ctx.filename +
stylize(' on line ' + ctx.line + ', column ' + (ctx.column + 1) + ':', 'grey'));
message += '\n' + error;
if (ctx.callLine) {
message += stylize('from ', 'red') + (ctx.filename || '') + '/n';
message += stylize(ctx.callLine, 'grey') + ' ' + ctx.callExtract + '/n';
}
return message;
}
function writeError(ctx, options) {
options = options || {};
if (options.silent) { return; }
print(formatError(ctx, options));
}
function loadStyleSheet(sheet, callback, reload, remaining) {
@@ -47,16 +76,65 @@ function loadStyleSheet(sheet, callback, reload, remaining) {
});
parser.parse(input, function (e, root) {
if (e) {
return error(e, sheetName);
return writeError(e);
}
try {
callback(e, root, input, sheet, { local: false, lastModified: 0, remaining: remaining }, sheetName);
} catch(e) {
error(e, sheetName);
writeError(e);
}
});
}
less.Parser.fileLoader = function (file, currentFileInfo, callback, env) {
var href = file;
if (currentFileInfo && currentFileInfo.currentDirectory && !/^\//.test(file)) {
href = less.modules.path.join(currentFileInfo.currentDirectory, file);
}
var path = less.modules.path.dirname(href);
var newFileInfo = {
currentDirectory: path + '/',
filename: href
};
if (currentFileInfo) {
newFileInfo.entryPath = currentFileInfo.entryPath;
newFileInfo.rootpath = currentFileInfo.rootpath;
newFileInfo.rootFilename = currentFileInfo.rootFilename;
newFileInfo.relativeUrls = currentFileInfo.relativeUrls;
} else {
newFileInfo.entryPath = path;
newFileInfo.rootpath = less.rootpath || path;
newFileInfo.rootFilename = href;
newFileInfo.relativeUrls = env.relativeUrls;
}
var j = file.lastIndexOf('/');
if(newFileInfo.relativeUrls && !/^(?:[a-z-]+:|\/)/.test(file) && j != -1) {
var relativeSubDirectory = file.slice(0, j+1);
newFileInfo.rootpath = newFileInfo.rootpath + relativeSubDirectory; // append (sub|sup) directory path of imported file
}
newFileInfo.currentDirectory = path;
newFileInfo.filename = href;
try {
var data = readFile(href);
} catch (e) {
callback({ type: 'File', message: "'" + less.modules.path.basename(href) + "' wasn't found" });
return;
}
try {
callback(null, data, href, newFileInfo, { lastModified: 0 });
} catch (e) {
callback(e, null, href);
}
};
function writeFile(filename, content) {
var fstream = new java.io.FileWriter(filename);
var out = new java.io.BufferedWriter(fstream);
@@ -66,53 +144,266 @@ function writeFile(filename, content) {
// Command line integration via Rhino
(function (args) {
var output,
compress = false,
i,
path;
for(i = 0; i < args.length; i++) {
switch(args[i]) {
case "-x":
compress = true;
var options = {
depends: false,
compress: false,
cleancss: false,
max_line_len: -1,
optimization: 1,
silent: false,
verbose: false,
lint: false,
paths: [],
color: true,
strictImports: false,
rootpath: '',
relativeUrls: false,
ieCompat: true,
strictMath: false,
strictUnits: false
};
var continueProcessing = true,
currentErrorcode;
var checkArgFunc = function(arg, option) {
if (!option) {
print(arg + " option requires a parameter");
continueProcessing = false;
return false;
}
return true;
};
var checkBooleanArg = function(arg) {
var onOff = /^((on|t|true|y|yes)|(off|f|false|n|no))$/i.exec(arg);
if (!onOff) {
print(" unable to parse "+arg+" as a boolean. use one of on/t/true/y/yes/off/f/false/n/no");
continueProcessing = false;
return false;
}
return Boolean(onOff[2]);
};
var warningMessages = "";
args = args.filter(function (arg) {
var match;
if (match = arg.match(/^-I(.+)$/)) {
options.paths.push(match[1]);
return false;
}
if (match = arg.match(/^--?([a-z][0-9a-z-]*)(?:=(.*))?$/i)) { arg = match[1]; } // was (?:=([^\s]*)), check!
else { return arg; }
switch (arg) {
case 'v':
case 'version':
console.log("lessc " + less.version.join('.') + " (LESS Compiler) [JavaScript]");
continueProcessing = false;
break;
case 'verbose':
options.verbose = true;
break;
case 's':
case 'silent':
options.silent = true;
break;
case 'l':
case 'lint':
options.lint = true;
break;
case 'strict-imports':
options.strictImports = true;
break;
case 'h':
case 'help':
//TODO
// require('../lib/less/lessc_helper').printUsage();
continueProcessing = false;
break;
case 'x':
case 'compress':
options.compress = true;
break;
case 'M':
case 'depends':
options.depends = true;
break;
case 'yui-compress':
warningMessages += "yui-compress option has been removed. assuming clean-css.";
options.cleancss = true;
break;
case 'clean-css':
options.cleancss = true;
break;
case 'max-line-len':
if (checkArgFunc(arg, match[2])) {
options.maxLineLen = parseInt(match[2], 10);
if (options.maxLineLen <= 0) {
options.maxLineLen = -1;
}
}
break;
case 'no-color':
options.color = false;
break;
case 'no-ie-compat':
options.ieCompat = false;
break;
case 'no-js':
options.javascriptEnabled = false;
break;
case 'include-path':
if (checkArgFunc(arg, match[2])) {
options.paths = match[2].split(os.type().match(/Windows/) ? ';' : ':')
.map(function(p) {
if (p) {
// return path.resolve(process.cwd(), p);
return p;
}
});
}
break;
case 'O0': options.optimization = 0; break;
case 'O1': options.optimization = 1; break;
case 'O2': options.optimization = 2; break;
case 'line-numbers':
if (checkArgFunc(arg, match[2])) {
options.dumpLineNumbers = match[2];
}
break;
case 'source-map':
if (!match[2]) {
options.sourceMap = true;
} else {
options.sourceMap = match[2];
}
break;
case 'source-map-rootpath':
if (checkArgFunc(arg, match[2])) {
options.sourceMapRootpath = match[2];
}
break;
case 'source-map-inline':
options.outputSourceFiles = true;
break;
case 'rp':
case 'rootpath':
if (checkArgFunc(arg, match[2])) {
options.rootpath = match[2].replace(/\\/g, '/');
}
break;
case "ru":
case "relative-urls":
options.relativeUrls = true;
break;
case "sm":
case "strict-math":
if (checkArgFunc(arg, match[2])) {
options.strictMath = checkBooleanArg(match[2]);
}
break;
case "su":
case "strict-units":
if (checkArgFunc(arg, match[2])) {
options.strictUnits = checkBooleanArg(match[2]);
}
break;
default:
if (!name) {
name = args[i];
} else if (!output) {
output = args[i];
} else {
print("unrecognised parameters");
print("input_file [output_file] [-x]");
}
console.log('invalid option ' + arg);
continueProcessing = false;
}
});
if (!continueProcessing) {
return;
}
var name = args[0];
if (name && name != '-') {
// name = path.resolve(process.cwd(), name);
}
var output = args[1];
var outputbase = args[1];
if (output) {
options.sourceMapOutputFilename = output;
// output = path.resolve(process.cwd(), output);
if (warningMessages) {
console.log(warningMessages);
}
}
// options.sourceMapBasepath = process.cwd();
options.sourceMapBasepath = '';
if (options.sourceMap === true) {
if (!output) {
console.log("the sourcemap option only has an optional filename if the css filename is given");
return;
}
options.sourceMapFullFilename = options.sourceMapOutputFilename + ".map";
options.sourceMap = less.modules.path.basename(options.sourceMapFullFilename);
}
if (!name) {
print('No files present in the fileset; Check your pattern match in build.xml');
console.log("lessc: no inout files");
console.log("");
// TODO
// require('../lib/less/lessc_helper').printUsage();
currentErrorcode = 1;
return;
}
// var ensureDirectory = function (filepath) {
// var dir = path.dirname(filepath),
// cmd,
// existsSync = fs.existsSync || path.existsSync;
// if (!existsSync(dir)) {
// if (mkdirp === undefined) {
// try {mkdirp = require('mkdirp');}
// catch(e) { mkdirp = null; }
// }
// cmd = mkdirp && mkdirp.sync || fs.mkdirSync;
// cmd(dir);
// }
// };
if (options.depends) {
if (!outputbase) {
console.log("option --depends requires an output path to be specified");
return;
}
console.log(outputbase + ": ");
}
if (!name) {
console.log('No files present in the fileset');
quit(1);
}
path = name.split("/");path.pop();path=path.join("/");
var input = readFile(name);
if (!input) {
print('lesscss: couldn\'t open file ' + name);
console.log('lesscss: couldn\'t open file ' + name);
quit(1);
}
options.filename = name;
var result;
try {
var parser = new less.Parser();
var parser = new less.Parser(options);
parser.parse(input, function (e, root) {
if (e) {
error(e, name);
writeError(e, options);
quit(1);
} else {
result = root.toCSS({compress: compress || false});
result = root.toCSS(options);
if (output) {
writeFile(output, result);
print("Written to " + output);
console.log("Written to " + output);
} else {
print(result);
}
@@ -121,8 +412,8 @@ function writeFile(filename, content) {
});
}
catch(e) {
error(e, name);
writeError(e, options);
quit(1);
}
print("done");
}(arguments));
console.log("done");
}(arguments));

View File

@@ -36,7 +36,7 @@ tree.JavaScript.prototype = {
try {
result = expression.call(context);
} catch (e) {
throw { message: "JavaScript evaluation error: '" + e.name + ': ' + e.message + "'" ,
throw { message: "JavaScript evaluation error: '" + e.name + ': ' + e.message.replace(/["]/g, "'") + "'" ,
index: this.index };
}
if (typeof(result) === 'string') {

13
test/rhino/test-header.js Normal file
View File

@@ -0,0 +1,13 @@
function initRhinoTest() {
process = { title: 'dummy' };
less.tree.functions.add = function (a, b) {
return new(less.tree.Dimension)(a.value + b.value);
};
less.tree.functions.increment = function (a) {
return new(less.tree.Dimension)(a.value + 1);
};
less.tree.functions._color = function (str) {
if (str.value === "evil red") { return new(less.tree.Color)("600"); }
};
}