@extjs/sencha-cmd-linux-32
Version:
Productivity and performance optimization tool for building applications with Sencha Ext JS and Sencha Touch.
1,583 lines (1,394 loc) • 50.5 kB
JavaScript
"use strict";
var Fashion = require('./export/Base.js');
var Visitor = require('./Visitor.js');
var Preprocessor = require('./Preprocessor.js');
var Output = require('./export/Output.js');
var Parser = require('./parse/Parser.js');
var Scanner = require('./parse/Scanner.js');
var Color = require('./export/type/Color.js');
var Runtime = require('./Runtime.js');
var Nodes = require('./parse/ast/Nodes.js'),
List = Nodes.List,
SelectorList = Nodes.SelectorList,
Constant = Nodes.Constant,
FunctionCall = Nodes.FunctionCall,
Variable = Nodes.Variable,
VariableAssignment = Nodes.VariableAssignment;
class StringCache {
constructor() {
this.array = [];
this.map = {};
}
addString(string) {
var idx = this.map[string];
if (typeof idx === 'undefined') {
idx = this.array.length;
this.array.push(string);
this.map[string] = idx;
}
return idx;
}
get(id) {
return this.array[id];
}
}
class ObjCache {
constructor() {
this.array = [];
}
addObj(obj) {
var idx = this.array.length;
this.array.push(obj);
return idx;
}
get(id) {
return this.array[id];
}
}
class Transpiler extends Visitor {
reset() {
this.output = new Output();
this.currentScope = {
__suffix: '',
__isGlobal: true
};
this.globalScope = this.currentScope;
this.globalVars = {};
this.errors = 0;
this.warnings = 0;
this.stringCache = new StringCache();
this.docCache = new ObjCache();
this.nodeCache = new ObjCache();
}
createScope(parent) {
parent = parent || this.currentScope;
var scope = Fashion.chain(parent);
scope.__suffix = scope.__suffix + '$';
return scope;
}
getScopeName(name, scope) {
//scope = scope || this.currentScope;
//
//if(scope.hasOwnProperty(name)) {
// return scope[name];
//}
return Fashion.getJsName(name);
}
getVariableName(node) {
return node.variable || node.name || node.value || node;
}
handleInlineExpression(expr) {
try {
var outwas = this.output,
output = new Output(),
parser = this.inlineParser || (this.inlineParser = new Parser()),
tree;
if (this.isSelector) {
parser.scanner = new Scanner(expr);
tree = parser.parseSequence();
} else {
tree = parser.parse('$foobar: ' + expr + ';');
tree = tree[0].value;
}
this.output = output;
this.handleStatement(tree);
this.output = outwas;
return output.get().trim();
} catch (error) {
Fashion.log("failed to evaluate inline expression : " + expr);
throw error;
}
}
handleInlineExpressions(text, start, skipEscape) {
text = text + '';
start = start || 0;
var out = [],
level = 0,
outwas, i, ch, ch2;
outer: for (i = start; i < text.length; i++) {
ch = text.charAt(i);
ch2 = (i < text.length - 1)
? text.charAt(i + 1)
: undefined;
switch (ch) {
case '\\':
if (!outwas && !skipEscape) {
out.push('\\\\');
} else {
out.push(ch);
}
break;
case '"':
if (!outwas && !skipEscape) {
out.push('\\"');
} else {
out.push(ch);
}
break;
case '#':
if (ch2 === '{') {
level++;
if (level < 2) {
outwas = out;
out = [];
i++;
} else {
out.push(ch);
}
} else {
out.push(ch);
}
break;
case '}':
level--;
if (!level) {
outwas.push('" + __rt_unquote(');
outwas.push(this.handleInlineExpression(out.join('')));
outwas.push(') + "');
out = outwas;
outwas = undefined;
} else {
out.push(ch);
}
break;
default:
out.push(ch);
break
}
}
return out.join('');
}
addSourceInfo(item) {
if (!this.symbols) {
return;
}
item = item || this.nodeStack[this.nodeStack.length - 1];
if (item && (item.lineNumber || item.file)) {
this.output.add("__rt_pushSourceInfo([" +
"" + item.lineNumber +
", '" + (item.file || "source-code") + "'])");
this.output.add(';');
}
}
createCallStackScope() {
if (!this.symbols) {
return;
}
this.output.addln("__rt_createCallStackScope();");
}
popCallStackScope() {
if (!this.symbols) {
return;
}
this.output.addln("__rt_popCallStackScope();");
}
handleStatements(statements) {
if (this.symbols) {
this.addSourceInfo();
}
this.visit(statements);
}
handleStatement(statement) {
if (statement && statement.hasOwnProperty('visitTarget')) {
statement = statement.visitTarget;
if (statement && Array.isArray(statement)) {
this.handleStatements(statement);
}
}
if (statement) {
if (statement instanceof Array) {
statement = new List(null, statement, ',');
}
this.visit(statement);
}
}
createDefaultScopeMap(args, isMixin) {
args = this.loadArgsArray(args);
var output = this.output,
defaulted = 0,
arg, a, varName, jsName, name;
this.isSignatureDeclaration = true;
this.generateGets = true;
for (a = 0; a < args.length; a++) {
arg = args[a];
if (arg) {
varName = (arg.variable || arg.name);
name = varName;
jsName = this.getScopeName(varName);
this.currentScope[jsName] = {
name: jsName,
param: true
};
varName = jsName;
if (arg.varArgs) {
output.addln(varName + ' = __rt_sliceArgs(arguments, ' +
(isMixin ? a + 1 : a) +
');');
defaulted++;
} else if (arg.type !== 'Variable' || arg.variable !== undefined) {
output.addln('var ' + varName + ' = ' + varName + ' || ');
this.handleStatement(arg);
output.add(';');
defaulted++;
} else {
output.addln('var ' + varName + ' = ' + varName + ' || __Null;');
}
output.addln('__rt_set("' + jsName + '", ' + varName + ', true);');
}
}
this.generateGets = false;
this.isSignatureDeclaration = false;
return defaulted;
}
getRegisteredDeclarationsMap(declaredParameters) {
var map = {}, param;
for (var d = 0; d < declaredParameters.length; d++) {
param = declaredParameters[d];
map[param.name] = param;
}
return map;
}
createCallArray(args, defaults, id, convertName, addComma) {
args = this.loadArgsArray(args);
if (defaults.parameters) {
defaults = defaults.parameters;
}
var me = this,
output = me.output,
len = args.length > defaults.length ? args.length : defaults.length,
declaredMap = me.getRegisteredDeclarationsMap(defaults),
actual = new Array(len),
arg, a, position;
for (var a = 0; a < args.length; a++) {
arg = args[a];
position = a;
if (arg && arg.variable) {
var argName = arg.variable;
if (convertName) {
if (argName.indexOf("$") == 0) {
argName = argName.substr(1);
}
argName = argName.replace(/\-/g, '_');
}
if (!declaredMap[argName]) {
var params = [];
for (var pName in declaredMap) {
params.push(pName);
}
Fashion.warn("function or mixin '" + id + "' had no parameter named " + argName + " : params were : " + params.join(", "));
// if a named parameter didn't match a parameter from the
// call signature, skip it and let the default value be used
continue;
} else {
position = declaredMap[argName].position;
}
}
actual[position] = arg;
}
for (a = 0; a < actual.length; a++) {
arg = actual[a];
if (addComma || (a > 0)) {
output.add(',');
output.space();
}
if (arg) {
output.addln();
if (arg.varArgs) {
output.add('__rt_applySpread(');
me.handleStatement(arg);
output.add(')');
} else {
me.handleStatement(arg);
}
} else {
output.addln("__udf");
}
}
return actual.length;
}
escapeString(str) {
return str && str.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
}
//<editor-fold desc="visitor methods">
Each(statement) {
if (statement.isMap) {
var me = this,
output = me.output,
arg = statement.variable,
names = statement.variable.items;
me.eachCount = me.eachCount || 1;
var jsNames = Fashion.convert(names, (name) => me.getScopeName(name)),
jsItrName = '__each_itr_' + me.eachCount,
jsListName = '__each__list';
names.forEach((name, i) => this.currentScope[jsNames[i]] = jsNames[i]);
output.addln("var " + jsListName + " = ");
me.handleStatement(statement.list);
output.add(";");
output.addln("for(var " + jsItrName + " = 0; " + jsItrName + " < " + jsListName + ".items.length - 1; " + jsItrName + "+=2) {");
output.indent();
output.addln('__rt_set("' + jsNames[0] + '", ' + jsListName + ".items[" + jsItrName + "]);");
output.addln('__rt_set("' + jsNames[1] + '", ' + jsListName + ".items[" + jsItrName + " + 1]);");
me.handleStatements(statement.statements);
output.unindentln("}");
} else {
var me = this,
output = me.output,
arg = statement.variable,
name = me.getVariableName(arg),
jsName = me.getScopeName(name),
jsListName = jsName + "__list",
jsItrName = jsName + "__itr";
this.currentScope[jsItrName] = jsItrName;
this.currentScope[jsListName] = jsListName;
this.currentScope[jsName] = jsName;
output.addln("var " + jsListName + " = ");
me.handleStatement(statement.list);
output.add(";");
output.addln("for(var " + jsItrName + " = 0; " + jsItrName + " < " + jsListName + ".items.length; " + jsItrName + "++) {");
output.indent();
output.addln('__rt_set("' + jsName + '", ' + jsListName + ".items[" + jsItrName + "]);");
me.handleStatements(statement.statements);
output.unindentln("}");
}
return false;
}
For(statement) {
var me = this,
output = me.output,
arg = statement.variable,
name = me.getVariableName(arg),
jsName = me.getScopeName(name),
jsItrName = jsName + "__itr";
this.currentScope[jsName] = jsName;
output.addln('for(var ' + jsItrName + ' = __rt_unbox(');
me.handleStatement(statement.start);
output.add('), end = (__rt_unbox(');
me.handleStatement(statement.end);
output.add(')');
if (!!statement.inclusive) {
output.add(' + 1');
}
output.add('); ' + jsItrName + ' < end; '+ jsItrName + '++){');
output.indent();
output.addln('var ' + jsName + ' = ' + jsItrName);
output.addln('__rt_set("' + jsName + '", ' + jsItrName + ', true);');
me.handleStatements(statement.statements);
output.unindentln('};');
return false;
}
While(statement) {
var output = this.output;
output.addln("while(__rt_unbox(");
this.handleStatement(statement.condition);
output.add(")) {");
output.indent();
this.handleStatements(statement.statements);
output.unindentln("};");
return false;
}
Function(statement) {
var me = this,
output = me.output,
func = statement.func,
jsName = Fashion.getJsName(func.id || func.value);
if (jsName === 'dynamic') {
me.error("Cannot define function named 'dynamic'", statement);
}
if (jsName === 'require') {
me.error("Cannot define function named 'require'", statement);
}
me.nestedDocs = true;
var scopeWas = me.currentScope;
me.currentScope = me.createScope();
output.addln('function ' + jsName + '__fn(');
var args = me.loadArgsArray(func.args || []);
for (var i = 0; i < args.length; i++) {
var arg = args[i];
var varName = (arg.variable || arg.name);
varName = me.getScopeName(varName);
if (i > 0) {
output.add(',');
output.space();
}
output.add(varName);
}
output.add(') {');
output.indent();
// load the defaults
output.addln('__rt_createScope(__rt_functions.' + jsName + ' && __rt_functions.' + jsName + '.createdScope);');
if (this.symbols) {
me.createCallStackScope();
}
if (this.symbols) {
this.addSourceInfo();
}
me.createDefaultScopeMap(func.args);
this.popScope = true;
// Handle all the statements within this function
if (statement.statements.length) {
me.handleStatements(statement.statements);
}
me.currentScope = scopeWas;
if (this.popScope) {
if (this.symbols) {
me.popCallStackScope();
}
output.addln("__rt_popScope();");
this.popScope = false;
}
output.unindentln('};');
output.addln('__rt_functions.' + jsName + ' = ' + jsName + '__fn;');
output.addln('__rt_functions.' + jsName + '.createdScope = __rt_getCurrentScope();');
me.nestedDocs = false;
return false;
}
Ruleset(statement, fnName) {
fnName = fnName || '__rt_ruleset';
var me = this,
output = me.output,
isGlobal = me.nodeStack.length === 1,
newScope = false,
docIdx = -1,
blockDocIdx = -1,
hasBlock = !!statement.statements;
output.addln(fnName + '(');
this.isSelector = statement.selectors;
this.handleStatement(statement.selectors);
this.isSelector = null;
if (statement.file) {
var fileIdx = this.stringCache.addString(statement.file);
output.add(",__rt_getString(" + fileIdx + ") + \":" + statement.lineNumber + "\"");
} else {
output.add(', null');
}
if (statement.docs && statement.docs.length) {
docIdx = this.docCache.addObj(statement.docs);
output.add(',__rt_getDocs(' + docIdx + ')');
} else {
output.add(', null');
}
if (statement.blockDocs && statement.blockDocs.length) {
blockDocIdx = this.docCache.addObj(statement.blockDocs);
output.add(',__rt_getDocs(' + blockDocIdx + ')');
} else {
output.add(', null');
}
output.add(', ' + hasBlock);
output.add(");");
if (isGlobal && Runtime.uniqueScopesForGlobalRulesets) {
newScope = true;
}
if (Runtime.uniqueScopesForAllRulesets) {
newScope = true;
}
if (newScope) {
var scopeWas = me.currentScope;
me.currentScope = me.createScope();
output.addln("__rt_createScope();")
me.handleStatements(statement.statements);
output.addln("__rt_popScope();")
me.currentScope = scopeWas;
} else {
me.handleStatements(statement.statements);
}
output.addln("__rt_rulesetDone();");
me.nestedDocs = false;
}
Mixin(statement) {
var me = this,
output = me.output,
name = statement.name,
jsName = Fashion.getJsName(name.id || name.value),
args, arg, varName, scopeWas, i;
me.nestedDocs = true;
me.processingMixin = true;
scopeWas = me.currentScope;
me.currentScope = me.createScope();
output.addln('__rt.mixins.' + jsName + '= function(');
args = me.loadArgsArray(name.args || []);
output.add('$$content');
for (i = 0; i < args.length; i++) {
arg = args[i];
varName = (arg.variable || arg.name);
varName = me.getScopeName(varName);
output.add(',');
output.space();
output.add(varName);
}
output.add(') {');
output.indent();
// load the defaults
output.addln('__rt_createScope(__rt.mixins.' + jsName + ' && __rt.mixins.' + jsName + '.createdScope);');
if (this.symbols) {
me.createCallStackScope();
}
if (this.symbols) {
this.addSourceInfo();
}
me.createDefaultScopeMap(name.args, true);
me.handleStatements(statement.statements);
me.currentScope = scopeWas;
if (this.symbols) {
me.popCallStackScope();
}
output.addln("__rt_popScope();")
output.unindentln('};');
output.addln('__rt.mixins.' + jsName + '.createdScope = __rt_getCurrentScope();');
me.nestedDocs = false;
me.processingMixin = false;
return false;
}
Content(statement) {
if (!this.processingMixin) {
this.error("@content may only be used within a mixin declaration");
}
this.output.addln("$$content && $$content();");
return false;
}
Include(statement) {
var me = this,
output = me.output,
include = statement.include,
id = include.id || include.value,
jsId = Fashion.getJsName(id),
args = me.loadArgsArray(include.args || []);
if (this.symbols) {
me.addSourceInfo();
output.add(';');
output.addln();
}
if (jsId == "fashion_defer_content") {
output.addln("__rt.defer(");
if (args[0]) {
output.add("__rt.unbox(");
me.handleStatement(args[0]);
output.add(")");
}
else {
output.add("null");
}
output.add(", ");
output.addln('(function(scope) { return function(){');
output.indent();
output.addln("__rt_createScope(scope);");
if (this.symbols) {
me.createCallStackScope();
}
me.handleStatements(statement.content.statements);
if (this.symbols) {
me.popCallStackScope();
}
output.addln("__rt_popScope();");
output.unindent();
output.addln("}})(__rt_getCurrentScope())");
output.add(");");
}
else if (jsId == 'fashion_inject_content') {
output.addln("__rt.runDeferred(");
if (args[0]) {
output.add("__rt.unbox(");
me.handleStatement(args[0]);
output.add(")");
}
output.add(");");
}
else if (!me.mixinDeclarations[jsId]) {
me.error("unknown definition for mixin named " + id + " : " + statement.file + ":" + statement.lineNumber);
} else {
output.addln('(__rt.mixins.' + jsId + ' || ' + jsId + '__mix).apply(__rt.mixins, __rt_applySpreadArgs([');
output.indent();
if (statement.content) {
output.addln('(function(scope) { return function(){');
output.indent();
output.addln("__rt_createScope(scope);");
if (this.symbols) {
me.createCallStackScope();
}
if (this.symbols) {
this.addSourceInfo();
}
me.handleStatements(statement.content.statements);
if (this.symbols) {
me.popCallStackScope();
}
output.addln("__rt_popScope();");
output.unindent();
output.addln("}})(__rt_getCurrentScope())");
} else {
output.add('__udf');
}
me.createCallArray(args, me.mixinDeclarations[jsId], id, false, true);
output.unindent();
output.add('], "' + jsId + '"));');
}
return false;
}
Declaration(statement) {
var me = this,
output = me.output,
namespacedRulesets = [],
props = [],
separator = ' ',
docIdx = -1,
val = statement.value,
i, nsRuleset;
if (val.type === 'List') {
separator = val.separator;
val = val.items;
} else if (!Array.isArray(val)) {
val = [val]
}
for (i = 0; i < val.length; i++) {
var prop = val[i];
if (prop.type !== 'Ruleset') {
props.push(prop);
} else {
namespacedRulesets.push(prop);
}
}
if (props.length) {
if (this.symbols) {
this.addSourceInfo();
}
output.addln('__rt_declare("' + me.handleInlineExpressions(statement.property) + '", ');
if (statement.property === 'font') {
me.isFontDecl = statement;
}
me.handleStatement(new List(null, props, separator));
output.add(',');
output.space();
output.add(!!statement.important + '');
if (statement.file) {
var fileIdx = this.stringCache.addString(statement.file);
output.add(",__rt_getString(" + fileIdx + ") + \":" + statement.lineNumber + "\"");
} else {
output.add(', null');
}
if (statement.docs && statement.docs.length) {
docIdx = this.docCache.addObj(statement.docs);
output.add(',__rt_getDocs(' + docIdx + ')');
} else {
output.add(', null');
}
output.add(');');
}
if (namespacedRulesets.length) {
for (i = 0; i < namespacedRulesets.length; i++) {
nsRuleset = namespacedRulesets[i];
nsRuleset.selectors = new SelectorList({
items: [new Constant({
dataType: 'Literal',
value: statement.property
})],
separator: ', '
});
me.Ruleset(nsRuleset, '__rt_namespacedRuleset');
delete nsRuleset.selectors;
}
}
me.isFontDecl = undefined;
return false;
}
VariableAssignment(statement) {
var me = this,
output = me.output,
name = statement.name,
bangGlobal = !!statement.global ? 1 : 0,
bangDynamic = !!statement.dynamic ? 1 : 0,
bangDefault = !!statement.default ? 1 : 0,
isGlobalVar = me.nodeStack.length === 1 ? 1 : 0,
jsName = me.getScopeName(name),
exists = me.currentScope[jsName],
createLocal = (!isGlobalVar && (!exists || !exists.param)) ? 1 : 0,
variable = me.dynamicVariables[jsName],
failDynamicAssignment = false,
processed = me.processedVariables,
isDynamic = false,
replaceMap = this.preprocessor.replacesMap;
if (this.symbols) {
this.addSourceInfo();
}
if (bangDynamic && !isGlobalVar) {
failDynamicAssignment = true;
}
if (!bangDynamic && variable && !isGlobalVar && (me.currentScope === me.globalScope)) {
// cannot reassign dynamic vars inside control logic
failDynamicAssignment = true;
}
if (bangGlobal && !bangDynamic && !isGlobalVar && variable) {
// cannot reassign dynamic vars inside control logic using !global
failDynamicAssignment = true;
}
if (failDynamicAssignment) {
this.error(["Dynamic variable ",
name,
" can only be assigned at file scope "
].join(''));
Fashion.error(' at ', statement);
var v = variable;
while (v && v.elevationCause) {
Fashion.error([
'\t',
v.name,
' elevated by ',
v.elevationCause.name,
' at '
].join(''),
v.elevationCause.getNode());
v = v.elevationCause;
}
}
if (isGlobalVar && variable && processed[jsName]) {
return false;
}
if (variable) {
if (!exists || (!exists.param && bangGlobal)) {
isDynamic = true;
}
}
if (exists) {
if (bangGlobal) {
createLocal = 0;
}
else if (!variable && Runtime.allowSetScopedVariables) {
// do not allow re-assingments of dynamic variables
// from a non-global scope
createLocal = 0;
}
} else if (bangGlobal) {
createLocal = 0;
}
if (createLocal) {
me.currentScope[jsName] = {
name: jsName
};
} else if (bangGlobal) {
jsName = me.getScopeName(name, me.globalScope);
}
if (isGlobalVar) {
me.globalScope[jsName] = jsName;
}
var setArgs = [];
if (isDynamic) {
output.addln('__rt_setDynamic("' + name + '", ');
output.add('__rt_getGlobalDefault("' + jsName + '") || ');
var idx = this.nodeCache.addObj(statement.value);
setArgs.push(idx);
}
else if (bangGlobal) {
output.addln('__rt_setGlobal("' + jsName + '", ');
if (bangDefault) {
output.add('__rt_getGlobalDefault("' + jsName + '") || ');
}
var idx = this.nodeCache.addObj(statement.value);
setArgs.push(idx);
}
else if (createLocal) {
output.addln('__rt_set("' + jsName + '", ');
if (bangDefault) {
output.add('__rt_getLocalDefault("' + jsName + '") || ');
}
}
else {
output.addln('__rt_setScoped("' + jsName + '", ');
if (bangDefault) {
output.add('__rt_getLocalDefault("' + jsName + '") || ');
}
}
me.handleStatement(statement.value);
if (setArgs.length) {
output.add(', ' + setArgs.join(', '));
}
output.add(');');
if (variable) {
processed[jsName] = true;
}
if (variable && variable.replaces) {
var assignment = new VariableAssignment(null, variable.replaces, new Variable(null, name));
assignment.deprecatedAssignment = true;
me.nodeStack.pop();
me.handleStatement(assignment);
me.nodeStack.push(statement);
}
return false;
}
If(statement) {
var output = this.output;
output.addln('if(__rt_unbox(');
this.handleStatement(statement.condition);
output.add(')) {');
output.indent();
this.handleStatements(statement.statements);
output.unindentln('}');
return false;
}
Else(statement) {
var output = this.output;
if (statement.condition) {
output.addln('else if(__rt_unbox(');
this.handleStatement(statement.condition);
output.add(')) {');
output.indent();
}
else {
output.indentln('else {');
}
this.handleStatements(statement.statements);
output.unindentln('}');
return false;
}
Return(statement) {
var isFunc = false,
stack = this.nodeStack;
for (var i = stack.length - 1; i >= 0; i--) {
if (stack[i].type == 'Function') {
isFunc = true;
break;
}
}
if (isFunc) {
this.popScope = false;
this.output.addln('var $$$r = ');
this.handleStatement(statement.expr);
this.output.add(';');
if (this.symbols) {
this.popCallStackScope();
}
this.output.addln("__rt_popScope();");
this.output.addln('return $$$r;')
} else {
Fashion.warn('Ingnored @return => ', statement);
}
return false;
}
BinaryExpression(statement) {
var me = this,
output = me.output,
suffix = '';
if ((statement.operator == '-' || statement.operator == '+') && statement.left === undefined) {
statement.left = new Constant({
dataType: 'Number',
value: 0
});
}
var divider = ', ',
prefix = '__rt';
switch (statement.operator) {
case '+':
case '-':
case '*':
case '%':
case '**':
case '==':
case '!=':
case '>':
case '<':
case '>=':
case '<=':
divider = '.operate("' + statement.operator + '",';
// output.add('__rt_operate("' + statement.operator + '", ');
break;
case 'and':
output.add('__rt_and(');
divider = '';
prefix = '';
break;
case 'or':
output.add('__rt_or(');
divider = '';
prefix = '';
break;
case '/':
var doOperator = true,
isDeclaration = false,
isParenthetical = false,
isFunctionCall = false,
stack = this.nodeStack,
parent;
for (var p = stack.length - 1; p >= 0; p--) {
parent = stack[p];
switch (parent.type) {
case 'Declaration':
isDeclaration = true;
break;
case 'ParentheticalExpression':
isParenthetical = true;
break;
case 'FunctionCall':
isFunctionCall = true;
default:
break;
}
}
doOperator = (!isDeclaration || !me.isFontDecl || isParenthetical || isFunctionCall);
if (!doOperator) {
output.add('new __Literal(');
me.handleStatement(statement.left);
output.add(' + "/" + ');
me.handleStatement(statement.right);
output.add(')');
return false;
} else {
divider = '.operate("' + statement.operator + '",';
// output.add('__rt_operate("' + statement.operator + '", ');
}
break;
default:
Fashion.log('Unrecognized binary expression operator: ' + statement.operator);
break;
}
output.add(prefix);
output.add(divider);
me.handleStatement(statement.left);
output.add(", ");
me.handleStatement(statement.right);
output.add(')');
output.add(suffix);
return false;
}
UnaryExpression(statement) {
var output = this.output;
switch (statement.operator) {
case 'not':
output.add('__rt_not(');
this.handleStatement(statement.expr);
output.add(')');
break;
default:
Fashion.log('Unrecognized unary expression operator ' + statement.operator);
}
return false;
}
Variable(statement) {
var name = statement.name,
jsName = this.getScopeName(name);
if (name == "$__filename") {
this.output.add('new __Text("' + statement.file + '")');
return;
}
else if (name == "$__dirname") {
var fileName = statement.file.replace("\\", '/');
var dirName = fileName.indexOf('/') > -1
? statement.file.substring(0, fileName.lastIndexOf('/'))
: statement.file;
this.output.add('new __Text("' + dirName + '")');
return;
}
if (!this.skipWarning && !(jsName in this.currentScope) && !(jsName in this.variables)) {
this.warn([
"Reference to undeclared variable ",
name,
" => ",
statement.file,
":",
statement.lineNumber
].join(''));
}
this.output.add('__rt_get("' + jsName + '")');
return false;
}
Constant(statement) {
var me = this,
output = me.output,
value = statement.value, regex;
if (statement.jsonEncoded) {
var tmp = JSON.parse(value);
value = tmp.value;
value = me.handleInlineExpressions(JSON.stringify(value), null, true);
}
else {
value = me.handleInlineExpressions(value);
}
switch (statement.dataType) {
case 'Length':
case 'Time':
case 'Angle':
regex = /([0-9\.\-]+)([\w]+)$/i;
value = value.match(regex);
output.add('new __Numeric(' + value[1] + ', ' + '"' + value[2] + '")');
break;
case 'Number':
var s = value + '';
if (s.indexOf(".") === 0) {
s = '0' + s;
}
value = s;
output.add('new __Numeric(' + value + ')');
break;
case 'Percentage':
var s = value + '';
if (s.indexOf(".") === 0) {
s = '0' + s;
}
value = s;
output.add('new __Numeric(' + value.replace('%', '').replace(/\\/g, "") + ', "%")');
break;
case 'String':
output.add('new __Text("' + value + '", "' + me.escapeString(statement.quoteChar) + '")');
break;
case 'Literal':
if (me.booleans.hasOwnProperty(value.toLowerCase())) {
if (value.toLowerCase() === 'true') {
output.add('__True');
} else {
output.add('__False');
}
}
else if (me.colors.hasOwnProperty(value.toLowerCase())) {
output.add('__rt_color("' + value + '")');
}
else if (value == 'null') {
output.add('__Null');
}
else if (value == 'none') {
output.add('__None');
}
else {
if (statement.jsonEncoded) {
output.add('new __Literal(' + value + ')');
}
else {
output.add('new __Literal("' + value + '")');
}
}
break;
case 'Color':
output.add('__ColorRGBA.fromHex("' + value + '")');
break;
default:
//Fashion.log(statement.dataType, value);
output.add('"' + value + '"');
}
return false;
}
FunctionCall(statement) {
var me = this,
output = me.output,
args = statement.args,
id = statement.id || statement.value,
jsId,
reserved = {
'if': true,
'else': true
};
id = reserved[id] ? '__' + id : id;
jsId = Fashion.getJsName(id);
if (jsId === '__if') {
var args = me.loadArgsArray(statement.args),
skipWarning = this.skipWarning;
output.add("(__rt_test(");
me.handleStatement(args[0]);
output.add(") ? ");
this.skipWarning = true;
me.handleStatement(args[1]);
output.add(" : ");
me.handleStatement(args[2]);
output.add(")");
this.skipWarning = skipWarning;
}
else if (me.functionDeclarations[jsId]) {
output.add('__rt_box((__rt.functions.' + jsId + ' || ' + jsId + '__fn).apply(__rt.functions, __rt_applySpreadArgs([');
output.indent();
me.createCallArray(statement.args, me.functionDeclarations[jsId], id);
output.unindent();
output.add('])))');
}
else if (me.registeredDeclarations[jsId]) {
output.add('__rt_box(__rt.registered.' + jsId + '.apply(__rt.registered, __rt_applySpreadArgs([');
output.indent();
me.createCallArray(statement.args, me.registeredDeclarations[jsId], id, true);
output.unindent();
output.add('])))');
}
else {
args = this.loadArgsArray(args);
output.add('new __FunctionCall("');
output.add(me.handleInlineExpressions(id));
output.add('", new __List([');
output.indent();
output.addln();
for (var a = 0; a < args.length; a++) {
var arg = args[a];
me.handleStatement(arg);
if (a < (args.length - 1)) {
output.add(',');
output.space();
}
}
output.unindentln('], ","))');
}
return false;
}
Extend(statement) {
this.output.addln('__rt_extendSelector(');
this.handleStatement(statement.selector);
this.output.add(');');
return false;
}
ParentheticalExpression(statement) {
if (this.isSelector) {
this.output.addln('new __ParentheticalExpression(');
this.handleStatement(statement.expr);
this.output.add(')');
}
else if (statement.expr) {
this.handleStatement(statement.expr);
}
else {
this.output.add("new __List([], ', ')");
}
return false;
}
List(statement) {
var output = this.output,
isMap = false;
if (statement.items.length && statement.items[0].isKVP) {
isMap = true;
}
if (!isMap) {
output.add('new __List([');
for (var i = 0; i < statement.items.length; i++) {
var item = statement.items[i];
this.handleStatement(item);
if (i < (statement.items.length - 1)) {
output.add(',');
output.space();
}
}
output.add('], "' + statement.separator + '")');
} else {
output.add('new __Map([');
for (var i = 0; i < statement.items.length; i++) {
var item = statement.items[i];
this.handleStatement(item.variable);
output.add(',');
output.space();
this.handleStatement(item);
if (i < (statement.items.length - 1)) {
output.add(',');
output.space();
}
}
output.add('])');
}
return false;
}
Warn(statement) {
// ignore
this.addSourceInfo();
this.output.addln("__rt_warn(__rt_unbox(");
this.handleStatement(statement.expr);
this.output.add('));');
return false;
}
Error(statement) {
// ignore
this.addSourceInfo();
this.output.addln("__rt_error(__rt_unbox(");
this.handleStatement(statement.expr);
this.output.add('));');
return false;
}
Debugger(statement) {
this.output.addln("debugger;");
return false;
}
Import(statement) {
var me = this,
output = me.output,
source = statement.source;
if ((source.type === 'List' || source.type === 'SelectorList') && source.separator && source.separator.indexOf(',') === 0) {
source = source.items;
} else {
source = [source];
}
this.isSelector = statement.source;
source.forEach((source) => {
if (source && !/(^js[:])|(\.js$)/.test(source.value)) {
output.addln('__rt_addDirectiveRuleset("@import", ');
if (source.type === 'MultiPartSelector' && source.items.length === 1) {
source = source.items[0];
}
if (source && source.type === 'CompoundSelector' && source.items.length === 1) {
source = source.items[0];
}
if (!source.type || source.dataType === 'String' || source.dataType === 'Literal') {
if (!source.type) {
source = new Constant({
value: source,
dataType: 'String',
quoteChar: '"'
});
}
if (source.value.indexOf('http://') !== 0 &&
source.value.indexOf('//') !== 0) {
source = new FunctionCall(null, 'url',[
new FunctionCall(null, 'unquote',[
source
])
]);
}
this.handleStatement(source);
} else {
this.handleStatement(source);
}
output.add(');');
}
});
this.isSelector = null;
return false;
}
Require(statement) {
return false;
}
Assignment(statement) {
this.output.addln('new __Literal(["');
this.output.add(this.handleInlineExpressions(statement.id));
this.output.add(statement.operator + '", ');
this.handleStatement(statement.expr);
this.output.add('].join(""))');
return false;
}
Debug(statement) {
this.output.addln("__rt_debug(__rt_unbox(");
this.handleStatement(statement.expr);
this.output.add("));");
}
Charset(statement) {
//var output = this.output;
//if (statement.charset) {
// output.addln('__rt_addDirectiveRuleset("@charset", \'');
// output.add('"' + statement.charset + '"');
// output.add('\');');
//}
return false;
}
SelectorPart(statement) {
var output = this.output;
output.add('new __SelectorPart(');
this.handleStatement(statement.value);
output.add(', "' + statement.selectorType + '")');
return false;
}
CompoundSelector(statement) {
var output = this.output;
output.add('new __CompoundSelector([');
for (var i = 0; i < statement.items.length; i++) {
var item = statement.items[i];
this.handleStatement(item);
if (i < (statement.items.length - 1)) {
output.add(',');
output.space();
}
}
output.add('], true)');
return false;
}
MultiPartSelector(statement) {
var output = this.output;
output.add('new __MultiPartSelector([');
for (var i = 0; i < statement.items.length; i++) {
var item = statement.items[i];
this.handleStatement(item);
if (i < (statement.items.length - 1)) {
output.add(',');
output.space();
}
}
output.add('])');
return false;
}
SelectorList(statement) {
var output = this.output;
output.add('new __SelectorList([');
for (var i = 0; i < statement.items.length; i++) {
var item = statement.items[i];
this.handleStatement(item);
if (i < (statement.items.length - 1)) {
output.add(',');
output.space();
}
}
output.add('])');
return false;
}
SelectorProperty(statement) {
var output = this.output;
output.add('new __SelectorProperty(');
this.handleStatement(statement.property);
output.add(', ');
this.handleStatement(statement.value);
output.add(')');
return false;
}
Default(statement) {
this.warn('Unrecognized statement type: ' + statement.type + " , " + JSON.stringify(statement, null, 4));
}
//</editor-fold>
error(message, data) {
Fashion.error(message, data);
this.errors++;
}
warn(message, data) {
Fashion.warn(message, data);
this.warnings++;
}
transpile(ast, disableGetter) {
var me = this,
preprocessor = this.preprocessor,
sortedAst;
me.reset();
if (!preprocessor) {
preprocessor = new Preprocessor();
preprocessor.preprocess(ast);
}
this.preprocessor = preprocessor;
me.functionDeclarations = preprocessor.functionDeclarations;
me.mixinDeclarations = preprocessor.mixinDeclarations;
me.registeredDeclarations = preprocessor.registeredDeclarations;
me.variables = preprocessor.getVariables();
me.dynamicVariables = preprocessor.getDynamicsMap();
me.processedVariables = {};
sortedAst = preprocessor.getSortedDynamicAstNodes();
if (Array.isArray(ast)) {
sortedAst.push.apply(sortedAst, ast);
} else {
sortedAst.push(ast);
}
me.nestedDocs = false;
me.handleStatements(sortedAst);
if (me.warnings) {
Fashion.warn("Sass compilation encountered " + me.warnings + " warning(s)");
}
if (me.errors) {
Fashion.raise("Sass compilation encountered " + me.errors + " error(s)");
}
return me.output.get().trim();
}
}
Fashion.apply(Transpiler.prototype, {
errors: 0,
warnings: 0,
preprocessor: undefined,
output: undefined,
currentScope: undefined,
globalScope: undefined,
globalVars: undefined,
isSignatureDeclaration: undefined,
nestedDocs: undefined,
processingMixin: undefined,
functionDeclarations: undefined,
mixinDeclarations: undefined,
registeredDeclarations: undefined,
isFontDecl: undefined,
isSelector: undefined,
variables: undefined,
dynamicVariables: undefined,
stringCache: undefined,
docCache: undefined,
nodeCache: undefined,
eachCount: undefined,
popScope: undefined,
generateGets: undefined,
processedVariables: undefined,
skipWarning: undefi