@extjs/sencha-cmd-linux-32
Version:
Productivity and performance optimization tool for building applications with Sencha Ext JS and Sencha Touch.
655 lines (566 loc) • 21.5 kB
JavaScript
;
var Fashion = require('./export/Base.js'),
Base = Fashion.Base;
var Env = require('./Env.js');
var Visitor = require('./Visitor.js');
var Runtime = require('./Runtime.js');
Fashion.currentFile = undefined;
class SassFile extends Base {
constructor(cfg) {
super(cfg);
this.readyListeners = [];
this.state = 0;
this.imports = {};
this.importedBy = {};
if (this.isJsExtension()) {
this.loadExtension();
} else {
this.loadSass();
}
}
getLoadPath() {
var loadPath = this.loadPath;
if (!loadPath) {
loadPath = this.loadPath = this.path;
}
return loadPath;
}
loadExtension() {
var me = this,
loadPath = me.getLoadPath();
if (me.state < 5) {
me.state = 5;
if (me.state < 9) {
me.state = 9;
if (typeof System !== 'undefined') {
try {
me.info("importing " + loadPath);
System.import(loadPath).then(function (extension) {
extension.init(me.builder.context.runtime);
me.state = 10;
me.content = '';
me.info("file " + loadPath + " is loaded");
me.checkImports();
}, function (err) {
me.error("file " + loadPath + " failed to load");
me.error((err.stack || err) + '');
me.checkImports();
});
} catch (err) {
me.error("file " + loadPath + " failed to load");
me.error(err);
me.error((err.stack || err) + '');
me.checkImports();
}
}
else {
try {
if (!/\.js$/.test(loadPath)) {
loadPath += '.js';
}
if (Env.isNode && loadPath.indexOf('/') !== 0 && loadPath.indexOf(':') !== 1) {
loadPath = process.cwd() + '/' + loadPath;
}
// if (loadPath.indexOf('http') === 0) {
// loadPath = loadPath.replace(/http(s)?:\/\/(.*?)(:\d{1,4})?\//, '')
// }
me.info("requiring " + loadPath);
delete require.cache[require.resolve(loadPath)];
var extension = require(loadPath);
extension.init(me.builder.context.runtime);
me.state = 10;
me.content = '';
me.info("file " + loadPath + " is loaded");
me.checkImports();
} catch (err) {
me.error("file " + loadPath + " failed to load");
me.error((err.stack || err) + '');
me.checkImports();
}
}
}
}
}
loadSass() {
var me = this,
loadPath;
if (me.state < 5) {
me.state = 5;
if (me.state < 10) {
loadPath = me.getLoadPath();
me.info("loading file " + loadPath);
if (me.isSaveFile) {
me.state = 10;
me.content = '';
me.checkImports();
return;
}
Env.loadFile(loadPath, function (content) {
me.state = 10;
me.info("file " + loadPath + " is loaded");
me.content = content;
me.checkImports();
}, function () {
var idx = loadPath.lastIndexOf('/'),
attempt = loadPath;
if (idx > -1) {
attempt = attempt.substring(0, idx + 1) + '_' + attempt.substring(idx + 1);
}
loadPath = me.loadPath = attempt;
me.info("retrying with " + loadPath);
Env.loadFile(loadPath, function (content) {
me.state = 10;
me.info("file " + loadPath + " is loaded");
me.content = content;
me.checkImports();
}, function () {
Fashion.error("failed to download path : " + loadPath);
me.content = "";
me.checkImports();
});
});
}
}
}
getAst() {
var me = this,
ast = me.ast,
content = me.content,
loadPath = me.getLoadPath(),
parser;
if (me.isJsExtension()) {
return undefined;
}
if (!ast && content) {
parser = me.builder.getParser();
me.debug("parsing file " + loadPath);
try {
ast = me.ast = parser.parse(content, loadPath);
} catch (err) {
Fashion.error("Error parsing file : " + loadPath + " => ");
throw err;
return undefined;
}
}
return ast;
}
getSassFile(basePath, targetPath, origSource, importer) {
return this.builder.getSassFile(basePath, targetPath, origSource, importer);
}
isJsExtension() {
var loadPath = this.getLoadPath();
return loadPath.indexOf(".js") > 0;
}
getImportSource(source) {
var imports = [];
if ((source.type === 'List' || source.type === 'SelectorList') && source.separator && source.separator.indexOf(',') === 0) {
imports = source.items;
} else {
imports.push(source);
}
imports = Fashion.convert(imports, (source) => {
if (source && 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 && source.value) {
return source.value;
}
return source;
});
imports = Fashion.filter(imports, (source) => {
if (!source) {
return false;
}
if (!source.indexOf) {
return false;
}
var idx = source.indexOf('.css');
if (idx > -1 && idx === (source.length - 4)) {
return false;
}
idx = source.indexOf('http://');
if (idx === 0) {
return false;
}
idx = source.indexOf('//');
if (idx === 0) {
return false;
}
return true;
});
return imports;
}
trimComment(comment) {
if (comment.indexOf('//#') === 0) {
comment = comment.substring(3);
}
if (comment.indexOf('//') === 0) {
comment = comment.substring(2);
}
if (comment.indexOf('/*') === 0) {
comment = comment.substring(2, comment.length - 3);
}
return comment.trim();
}
dependsOn(path) {
var me = this;
if (me.imports[path]) {
return true;
}
for (var loadPath in me.imports) {
var dep = me.imports[loadPath];
if (dep.dependsOn(path)) {
return true;
}
}
return false;
}
checkImports() {
var me = this,
loadPath = me.getLoadPath(),
sassFiles = [],
missing, i;
if (me.state < 15) {
me.info("checking Imports for file " + loadPath);
me.state = 15;
// normal scss file
if (!me.isJsExtension()) {
if (me.isUiFile) {
me.mixinCalls = [];
}
var vis = new Visitor({
skipBranching: true,
loadJsExtension (source) {
source = source.replace(/;$/, '')
.replace(/^'/, '')
.replace(/'$/, '')
.replace(/\.js$/, '')
.replace(/^js:\s*/, '');
if (source.indexOf(".") !== 0) {
source = "./" + source;
}
var sassFile = me.getSassFile(me.path, source + ".js", source, me);
if (sassFile === me) {
Fashion.raise("file " + loadPath + " should not import itself");
}
me.imports[sassFile.getLoadPath()] = sassFile;
sassFile.importedBy[loadPath] = me;
if (sassFile.state < 20) {
sassFiles.push(sassFile);
}
},
//Comment (comment) {
// if (comment.indexOf('//#') === 0) {
// comment = me.trimComment(comment);
// if (comment.indexOf('@require ') === 0) {
// comment = comment.replace('@require ', '');
// this.loadJsExtension(comment);
// }
// }
//},
FunctionCall (node) {
var funcName = node.id || node.value;
var handlers = this;
if (funcName === 'require') {
var sources = me.getImportSource(node.args);
Fashion.warn("Use of 'require()' will be deprecated", node);
Fashion.warn("Use @import instead");
sources.forEach((source) => {
handlers.loadJsExtension(source);
});
node.visitTarget = null;
}
},
Require(node) {
var source = me.getImportSource(node.source)[0],
isGlobal = this.nodeStack.length == 1;
if (source.indexOf) {
if (!isGlobal) {
Fashion.raise('Cannot use require() "' + source + '" from non-file-scope location', node);
}
Fashion.warn("Use of '@require' has been deprecated", node);
Fashion.warn("Use @import instead");
delete node.visitTarget;
this.loadJsExtension(source);
}
},
Import(node) {
delete node.visitTarget;
delete node.nodeFiles;
var handlers = this,
source = me.getImportSource(node.source);
source.forEach((source) => {
if (/(^js[:])|(\.js$)/.test(source)) {
handlers.loadJsExtension(source);
} else {
var sassFile = me.getSassFile(me.path, source, source);
if (sassFile === me) {
Fashion.raise("file " + loadPath + " should not import itself");
}
if (sassFile.dependsOn(loadPath)) {
me.importError = new Error("Import cycle detected between " + me.getLoadPath() + " and " + sassFile.getLoadPath());
} else {
me.imports[sassFile.getLoadPath()] = sassFile;
sassFile.importedBy[loadPath] = me;
if (sassFile.state < 20) {
sassFiles.push(sassFile);
}
}
}
});
},
Include (node) {
if (me.isUiFile) {
me.mixinCalls.push(node);
}
}
});
vis.visit(me.getAst());
}
// javascript extension file
else if (Fashion && Env && Env.isRhino) {
var content = me.content + "\n//# sourceURL=" + loadPath;
eval(content);
}
// indicate that the state has passed out of checking imports
me.state == 16;
missing = sassFiles.length;
if (!missing) {
me.fireReady();
return;
}
for (i = 0; i < sassFiles.length; i++) {
sassFiles[i].onReady(function () {
missing--;
if (missing === 0) {
me.fireReady();
} else {
me.debug("file " + loadPath + " still waiting for " + missing + " other files");
}
});
}
}
}
onReady(listener) {
var me = this;
if (me.state >= 20) {
listener(me);
} else {
me.readyListeners.push(listener);
if (me.state == 10) {
me.checkImports();
}
}
}
fireReady() {
var me = this;
if (me.state < 20) {
me.info("file " + me.getLoadPath() + " is ready");
me.state = 20;
var listener;
while ((listener = me.readyListeners.shift()) != null) {
listener(me);
}
}
}
getExpandedAst(stamp) {
stamp = stamp || new Date().getTime();
var me = this,
ast = me.getAst();
if (me.importError) {
var err = me.importError;
delete me.importError;
throw err;
}
function addSourceInfo (vis) {
if (vis.addSourceInfo) {
vis.addSourceInfo(this.node);
}
}
function createCallStackScope (vis) {
if (vis.createCallStackScope) {
vis.createCallStackScope();
}
}
function popCallStackScope (vis) {
if (vis.popCallStackScope) {
vis.popCallStackScope();
}
}
if (me.imported != stamp) {
me.imported = stamp;
if (!me.isJsExtension()) {
me.debug("expanding ast for file " + me.getLoadPath());
var vis = new Visitor({
skipBranching: true,
Import(node) {
delete node.visitTarget;
var source = me.getImportSource(node.source),
visitTarget = [];
source.forEach((source) => {
if (source && source.indexOf && !/(^js[:])|(\.js$)/.test(source) && !node.skipSassImport) {
var sassFile = me.getSassFile(me.path, source);
sassFile.importing = true;
var importAst = sassFile.getExpandedAst(stamp);
if (me.builder.context.enableSymbols) {
visitTarget.push({
node: node,
doVisit: addSourceInfo
});
visitTarget.push({
doVisit: createCallStackScope
});
}
visitTarget.push(importAst);
if (me.builder.context.enableSymbols) {
visitTarget.push({
doVisit: popCallStackScope
});
}
sassFile.importing = false;
}
});
if (visitTarget.length) {
node.visitTarget = visitTarget;
}
}
});
me.expanding = true;
vis.visit(ast);
me.expanding = false;
return ast;
}
}
return Runtime.allowMultipleImports ? ast : undefined;
}
invalidate() {
var me = this;
if (me.state >= 10) {
me.info("invalidating file " + me.getLoadPath());
me.state = 0;
delete me.ast;
delete me.content;
delete me.imported;
for (var name in me.importedBy) {
me.importedBy[name].unready();
}
var loadPath = me.getLoadPath();
for (name in me.imports) {
delete me.imports[name].importedBy[loadPath];
}
me.imports = {};
if (me.isJsExtension()) {
me.loadExtension();
} else {
me.loadSass();
}
}
}
unready() {
this.state = 10;
delete this.ast;
for (var name in this.importedBy) {
this.importedBy[name].unready();
}
}
debug(message) {
// Fashion.log(message);
}
info(message) {
// Fashion.log(message);
}
error(message) {
Fashion.error(message);
}
getCustomUIs () {
var me = this,
mixinMap = {},
allUIs = {},
calls = me.mixinCalls,
separator = ', ',
node, mixinName, include, args, arg, argName, argMap, uiMap;
allUIs[me.jsClassName] = mixinMap;
for (var i = 0; i < calls.length; i++) {
node = calls[i];
include = node.include;
mixinName = include.id || include.value;
uiMap = mixinMap[mixinName] || {};
args = include.args;
if (args.isFashionListAst) {
args = args.items;
separator = args.separator;
}
if (!Array.isArray(args)) {
args = [args];
}
argMap = {};
for (var a = 0; a < args.length; a++) {
arg = args[a];
argName = a;
var value = arg.name || arg.value;
if (arg.variable) {
argName = arg.variable;
}
if (!value) {
while(arg && arg.expr) {
arg = arg.expr;
}
var converter = function(item) {
item = (item && item.expr) || item;
if (item.isFashionListAst) {
var sep = item.separator || separator,
items = Fashion.convert(item.items, converter),
value = items.join(sep);
if (items.length > 1) {
value = '(' + value+ ')';
}
return value;
}
return item.name || item.value;
};
if (arg.isFashionListAst) {
separator = arg.separator || separator;
value = converter(arg);
}
else {
value = arg.name || arg.value;
}
}
argMap[argName] = value;
}
if (argMap.$ui) {
var tmp = {};
tmp[argMap.$ui] = argMap;
delete argMap.$ui;
argMap = tmp;
}
Fashion.apply(uiMap, argMap);
mixinMap[mixinName] = uiMap;
}
return allUIs;
}
}
Fashion.apply(SassFile.prototype, {
$isSassFile: true,
expanding: false,
readyListeners: null,
state: null,
imports: null,
importedBy: null,
loadPath: null,
path: null,
content: null,
originalSource: null,
ast: null,
imported: null,
importer: null,
builder: null,
isSaveFile: null,
isUiFile: null,
jsClassName: null,
mixinCalls: null
});
module.exports = SassFile;