diff --git a/Alloy/alloy.js b/Alloy/alloy.js index 1dd6c929f..ca46d3748 100755 --- a/Alloy/alloy.js +++ b/Alloy/alloy.js @@ -4,18 +4,19 @@ * See LICENSE for more information on licensing. */ var program = require('commander'), - logger = require('./logger'), os = require('os'), - U = require('./utils'), colors = require('colors'), _ = require('lodash'), - pkginfo = require('pkginfo')(module, 'version'), path = require('path'), - fs = require('fs'), - CONST = require('./common/constants'); + fs = require('fs'); -// patch to remove the warning in node >=0.8 -path.existsSync = fs.existsSync || path.existsSync; +const { + logger, + platforms, + utils: U +} = require('alloy-utils'); + +require('pkginfo')(module, 'version'); // avoid io issues on Windows in nodejs 0.10.X: https://github.com/joyent/node/issues/3584 if (process.env.ALLOY_TESTS && /^win/i.test(os.platform())) { @@ -98,8 +99,8 @@ if (program.args.length === 0) { process.exit(0); } -if (program.platform && !_.includes(CONST.PLATFORM_FOLDERS_ALLOY, program.platform)) { - U.die('Invalid platform "' + program.platform + '" specified, must be [' + CONST.PLATFORM_FOLDERS_ALLOY.join(',') + ']'); +if (program.platform && !_.includes(platforms.constants.PLATFORM_FOLDERS_ALLOY, program.platform)) { + U.die('Invalid platform "' + program.platform + '" specified, must be [' + platforms.constants.PLATFORM_FOLDERS_ALLOY.join(',') + ']'); } // Validate the given command @@ -134,7 +135,7 @@ function getCommands() { try { var commandsPath = path.join(__dirname, 'commands'); return _.filter(fs.readdirSync(commandsPath), function(file) { - return path.existsSync(path.join(commandsPath, file, 'index.js')); + return fs.existsSync(path.join(commandsPath, file, 'index.js')); }); } catch (e) { U.die('Error getting command list', e); diff --git a/Alloy/builtins/string.js b/Alloy/builtins/string.js index 0bbde84e9..b69127b44 100755 --- a/Alloy/builtins/string.js +++ b/Alloy/builtins/string.js @@ -64,10 +64,7 @@ exports.lcfirst = function (text) { * @param {String} amount Amount to format. * @return {String} Amount formatted as a currency value. */ -exports.formatCurrency = !(OS_MOBILEWEB) ? String.formatCurrency : function (amount) { - var num = isNaN(amount) || amount === '' || amount === null ? 0.00 : amount; - return '$' + parseFloat(num).toFixed(2); -}; +exports.formatCurrency = String.formatCurrency; /** diff --git a/Alloy/commands/compile/BuildLog.js b/Alloy/commands/compile/BuildLog.js deleted file mode 100644 index 6210ead2e..000000000 --- a/Alloy/commands/compile/BuildLog.js +++ /dev/null @@ -1,59 +0,0 @@ -var fs = require('fs-extra'), - chmodr = require('chmodr'), - path = require('path'), - CONST = require('../../common/constants'), - logger = require('../../logger'); - -var dir, file, projectPath; - -function BuildLog(_projectPath) { - // make/reference singleton instance - if (BuildLog.instance) { - return BuildLog.instance; - } - BuildLog.instance = this; - - // set "private" variables - projectPath = _projectPath; - dir = path.join(projectPath, CONST.DIR.BUILD); - file = path.join(dir, 'build.json'); - - // expose data object - this.isNew = true; - this.data = {}; - - // make sure the alloy build folder exists - if (!fs.existsSync(dir)) { - fs.mkdirpSync(dir); - chmodr.sync(dir, 0755); - } - - // load it up - this.read(); -} - -BuildLog.prototype.read = function() { - if (!fs.existsSync(file)) { - this.isNew = true; - this.data = {}; - } else { - this.isNew = false; - try { - this.data = JSON.parse(fs.readFileSync(file, 'utf8')); - } catch (e) { - logger.warn('Build log at "' + path.relative(projectPath, file) + - '" is corrupt, creating a new one...'); - this.data = {}; - } - } -}; - -BuildLog.prototype.write = function() { - try { - fs.writeFileSync(file, JSON.stringify(this.data)); - } catch (e) { - logger.warn('Unable to write build log to "' + path.relative(projectPath, file) + '"'); - } -}; - -module.exports = BuildLog; diff --git a/Alloy/commands/compile/CompilerMakeFile.js b/Alloy/commands/compile/CompilerMakeFile.js index c2fd9f8d7..43ff67e51 100755 --- a/Alloy/commands/compile/CompilerMakeFile.js +++ b/Alloy/commands/compile/CompilerMakeFile.js @@ -1,5 +1,6 @@ -var logger = require('../../logger'), - colors = require('colors'); +var colors = require('colors'); + +const { logger } = require('alloy-utils'); function CompilerMakeFile() { var handlers = {}; diff --git a/Alloy/commands/compile/Orphanage.js b/Alloy/commands/compile/Orphanage.js index 0db007e83..9ed68a54e 100644 --- a/Alloy/commands/compile/Orphanage.js +++ b/Alloy/commands/compile/Orphanage.js @@ -6,12 +6,15 @@ var fs = require('fs-extra'), walkSync = require('walk-sync'), path = require('path'), - platforms = require('../../../platforms/index'), - logger = require('../../logger'), - CONST = require('../../common/constants'), - U = require('../../utils'), _ = require('lodash'); +const { + constants: CONST, + logger, + platforms, + utils: U +} = require('alloy-utils'); + var ALLOY_ROOT = path.join(__dirname, '..', '..'); var dirs, platform, titaniumFolder, theme, adapters; diff --git a/Alloy/commands/compile/ast/builtins-plugin.js b/Alloy/commands/compile/ast/builtins-plugin.js deleted file mode 100644 index de5fc4ab1..000000000 --- a/Alloy/commands/compile/ast/builtins-plugin.js +++ /dev/null @@ -1,91 +0,0 @@ -var path = require('path'), - fs = require('fs'), - _ = require('lodash'), - logger = require('../../../logger'), - U = require('../../../utils'); - -var EXCLUDE = ['backbone', 'CFG', 'underscore']; -var BUILTINS_PATH = path.join(__dirname, '..', '..', '..', 'builtins'); -var loaded = []; - -function appendExtension(file, extension) { - extension = '.' + extension; - file = U.trim(file); - - var len = extension.length; - if (file.substring(file.length - extension.length) !== extension) { - return file + extension; - } else { - return file; - } -} - -function loadBuiltin(source, name, dest) { - if (!path.existsSync(source)) { - return; - } - - logger.debug(' - [' + name + '] --> "' + dest + '"'); - U.copyFileSync(source, dest); - loaded = _.union(loaded, [name]); -} - -function loadMomentLanguages(config) { - // retrieve the languages of the project - var i18nPath = path.join(config.dir.project, 'i18n'); - if (fs.existsSync(i18nPath)) { - var languages = _.filter(fs.readdirSync(i18nPath), function(file) { - return fs.statSync(path.join(i18nPath, file)).isDirectory(); - }); - - // filter the momentjs translation files that match one of these languages - var availableI18nPath = path.join(BUILTINS_PATH, 'moment', 'lang'); - var fileNames = _.filter(fs.readdirSync(availableI18nPath), function(file) { - return _.indexOf(languages, file.substr(0, 2)) !== -1; - }); - - // import these files - _.each(fileNames, function(file) { - var source = path.join(BUILTINS_PATH, 'moment', 'lang', file); - var dest = path.join(config.dir.resources, 'alloy', 'moment', 'lang', file); - loadBuiltin(source, file, dest); - }); - } -} - -module.exports = function (_ref) { - var types = _ref.types; - var rx = /^(\/?alloy)\/(.+)$/; - - return { - visitor: { - CallExpression: function(p) { - var theString = p.node.arguments[0], - match; - if (p.node.callee.name === 'require' && // Is this a require call? - theString && types.isStringLiteral(theString) && // Is the 1st param a literal string? - (match = theString.value.match(rx)) !== null && // Is it an alloy module? - !_.includes(EXCLUDE, match[2]) && // Make sure it's not excluded. - !_.includes(loaded, match[2]) // Make sure we didn't find it already - ) { - // Make sure it hasn't already been copied to Resources - var name = appendExtension(match[2], 'js'); - if (fs.existsSync(path.join(this.opts.dir.resources, match[1], name))) { - return; - } - - // make sure the builtin exists - var source = path.join(BUILTINS_PATH, name); - var dest = path.join(this.opts.dir.resources, 'alloy', name); - loadBuiltin(source, name, dest); - - if ('moment.js' === name) { - // if momentjs is required in the project, also load the - // localizations which may be used - loadMomentLanguages(this.opts); - } - } - } - } - }; -}; diff --git a/Alloy/commands/compile/ast/controller.js b/Alloy/commands/compile/ast/controller.js deleted file mode 100644 index 82af33902..000000000 --- a/Alloy/commands/compile/ast/controller.js +++ /dev/null @@ -1,96 +0,0 @@ -var U = require('../../../utils'), - babylon = require('@babel/parser'), - types = require('@babel/types'), - generate = require('@babel/generator').default, - { default: traverse, Hub, NodePath } = require('@babel/traverse'); - -var isBaseControllerExportExpression = types.buildMatchMemberExpression('exports.baseController'); - -const GENCODE_OPTIONS = { - retainLines: true -}; - -exports.processController = function(code, file) { - var baseController = '', - moduleCodes = '', - newCode = '', - exportSpecifiers = []; - - try { - var ast = babylon.parse(code, { sourceFilename: file, sourceType: 'unambiguous' }); - - const hub = new Hub(); - hub.buildError = function (node, message, Error) { - const loc = node && node.loc; - const err = new Error(message); - - if (loc) { - err.loc = loc.start; - } - - return err; - }; - const path = NodePath.get({ - hub: hub, - parent: ast, - container: ast, - key: 'program' - }).setContext(); - traverse(ast, { - enter: function(path) { - if (types.isAssignmentExpression(path.node) && isBaseControllerExportExpression(path.node.left)) { - // what's equivalent of print_to_string()? I replaced with simple value property assuming it's a string literal - baseController = '\'' + path.node.right.value + '\''; - } - }, - - ImportDeclaration: function(path) { - moduleCodes += generate(path.node, GENCODE_OPTIONS).code; - path.remove(); - }, - - ExportNamedDeclaration: function(path) { - var node = path.node; - var specifiers = node.specifiers; - if (specifiers && specifiers.length !== 0) { - specifiers.forEach(function (specifier) { - if (specifier.local && specifier.local.name) { - exportSpecifiers.push(specifier.local.name); - } - }); - } - moduleCodes += generate(node, GENCODE_OPTIONS).code; - path.remove(); - } - }, path.scope); - - if (exportSpecifiers.length > 0) { - traverse(ast, { - enter: function(path) { - var node = path.node, - name; - if (node.type === 'VariableDeclaration') { - name = node.declarations[0].id.name; - } else if (node.type === 'FunctionDeclaration' || node.type === 'ClassDeclaration') { - name = node.id.name; - } - - if (exportSpecifiers.indexOf(name) !== -1) { - moduleCodes += generate(node, GENCODE_OPTIONS).code; - path.remove(); - } - } - }); - } - - newCode = generate(ast, GENCODE_OPTIONS).code; - } catch (e) { - U.dieWithCodeFrame('Error generating AST for "' + file + '". Unexpected token at line ' + e.loc.line + ' column ' + e.loc.column, e.loc, code); - } - - return { - es6mods: moduleCodes, - base: baseController, - code: newCode - }; -}; diff --git a/Alloy/commands/compile/ast/optimizer-plugin.js b/Alloy/commands/compile/ast/optimizer-plugin.js deleted file mode 100644 index 34d6248c4..000000000 --- a/Alloy/commands/compile/ast/optimizer-plugin.js +++ /dev/null @@ -1,71 +0,0 @@ -var CONST = require('../../../common/constants'), - _ = require('lodash'), - path = require('path'), - fs = require('fs'); - -// Walk tree transformer changing (Ti|Titanium).Platform.(osname|name) -// into static strings where possible. This will allow the following -// compression step to reduce the code further. -module.exports = function (_ref) { - var types = _ref.types; - - var isTiPlatform = types.buildMatchMemberExpression('Ti.Platform'); - var isTitaniumPlatform = types.buildMatchMemberExpression('Titanium.Platform'); - - return { - pre: function(state) { - var config = this.opts || {}; - config.deploytype = config.deploytype || 'development'; - - // create list of platform and deploy type defines - var defines = {}; - _.each(CONST.DEPLOY_TYPES, function(d) { - defines[d.key] = config.deploytype === d.value; - }); - _.each(CONST.DIST_TYPES, function(d) { - defines[d.key] = _.includes(d.value, config.target); - }); - _.each(CONST.PLATFORMS, function(p) { - defines['OS_' + p.toUpperCase()] = config.platform === p; - }); - this.defines = defines; - - // make sure the platform require includes - var platformString = config.platform.toLowerCase(); - var platformPath = path.join(__dirname, '..', '..', '..', '..', 'platforms', platformString, 'index'); - if (!fs.existsSync(platformPath + '.js')) { - this.platform = {name: undefined, osname: undefined }; - } else { - // create, transform, and validate the platform object - this.platform = require(platformPath); - if (!_.isString(this.platform.name)) { this.platform.name = undefined; } - if (!_.isString(this.platform.osname)) { this.platform.osname = undefined; } - } - }, - visitor: { - MemberExpression: function(path, state) { - // console.log(JSON.stringify(path.node)); - var name = ''; - if (types.isStringLiteral(path.node.property)) { - name = path.node.property.value; - } else if (types.isIdentifier(path.node.property)) { - name = path.node.property.name; - } else { - return; - } - - if ((name === 'name' || name === 'osname') && this.platform[name]) { - if (isTiPlatform(path.node.object) || isTitaniumPlatform(path.node.object)) { - path.replaceWith(types.stringLiteral(this.platform[name])); - } - } - }, - Identifier: function(path) { - if (this.defines.hasOwnProperty(path.node.name) && - (path.parent.type !== 'VariableDeclarator' || path.node.name !== path.parent.id.name)) { - path.replaceWith(types.booleanLiteral(this.defines[path.node.name])); - } - } - } - }; -}; diff --git a/Alloy/commands/compile/compilerUtils.js b/Alloy/commands/compile/compilerUtils.js deleted file mode 100755 index cf5e757a0..000000000 --- a/Alloy/commands/compile/compilerUtils.js +++ /dev/null @@ -1,1033 +0,0 @@ -var U = require('../../utils'), - colors = require('colors'), - path = require('path'), - os = require('os'), - fs = require('fs-extra'), - walkSync = require('walk-sync'), - chmodr = require('chmodr'), - jsonlint = require('jsonlint'), - logger = require('../../logger'), - astController = require('./ast/controller'), - _ = require('lodash'), - styler = require('./styler'), - XMLSerializer = require('xmldom').XMLSerializer, - CONST = require('../../common/constants'); - -/////////////////////////////////////// -////////// private variables ////////// -/////////////////////////////////////// -var alloyRoot = path.join(__dirname, '..', '..'), - platformsDir = path.join(alloyRoot, '..', 'platforms'), - alloyUniqueIdPrefix = '__alloyId', - alloyUniqueIdCounter = 0, - JSON_NULL = JSON.parse('null'), - compilerConfig; - -/////////////////////////////// -////////// constants ////////// -/////////////////////////////// -var RESERVED_ATTRIBUTES = [ - 'platform', - 'formFactor', - 'if', - CONST.BIND_COLLECTION, - CONST.BIND_WHERE, - CONST.AUTOSTYLE_PROPERTY, - 'ns', - 'method', - 'module' - ], - RESERVED_ATTRIBUTES_REQ_INC = [ - 'platform', - 'type', - 'src', - 'formFactor', - 'if', - CONST.BIND_COLLECTION, - CONST.BIND_WHERE, - CONST.AUTOSTYLE_PROPERTY, - 'ns', - 'method', - 'module' - ], - RESERVED_EVENT_REGEX = new RegExp(`^(?:(${CONST.PLATFORMS.join('|')}):)?on([A-Z].+)`); - -// load CONDITION_MAP with platforms -exports.CONDITION_MAP = { - handheld: { - runtime: '!Alloy.isTablet' - }, - tablet: { - runtime: 'Alloy.isTablet' - } -}; -_.each(CONST.PLATFORMS, function(p) { - exports.CONDITION_MAP[p] = require(path.join(platformsDir, p, 'index'))['condition']; -}); - -exports.bindingsMap = {}; -exports.destroyCode = ''; -exports.postCode = ''; -exports.models = []; -exports.dataFunctionNames = {}; - -////////////////////////////////////// -////////// public interface ////////// -////////////////////////////////////// -exports.getCompilerConfig = function() { - return compilerConfig; -}; - -exports.generateVarName = function(id, name) { - if (_.includes(CONST.JS_RESERVED_ALL, id)) { - U.die([ - 'Invalid ID "' + id + '" for <' + name + '>.', - 'Can\'t use reserved Javascript words as IDs.', - 'Reserved words: [' + CONST.JS_RESERVED_ALL.sort().join(',') + ']' - ]); - } - return '$.__views["' + id + '"]'; -}; - -exports.generateUniqueId = function() { - return alloyUniqueIdPrefix + alloyUniqueIdCounter++; -}; - -exports.getNodeFullname = function(node) { - var name = node.nodeName, - ns = node.getAttribute('ns') || CONST.IMPLICIT_NAMESPACES[name] || CONST.NAMESPACE_DEFAULT, - fullname = ns + '.' + name; - - return fullname; -}; - -exports.isNodeForCurrentPlatform = function(node) { - var isForCurrentPlatform = !node.hasAttribute('platform') || !compilerConfig || !compilerConfig.alloyConfig; - _.each(node.getAttribute('platform').split(','), function(p) { - // need to account for multiple platforms and negation, such as - // platform=ios,android or platform=!ios or platform="android,!mobileweb" - p = p.trim(); - if (p === compilerConfig.alloyConfig.platform || (p.indexOf('!') === 0 && p.slice(1) !== compilerConfig.alloyConfig.platform)) { - isForCurrentPlatform = true; - } - }); - return isForCurrentPlatform; -}; -exports.getParserArgs = function(node, state, opts) { - state = state || {}; - opts = opts || {}; - - var defaultId = opts.defaultId || undefined, - doSetId = opts.doSetId === false ? false : true, - name = node.nodeName, - ns = node.getAttribute('ns') || CONST.IMPLICIT_NAMESPACES[name] || CONST.NAMESPACE_DEFAULT, - fullname = (ns && ns.length) ? (ns + '.' + name) : name, - id = node.getAttribute('id') || defaultId || exports.generateUniqueId(), - platform = node.getAttribute('platform'), - formFactor = node.getAttribute('formFactor'), - tssIf = node.getAttribute('if'), - platformObj; - - // make sure we're not reusing the default ID for the first top level element - if (id === exports.currentDefaultId && - (node.parentNode && node.parentNode.nodeName !== 'Alloy') && - !node.__idWarningHandled) { - logger.warn([ - '<' + name + '> at line ' + node.lineNumber + - ' is using this view\'s default ID "' + id + '". ' + - 'Only a top-level element in a view should use the default ID' - ]); - node.__idWarningHandled = true; - } - - // handle binding arguments - var bindObj = {}; - bindObj[CONST.BIND_COLLECTION] = node.getAttribute(CONST.BIND_COLLECTION); - bindObj[CONST.BIND_WHERE] = node.getAttribute(CONST.BIND_WHERE); - bindObj[CONST.BIND_TRANSFORM] = node.getAttribute(CONST.BIND_TRANSFORM); - bindObj[CONST.BIND_FUNCTION] = node.getAttribute(CONST.BIND_FUNCTION); - - // cleanup namespaces and nodes - ns = ns.replace(/^Titanium\./, 'Ti.'); - if (doSetId && !_.includes(CONST.MODEL_ELEMENTS, fullname)) { - node.setAttribute('id', id); - } - - // process the platform attribute - if (platform) { - platformObj = {}; - _.each((platform).split(','), function(p) { - var matches = U.trim(p).match(/^(\!{0,1})(.+)/); - if (matches !== null) { - var negate = matches[1]; - var name = matches[2]; - if (_.includes(CONST.PLATFORMS, name)) { - if (negate === '!') { - _.each(_.without(CONST.PLATFORMS, name), function(n) { - platformObj[n] = true; - }); - } else { - platformObj[name] = true; - } - return; - } - } - U.die('Invalid platform type found: ' + p); - }); - } - - // get create arguments and events from attributes - var createArgs = {}, - events = []; - var attrs = _.includes(['Alloy.Require'], fullname) ? - RESERVED_ATTRIBUTES_REQ_INC : - RESERVED_ATTRIBUTES; - - // determine whether to autoStyle this component - // 1. autoStyle attribute - // 2. autoStyle from - // 3. autoStyle from config.json - var autoStyle = (function() { - var prop = CONST.AUTOSTYLE_PROPERTY; - if (node.hasAttribute(prop)) { - return node.getAttribute(prop) === 'true'; - } else { - return exports[prop]; - } - })(); - - // TODO: Add the apiName until TIMOB-12553 is resolved - if (autoStyle) { - createArgs[CONST.APINAME_PROPERTY] = fullname; - } - - _.each(node.attributes, function(attr) { - var attrName = attr.nodeName; - if (_.includes(attrs, attrName)) { return; } - var matches = attrName.match(RESERVED_EVENT_REGEX); - if (matches !== null && exports.isNodeForCurrentPlatform(node) && !_.includes(CONST.SPECIAL_PROPERTY_NAMES, attrName)) { - if (matches[1] && compilerConfig.alloyConfig.platform !== matches[1]) { - return; - } - events.push({ - name: U.lcfirst(matches[2]), - value: node.getAttribute(attrName) - }); - } else { - var theValue = node.getAttribute(attrName); - - // find platform specific attributes - var attributeParts = attrName.split(':'); - if ( attributeParts.length === 2 && _.includes(CONST.PLATFORMS, attributeParts[0])) { - // if this attribute is for this platform, create it without namespace. - if ( attributeParts[0] === compilerConfig.alloyConfig.platform ) { - attrName = attributeParts[1]; - } else { - return; - } - } - - if (/(^|\+)\s*(?:(?:Ti|Titanium|Alloy.Globals|Alloy.CFG|\$.args)\.|L\(.+\)\s*$)/.test(theValue)) { - var match = theValue.match(/^\s*L\([^'"]+\)\s*$/); - if (match !== null) { - theValue = theValue.replace(/\(/g, '("').replace(/\)/g, '")'); - } - theValue = styler.STYLE_EXPR_PREFIX + theValue; - } - - if (attrName === 'class') { - if (autoStyle) { - createArgs[CONST.CLASS_PROPERTY] = theValue.split(/\s+/) || []; - } - } else { - if (theValue === 'true') { - theValue = true; - } else if (theValue === 'false') { - theValue = false; - } else { - var n = parseInt(theValue); - if (!isNaN(n) && String(n) === theValue.trim()) { - theValue = n; - } else { - n = parseFloat(theValue); - if (!isNaN(n) && String(n) === theValue.trim()) { - theValue = n; - } - } - } - _.set(createArgs, attrName, theValue ); - } - } - }); - - if (autoStyle && !createArgs[CONST.CLASS_PROPERTY]) { - createArgs[CONST.CLASS_PROPERTY] = []; - } - - return _.extend({ - ns: ns, - name: name, - id: id, - fullname: fullname, - formFactor: node.getAttribute('formFactor'), - symbol: exports.generateVarName(id, name), - classes: node.getAttribute('class').split(' ') || [], - tssIf: node.getAttribute('if').split(',') || [], - parent: state.parent || {}, - platform: platformObj, - createArgs: createArgs, - events: events - }, bindObj); -}; - -exports.generateNodeExtended = function(node, state, newState) { - return exports.generateNode(node, _.extend(_.clone(state), newState)); -}; - -exports.generateNode = function(node, state, defaultId, isTopLevel, isModelOrCollection) { - if (node.nodeType != 1) return ''; - if (!exports.isNodeForCurrentPlatform(node)) { - return ''; - } - - var args = exports.getParserArgs(node, state, { defaultId: defaultId }), - codeTemplate = 'if (<%= condition %>) {\n<%= content %>}\n', - code = { - content: '', - pre: '' - }; - - // Check for platform specific considerations - var conditionType = compilerConfig && compilerConfig.alloyConfig && compilerConfig.alloyConfig.platform ? 'compile' : 'runtime'; - if (args.platform) { - var conditionArray = []; - _.each(args.platform, function(v, k) { - conditionArray.push(exports.CONDITION_MAP[k][conditionType]); - }); - - code.condition = '(' + conditionArray.join(' || ') + ')'; - } - - //Add form factor condition, if application form-factor specific runtime check - if (args.formFactor && exports.CONDITION_MAP[args.formFactor]) { - var check = exports.CONDITION_MAP[args.formFactor].runtime; - code.condition = (code.condition) ? code.condition += ' && ' + check : check; - } - - // ALOY-871: add the if condition check - args.tssIf = _.compact(args.tssIf); - if (args.tssIf.length > 0) { - if (code.condition) { - code.condition += (' && (' + args.tssIf.join(' || ') + ')'); - } else { - code.condition = args.tssIf.join(' || '); - } - } - - // pass relevant conditional information in state - if (code.condition) { - if (state.condition) { - state.condition += '&&' + code.condition; - } else { - state.condition = code.condition; - } - } - - // Determine which parser to use for this node - var parsersDir = path.join(alloyRoot, 'commands', 'compile', 'parsers'); - var parserRequire = 'default'; - if (_.includes(fs.readdirSync(parsersDir), args.fullname + '.js')) { - parserRequire = args.fullname + '.js'; - } - - // Execute the appropriate tag parser and append code - var isLocal = state.local; - // [ALOY-787] keeping track of widget id - var widgetId = state.widgetId; - state = require('./parsers/' + parserRequire).parse(node, state) || { parent: {} }; - code.content += state.code; - state.widgetId = widgetId; - - // Use local variable if given - if (isLocal && state.parent) { args.symbol = state.parent.symbol || args.symbol; } - - // Use manually given args.symbol if present - if (state.args) { args.symbol = state.args.symbol || args.symbol; } - - // add to list of top level views, if its top level - if (isTopLevel) { - if (state.isProxyProperty) { - delete state.isProxyProperty; - code.content += state.parent.symbol + ' && $.addProxyProperty("' + state.propertyName + - '", ' + state.parent.symbol + ');\n'; - } else { - code.content += args.symbol + ' && $.addTopLevelView(' + args.symbol + ');\n'; - } - } - - // handle any model/collection code - if (state.modelCode) { - code.pre += state.modelCode; - delete state.modelCode; - } - - // handle any events from markup - if (args.events && args.events.length > 0 && - !_.includes(CONST.SKIP_EVENT_HANDLING, args.fullname) && - !state.isViewTemplate) { - // determine which function name to use for event handling: - // * addEventListener() for Titanium proxies - // * on() for everything else (controllers, models, collections) - var eventFunc = /^Alloy\.(?:Collection|Model|Require|Widget)/.test(args.fullname) ? - 'on' : 'addEventListener'; - - _.each(args.events, function(ev) { - var eventObj = { - obj: isModelOrCollection ? state.args.symbol : args.symbol, - ev: ev.name, - cb: ev.value, - escapedCb: ev.value.replace(/'/g, "\\'"), - func: eventFunc - }, - postCode; - - if (_.includes(['Alloy.Widget', 'Alloy.Require'], args.fullname)) { - eventObj.obj = state.controller; - } - - // create templates for immediate and deferred event handler creation - var theDefer = _.template("__defers['<%= obj %>!<%= ev %>!<%= escapedCb %>']")(eventObj); - var theEvent; - if (eventFunc === 'addEventListener') { - theEvent = _.template("$.addListener(<%= obj %>,'<%= ev %>',<%= cb %>)")(eventObj); - } else { - theEvent = _.template("<%= obj %>.<%= func %>('<%= ev %>',<%= cb %>)")(eventObj); - } - var deferTemplate = theDefer + ' && ' + theEvent + ';'; - var immediateTemplate; - if (/[\.\[]/.test(eventObj.cb)) { - immediateTemplate = 'try{' + theEvent + ';}catch(e){' + theDefer + '=true;}'; - } else { - immediateTemplate = '<%= cb %>?' + theEvent + ':' + theDefer + '=true;'; - } - - // add the generated code to the view code and post-controller code respectively - code.content += _.template(immediateTemplate)(eventObj); - postCode = _.template(deferTemplate)(eventObj); - exports.postCode += state.condition ? _.template(codeTemplate)({ - condition: state.condition, - content: postCode - }) : postCode; - }); - } - - // Continue parsing if necessary - if (state.parent) { - var states = _.isArray(state.parent) ? state.parent : [state.parent]; - _.each(states, function(p) { - var parent = p.node; - if (!parent) { return; } - for (var i = 0, l = parent.childNodes.length; i < l; i++) { - var newState = _.defaults({ parent: p }, state); - if (node.hasAttribute('formFactor') || state.parentFormFactor) { - // propagate the form factor down through the hierarchy - newState.parentFormFactor = (node.getAttribute('formFactor') || state.parentFormFactor); - } - code.content += exports.generateNode(parent.childNodes.item(i), newState); - } - }); - } - - if (!isModelOrCollection) { - return code.condition ? _.template(codeTemplate)(code) : code.content; - } else { - return { - content: code.condition ? _.template(codeTemplate)(code) : code.content, - pre: code.condition ? _.template(codeTemplate)({content:code.pre}) : code.pre - }; - } -}; - -exports.expandRequireNode = function(requireNode, doRecursive) { - var cloneNode = requireNode.cloneNode(true); - - function getViewRequirePath(node) { - var regex = new RegExp('\\.' + CONST.FILE_EXT.VIEW + '$'), - src = node.getAttribute('src'), - fullname = exports.getNodeFullname(node), - name = node.getAttribute('name') || CONST.NAME_WIDGET_DEFAULT, - type = fullname === 'Alloy.Widget' ? 'widget' : node.getAttribute('type') || CONST.REQUIRE_TYPE_DEFAULT, - fullpaths = []; - - var platform; - if (compilerConfig && compilerConfig.alloyConfig && compilerConfig.alloyConfig.platform) { - platform = compilerConfig.alloyConfig.platform; - } - - // Must be a view, with a valid src, in a element - if (!src) { - return null; - } else if (fullname === 'Alloy.Require' && type === 'view') { - if (platform) { fullpaths.push(path.join(compilerConfig.dir.views, platform, src)); } - fullpaths.push(path.join(compilerConfig.dir.views, src)); - } else if (fullname === 'Alloy.Widget' || - (fullname === 'Alloy.Require' && type === 'widget')) { - U.getWidgetDirectories(compilerConfig.dir.home).forEach(function(wDir) { - if (wDir.manifest.id === src) { - if (platform) { - fullpaths.push(path.join(wDir.dir, CONST.DIR.VIEW, platform, name)); - } - fullpaths.push(path.join(wDir.dir, CONST.DIR.VIEW, name)); - } - }); - } else { - return null; - } - - // check the extensions on the paths to check - var found = false; - var fullpath; - for (var i = 0; i < fullpaths.length; i++) { - fullpath = fullpaths[i]; - fullpath += regex.test(fullpath) ? '' : '.' + CONST.FILE_EXT.VIEW; - if (fs.existsSync(fullpath)) { - found = true; - break; - } - } - - // abort if there's no view to be found - if (!found) { - U.die([ - type + ' "' + src + '" ' + (type === 'widget' ? 'view "' + name + '" ' : '') + - 'does not exist.', - 'The following paths were inspected:' - ].concat(fullpaths)); - } - - return fullpath; - } - - //create function, it expects 2 values. - function insertAfter(newElement, targetElement) { - //target is what you want it to go after. Look for this elements parent. - var parent = targetElement.parentNode; - - //if the parents lastchild is the targetElement... - if (parent.lastchild == targetElement) { - //add the newElement after the target element. - parent.appendChild(newElement); - } else { - // else the target has siblings, insert the new element between the target and it's next sibling. - parent.insertBefore(newElement, targetElement.nextSibling); - } - } - - function processRequire(node, isFirst) { - // make sure we have a valid required view and get its path - var fullpath = getViewRequirePath(node); - if (fullpath === null) { - return; - } - - // re-assemble XML with required elements - if (isFirst) { - cloneNode = U.XML.getAlloyFromFile(fullpath); - } else { - var newDocRoot = U.XML.getAlloyFromFile(fullpath); - _.each(U.XML.getElementsFromNodes(newDocRoot.childNodes), function(n) { - insertAfter(n, node); - }); - - node.parentNode.removeChild(node); - } - } - - // Expand the , recursively if specified - if (getViewRequirePath(cloneNode) !== null) { - processRequire(cloneNode, true); - while (doRecursive) { - var reqs = cloneNode.getElementsByTagName('Require'); - var widgets = cloneNode.getElementsByTagName('Widget'); - var all = []; - - // condense node lists into a single array - _.each(reqs, function(req) { - all.push(req); - }); - _.each(widgets, function(widget) { - all.push(widget); - }); - - // find all the valid widgets/requires - var viewRequires = _.filter(reqs, function(req) { - return getViewRequirePath(req) !== null; - }); - - if (viewRequires.length === 0) { - break; - } - - // TODO: https://jira.appcelerator.org/browse/ALOY-256 - //_.each(viewRequires, processRequire); - processRequire(viewRequires[0]); - } - } - - return cloneNode; -}; - -exports.inspectRequireNode = function(node) { - var newNode = exports.expandRequireNode(node, true); - var children = U.XML.getElementsFromNodes(newNode.childNodes); - var names = []; - - _.each(children, function(c) { - var args = exports.getParserArgs(c); - - // skip model elements when inspecting nodes for - if (_.includes(CONST.MODEL_ELEMENTS, args.fullname)) { - newNode.removeChild(c); - return; - } - - names.push(args.fullname); - }); - - return { - children: U.XML.getElementsFromNodes(newNode.childNodes), - length: names.length, - names: names - }; -}; - -exports.copyWidgetResources = function(resources, resourceDir, widgetId, opts) { - - opts = opts || {}; - var platform; - if (compilerConfig && compilerConfig.alloyConfig && compilerConfig.alloyConfig.platform) { - platform = compilerConfig.alloyConfig.platform; - } - - _.each(resources, function(dir) { - if (!path.existsSync(dir)) { return; } - logger.trace('WIDGET_SRC=' + path.relative(compilerConfig.dir.project, dir)); - var files = walkSync(dir); - _.each(files, function(file) { - file = path.normalize(file); - var source = path.join(dir, file); - - // make sure the file exists and that it is not filtered - if (!fs.existsSync(source) || - (opts.filter && opts.filter.test(file)) || - (opts.exceptions && _.includes(opts.exceptions, file))) { - return; - } - - if (fs.statSync(source).isFile()) { - var dirname = path.dirname(file); - var parts = dirname.split(/[\/\\]/); - if (opts.titaniumFolder && parts[0] === opts.titaniumFolder) { - dirname = parts.slice(1).join('/'); - } - - var destDir = path.join(resourceDir, dirname, widgetId); - var dest = path.join(destDir, path.basename(file)); - if (!path.existsSync(destDir)) { - fs.mkdirpSync(destDir); - chmodr.sync(destDir, 0755); - } - - logger.trace('Copying ' + file.yellow + ' --> ' + - path.relative(compilerConfig.dir.project, dest).yellow + '...'); - U.copyFileSync(source, dest); - } - }); - - // [ALOY-1002] Remove ios folder copied from widget - var iosDir = path.join(resourceDir, 'ios'); - if (fs.existsSync(iosDir)) { - fs.removeSync(iosDir); - } - logger.trace(' '); - }); - - if (opts.theme) { - // if this widget has been themed, copy its theme assets atop the stock ones - var widgetThemeDir = path.join(compilerConfig.dir.project, 'app', 'themes', opts.theme, 'widgets', widgetId); - if (fs.existsSync(widgetThemeDir)) { - logger.trace('Processing themed widgets'); - var widgetAssetSourceDir = path.join(widgetThemeDir, 'assets'); - var widgetAssetTargetDir = path.join(resourceDir, widgetId); - if (fs.existsSync(widgetAssetSourceDir)) { - fs.copySync(widgetAssetSourceDir, widgetAssetTargetDir, {preserveTimestamps: true}); - } - // platform-specific assets from the widget must override those of the theme - if (platform && path.existsSync(path.join(resources[0], platform))) { - fs.copySync(path.join(resources[0], platform), widgetAssetTargetDir, {preserveTimestamps: true}); - } - // however platform-specific theme assets must override the platform assets from the widget - if (platform && path.existsSync(path.join(widgetAssetSourceDir, platform))) { - logger.trace('Processing platform-specific theme assets for the ' + widgetId + ' widget'); - widgetAssetSourceDir = path.join(widgetAssetSourceDir, platform); - fs.copySync(widgetAssetSourceDir, widgetAssetTargetDir, {preserveTimestamps: true}); - } - - // [ALOY-1002] Remove platform-specific folders copied from theme - if (fs.existsSync(widgetAssetTargetDir)) { - var files = walkSync(widgetAssetTargetDir); - _.each(files, function(file) { - var source = path.join(widgetAssetTargetDir, file); - if (path.existsSync(source) && fs.statSync(source).isDirectory()) { - fs.removeSync(source); - } - }); - } - } - } -}; - -exports.mergeI18N = function mergeI18N(src, dest, opts) { - var serializer = new XMLSerializer(); - opts || (opts = {}); - - (function walk(src, dest) { - if (!fs.existsSync(src)) return; - - fs.readdirSync(src).forEach(function (name) { - var srcFile = path.join(src, name); - var destFile = path.join(dest, name); - - if (!fs.existsSync(srcFile)) return; - - if (fs.statSync(srcFile).isDirectory()) { - fs.existsSync(destFile) || fs.mkdirpSync(destFile); - chmodr.sync(destFile, 0755); - return walk(srcFile, destFile); - } - - if (!fs.existsSync(destFile)) { - logger.debug('Writing ' + destFile.yellow); - return U.copyFileSync(srcFile, destFile); - } - - if (!/\.xml$/.test(srcFile)) { - return; - } - - // merge! - var existing = {}; - var destXml = U.XML.parseFromFile(destFile); - var destDoc = destXml.documentElement; - var srcXml = U.XML.parseFromFile(srcFile); - var srcDoc = srcXml.documentElement; - - if (!destDoc) { - U.die('Error processing "' + destFile + '"'); - } - - if (!srcDoc) { - U.die('Error processing "' + srcFile + '"'); - } - - _.each(destDoc.getElementsByTagName('string'), function (node) { - var name = node.getAttribute('name'); - existing[name] = node; - }); - - _.each(srcDoc.getElementsByTagName('string'), function (node) { - var name = node.getAttribute('name'); - if (!existing.hasOwnProperty(name)) { - destDoc.appendChild(destXml.createTextNode('\t')); - destDoc.appendChild(node); - destDoc.appendChild(destXml.createTextNode('\n')); - } else if (opts.override) { - destDoc.replaceChild(node, existing[name]); - } - }); - - logger.debug('Merging ' + srcFile.yellow + ' --> ' + destFile.yellow); - fs.writeFileSync(destFile, serializer.serializeToString(destXml), 'utf8'); - }); - }(src, dest)); -}; - -function updateImplicitNamspaces(platform) { - switch (platform) { - case 'android': - break; - case 'ios': - break; - case 'mobileweb': - CONST.IMPLICIT_NAMESPACES.NavigationGroup = 'Ti.UI.MobileWeb'; - break; - } -} - -exports.createCompileConfig = function(inputPath, outputPath, alloyConfig, buildLog) { - var dirs = ['assets', 'config', 'controllers', 'lib', 'migrations', 'models', 'styles', 'themes', 'vendor', 'views', 'widgets']; - var libDirs = ['builtins', 'template']; - var resources = path.resolve(path.join(outputPath, 'Resources')); - - var obj = { - alloyConfig: alloyConfig, - dir: { - home: path.resolve(inputPath), - project: path.resolve(outputPath), - resources: resources, - resourcesAlloy: path.join(resources, 'alloy') - }, - buildLog: buildLog - }; - - // create list of dirs - _.each(dirs, function(dir) { - obj.dir[dir] = path.resolve(path.join(inputPath, dir)); - }); - _.each(libDirs, function(dir) { - obj.dir[dir] = path.resolve(path.join(alloyRoot, dir)); - }); - - // ensure the generated directories exist - U.ensureDir(obj.dir.resources); - - // process and normalize the config.json file - var configs = _.defaults(generateConfig(obj), { - // sets the theme - theme: undefined, - - // are we going to generate sourcemaps? - sourcemap: true, - - // are we enabling dynamic styling for all generated components? - autoStyle: false, - - // the list of widget dependencies - dependencies: {}, - - // TODO: Include no adapters by default - adapters: CONST.ADAPTERS - }); - - // normalize adapters - if (!configs.adapters) { - configs.adapters = []; - } else if (!_.isArray(configs.adapters)) { - configs.adapters = [configs.adapters]; - } - - logger.debug(JSON.stringify(configs, null, ' ').split(os.EOL)); - - // update implicit namespaces, if possible - updateImplicitNamspaces(alloyConfig.platform); - - // keep a copy of the config for this module - compilerConfig = _.extend(obj, configs); - - return obj; -}; - -function generateConfig(obj) { - var buildLog = obj.buildLog; - var o = {}; - var alloyConfig = obj.alloyConfig; - var platform = require('../../../platforms/' + alloyConfig.platform + '/index').titaniumFolder; - //var defaultCfg = 'module.exports=' + JSON.stringify(o) + ';'; - - // get the app and resources locations - var appCfg = path.join(obj.dir.home, 'config.' + CONST.FILE_EXT.CONFIG); - var resourcesBase = (function() { - var base = obj.dir.resources; - if (platform) { base = path.join(base, platform); } - return path.join(base, 'alloy'); - })(); - var resourcesCfg = path.join(resourcesBase, 'CFG.js'); - - // parse config.json, if it exists - if (path.existsSync(appCfg)) { - o = exports.parseConfig(appCfg, alloyConfig, o); - - if (o.theme) { - var themeCfg = path.join(obj.dir.home, 'themes', o.theme, 'config.' + CONST.FILE_EXT.CONFIG); - - // parse theme config.json, if it exists - if (path.existsSync(themeCfg)) { - o = exports.parseConfig(themeCfg, alloyConfig, o); - } - } - } - - // only regenerate the CFG.js when necessary - var hash = U.createHashFromString(JSON.stringify(o)); - if (buildLog.data.cfgHash && buildLog.data.cfgHash === hash && fs.existsSync(path.join(obj.dir.resources, 'alloy', 'CFG.js'))) { - // use cached CFG.js file - logger.info(' [config.json] config.json unchanged, using cached config.json...'); - } else { - // cached CFG.js is out of sync with config.json, regenerate and save - logger.info(' [config.json] regenerating CFG.js from config.json...'); - buildLog.data.cfgHash = hash; - // write out the config runtime module - fs.mkdirpSync(resourcesBase); - chmodr.sync(resourcesBase, 0755); - - //logger.debug('Writing "Resources/' + (platform ? platform + '/' : '') + 'alloy/CFG.js"...'); - var output = 'module.exports=' + JSON.stringify(o) + ';'; - fs.writeFileSync(resourcesCfg, output); - - // TODO: deal with TIMOB-14884 - var baseFolder = path.join(obj.dir.resources, 'alloy'); - if (!fs.existsSync(baseFolder)) { - fs.mkdirpSync(baseFolder); - chmodr.sync(baseFolder, 0755); - } - fs.writeFileSync(path.join(baseFolder, 'CFG.js'), output); - } - - return o; -} - -exports.parseConfig = function(file, alloyConfig, o) { - var j, distType; - try { - j = jsonlint.parse(fs.readFileSync(file, 'utf8')); - } catch (e) { - U.die('Error processing "config.' + CONST.FILE_EXT.CONFIG + '"', e); - } - - _.each(j, function(v, k) { - if (!/^(?:env\:|os\:|dist\:)/.test(k) && k !== 'global') { - logger.debug(k + ' = ' + JSON.stringify(v)); - o[k] = v; - } - }); - - if (alloyConfig) { - o = _.extend(o, j['global']); - o = _.extend(o, j['env:' + alloyConfig.deploytype]); - o = _.extend(o, j['os:' + alloyConfig.platform]); - o = _.extend(o, j['env:' + alloyConfig.deploytype + ' os:' + alloyConfig.platform]); - o = _.extend(o, j['os:' + alloyConfig.platform + ' env:' + alloyConfig.deploytype]); - - if (alloyConfig.deploytype === 'production' && alloyConfig.target) { - distType = _.find(CONST.DIST_TYPES, function (obj) { return obj.value.indexOf(alloyConfig.target) !== -1; }); - if (distType) { - distType = distType.key.toLowerCase().replace('_', ':'); - o = _.extend(o, j[distType]); - o = _.extend(o, j['os:' + alloyConfig.platform + ' ' + distType]); - } - } - if (alloyConfig.theme) { - o.theme = alloyConfig.theme; - } - } - - return o; -}; - -exports.loadController = function(file) { - var code = { - parentControllerName: '', - controller: '', - pre: '', - es6mods: '' - }, - contents; - - // Read the controller file - try { - if (!path.existsSync(file)) { - return code; - } - contents = fs.readFileSync(file, 'utf8'); - } catch (e) { - U.die('Error reading controller file "' + file + '".', e); - } - - // get the base controller for this controller, also process import/export statements - var controller = astController.processController(contents, file); - code.controller = controller.code; - code.parentControllerName = controller.base; - code.es6mods = controller.es6mods; - - return code; -}; - -exports.validateNodeName = function(node, names) { - var fullname = exports.getNodeFullname(node); - var ret = null; - if (!_.isArray(names)) { names = [names]; } - - // Is the node name in the given list of valid names? - ret = _.find(names, function(name) { return name === fullname; }); - if (ret) { return ret; } - - // Is it an Alloy.Require? - if (fullname === 'Alloy.Require' || fullname === 'Alloy.Widget') { - var inspect = exports.inspectRequireNode(node); - ret = _.find(inspect.children, function(n) { - return _.includes(names, exports.getNodeFullname(n)); - }); - if (ret) { - return exports.getNodeFullname(ret); - } - } - - return null; -}; - -exports.generateCollectionBindingTemplate = function(args) { - var code = ''; - var COLLECTION_BINDING_EVENTS = CONST.COLLECTION_BINDING_EVENTS_092; - - // Check if not 0.9.2 and if it's a supported version as we'll default to 0.9.2 if the version is not supported - if (compilerConfig.backbone !== '0.9.2' && CONST.SUPPORTED_BACKBONE_VERSIONS.includes(compilerConfig.backbone)) { - COLLECTION_BINDING_EVENTS = CONST.COLLECTION_BINDING_EVENTS; - } - - // Determine the collection variable to use - var obj = { name: args[CONST.BIND_COLLECTION] }; - var col = _.template((exports.currentManifest ? CONST.WIDGET_OBJECT : 'Alloy') + ".Collections['<%= name %>'] || <%= name %>")(obj); - var colVar = exports.generateUniqueId(); - - // Create the code for the filter and transform functions - var where = args[CONST.BIND_WHERE]; - var transform = args[CONST.BIND_TRANSFORM]; - var whereCode = where ? where + '(' + colVar + ')' : colVar + '.models'; - var transformCode = transform ? transform + '(<%= localModel %>)' : '_.isFunction(<%= localModel %>.transform)?<%= localModel %>.transform():<%= localModel %>.toJSON()'; - var handlerFunc = args[CONST.BIND_FUNCTION] || exports.generateUniqueId(); - if (args.parentFormFactor) { - if (!exports.dataFunctionNames[handlerFunc]) { - exports.dataFunctionNames[handlerFunc] = []; - } - exports.dataFunctionNames[handlerFunc].push(args.parentFormFactor); - // append the form factor for the code below - handlerFunc += U.ucfirst(args.parentFormFactor); - } - // construct code template - code += 'var ' + colVar + '=' + col + ';'; - code += 'function ' + handlerFunc + '(e) {'; - code += ' if (e && e.fromAdapter) { return; }'; - code += ' var opts = ' + handlerFunc + '.opts || {};'; - code += ' var models = ' + whereCode + ';'; - code += ' var len = models.length;'; - code += '<%= pre %>'; - code += ' for (var i = 0; i < len; i++) {'; - code += ' var <%= localModel %> = models[i];'; - if (!args.isDataBoundMap) { - code += ' <%= localModel %>.' + CONST.BIND_TRANSFORM_VAR + ' = ' + transformCode + ';'; - } else { - // because (ti.map).annotations[] doesn't accept an array of anonymous objects - // we convert them to actual Annotations before pushing them to the array - code += " <%= annotationArray %>.push(require('ti.map').createAnnotation(" + transformCode + '));'; - } - code += '<%= items %>'; - code += ' }'; - code += '<%= post %>'; - code += '};'; - code += colVar + ".on('" + COLLECTION_BINDING_EVENTS + "'," + handlerFunc + ');'; - - exports.destroyCode += colVar + ' && ' + ((args.parentFormFactor) ? 'Alloy.is' + U.ucfirst(args.parentFormFactor) + ' && ' : '' ) + - colVar + ".off('" + COLLECTION_BINDING_EVENTS + "'," + handlerFunc + ');'; - - return code; -}; diff --git a/Alloy/commands/compile/index.js b/Alloy/commands/compile/index.js index 1a742621e..934f9616a 100755 --- a/Alloy/commands/compile/index.js +++ b/Alloy/commands/compile/index.js @@ -5,24 +5,29 @@ var ejs = require('ejs'), chmodr = require('chmodr'), vm = require('vm'), babel = require('@babel/core'), - async = require('async'), // alloy requires _ = require('lodash'), - logger = require('../../logger'), - U = require('../../utils'), - tiapp = require('../../tiapp'), - CONST = require('../../common/constants'), - platforms = require('../../../platforms/index'), // alloy compiler requires - CU = require('./compilerUtils'), - styler = require('./styler'), - sourceMapper = require('./sourceMapper'), CompilerMakeFile = require('./CompilerMakeFile'), - BuildLog = require('./BuildLog'), Orphanage = require('./Orphanage'); +const { + BuildLog, + configureBabelPlugins, + createCompileConfig, + createCompiler, + sourceMapper, + utils: CU +} = require('alloy-compiler'); +const { + constants: CONST, + logger, + platforms, + utils: U +} = require('alloy-utils'); + var alloyRoot = path.join(__dirname, '..', '..'), viewRegex = new RegExp('\\.' + CONST.FILE_EXT.VIEW + '$'), controllerRegex = new RegExp('\\.' + CONST.FILE_EXT.CONTROLLER + '$'), @@ -34,7 +39,8 @@ var alloyRoot = path.join(__dirname, '..', '..'), buildLog, theme, platformTheme, - widgetIds = []; + widgetIds = [], + compiler; var times = { first: null, @@ -61,10 +67,6 @@ module.exports = function(args, program) { // Initialize modules used throughout the compile process buildLog = new BuildLog(paths.project); - tiapp.init(path.join(paths.project, 'tiapp.xml')); - - // validate the current Titanium SDK version, exit on failure - tiapp.validateSdkVersion(); // construct compiler config from command line config parameters // and print the configuration data @@ -102,7 +104,7 @@ module.exports = function(args, program) { ]); } titaniumFolder = platforms[buildPlatform].titaniumFolder; - otherPlatforms = _.without(CONST.PLATFORM_FOLDERS, titaniumFolder); + otherPlatforms = _.without(platforms.constants.PLATFORM_FOLDERS, titaniumFolder); // check the platform and i18n to see if it was generated by us last time var destI18NDir = path.join(paths.project, 'i18n'); @@ -159,8 +161,12 @@ module.exports = function(args, program) { // create compile config from paths and various alloy config files logger.debug('----- CONFIG.JSON -----'); - // NOTE: the following line creates the Resources/alloy/CFG.js and Resources//alloy/CFG.js - compileConfig = CU.createCompileConfig(paths.app, paths.project, alloyConfig, buildLog); + compileConfig = createCompileConfig({ + projectDir: paths.project, + buildLog, + alloyConfig, + logLevel: logger.TRACE + }); theme = compileConfig.theme; platformTheme = buildLog.data[buildPlatform] ? buildLog.data[buildPlatform]['theme'] : ''; @@ -233,22 +239,20 @@ module.exports = function(args, program) { if (restrictionPath === null) { // Generate alloy.js from template var libAlloyJsDest = path.join(paths.resources, titaniumFolder, 'alloy.js'); - var pkginfo = require('pkginfo')(module, 'version'); logger.trace('Generating ' + path.relative(titaniumFolder, libAlloyJsDest).yellow); fs.writeFileSync( libAlloyJsDest, ejs.render( fs.readFileSync(path.join(alloyRoot, 'template', 'lib', 'alloy.js'), 'utf8'), - { version: module.exports.version } + { version: program.version() } ) ); } - // NOTE: copies `common/constants.js` from Alloy into `/Resources//alloy` - updateFilesWithBuildLog( - path.join(alloyRoot, 'common'), - path.join(paths.resources, titaniumFolder, 'alloy'), - { rootDir: paths.project, restrictionPath: restrictionPath } + // NOTE: copies `alloy-utils/lib/constants.js` into `/Resources//alloy` + U.copyFileSync( + path.join(path.dirname(require.resolve('alloy-utils')), 'constants.js'), + path.join(paths.resources, titaniumFolder, 'alloy', 'constants.js') ); // create runtime folder structure for alloy @@ -404,9 +408,7 @@ module.exports = function(args, program) { logger.info('----- MVC GENERATION -----'); - // create the global style, if it exists - styler.setPlatform(buildPlatform); - styler.loadGlobalStyles(paths.app, theme ? {theme:theme} : {}); + compiler = createCompiler({ compileConfig }); // Create collection of all widget and app paths var widgetDirs = U.getWidgetDirectories(paths.app); @@ -420,7 +422,7 @@ module.exports = function(args, program) { // Create a regex for determining which platform-specific // folders should be used in the compile process - var filteredPlatforms = _.reject(CONST.PLATFORM_FOLDERS_ALLOY, function(p) { + var filteredPlatforms = _.reject(platforms.constants.PLATFORM_FOLDERS_ALLOY, function(p) { return p === buildPlatform; }); filteredPlatforms = _.map(filteredPlatforms, function(p) { return p + '[\\\\\\/]'; }); @@ -480,13 +482,6 @@ module.exports = function(args, program) { generateAppJs(paths, compileConfig, restrictionPath, compilerMakeFile); - // ALOY-905: workaround TiSDK < 3.2.0 iOS device build bug where it can't reference app.js - // in platform-specific folders, so we just copy the platform-specific one to - // the Resources folder. - if (buildPlatform === 'ios' && tiapp.version.lt('3.2.0')) { - U.copyFileSync(path.join(paths.resources, titaniumFolder, 'app.js'), path.join(paths.resources, 'app.js')); - } - // optimize code logger.info('----- OPTIMIZING -----'); @@ -585,342 +580,54 @@ function matchesRestriction(files, fileRestriction) { } function parseAlloyComponent(view, dir, manifest, noView, fileRestriction) { - var parseType = noView ? 'controller' : 'view'; - fileRestriction = fileRestriction || null; + const parseType = noView ? 'controller' : 'view'; + if (!view) { + U.die('Undefined ' + parseType + ' passed to parseAlloyComponent()'); + } + if (!dir) { + U.die('Failed to parse ' + parseType + ' "' + view + '", no directory given'); + } - // validate parameters - if (!view) { U.die('Undefined ' + parseType + ' passed to parseAlloyComponent()'); } - if (!dir) { U.die('Failed to parse ' + parseType + ' "' + view + '", no directory given'); } - - var dirRegex = new RegExp('^(?:' + CONST.PLATFORM_FOLDERS_ALLOY.join('|') + ')[\\\\\\/]*'); - var basename = path.basename(view, '.' + CONST.FILE_EXT[parseType.toUpperCase()]), - dirname = path.dirname(view).replace(dirRegex, ''), - viewName = basename, - template = { - viewCode: '', - modelVariable: CONST.BIND_MODEL_VAR, - parentVariable: CONST.PARENT_SYMBOL_VAR, - itemTemplateVariable: CONST.ITEM_TEMPLATE_VAR, - controllerPath: (dirname ? path.join(dirname, viewName) : viewName).replace(/\\/g, '/'), - preCode: '', - postCode: '', - Widget: !manifest ? '' : 'var ' + CONST.WIDGET_OBJECT + - " = new (require('/alloy/widget'))('" + manifest.id + "');this.__widgetId='" + - manifest.id + "';", - WPATH: !manifest ? '' : _.template(fs.readFileSync(path.join(alloyRoot, 'template', 'wpath.js'), 'utf8'))({ WIDGETID: manifest.id }), - __MAPMARKER_CONTROLLER_CODE__: '', - ES6Mod: '' - }, - widgetDir = dirname ? path.join(CONST.DIR.COMPONENT, dirname) : CONST.DIR.COMPONENT, - widgetStyleDir = dirname ? path.join(CONST.DIR.RUNTIME_STYLE, dirname) : - CONST.DIR.RUNTIME_STYLE, - state = { parent: {}, styles: [] }, - files = {}; - - // reset the bindings map - styler.bindingsMap = {}; - CU.destroyCode = ''; - CU.postCode = ''; - CU[CONST.AUTOSTYLE_PROPERTY] = compileConfig[CONST.AUTOSTYLE_PROPERTY]; - CU.currentManifest = manifest; - CU.currentDefaultId = viewName; - - // create a list of file paths - var searchPaths = noView ? ['CONTROLLER'] : ['VIEW', 'STYLE', 'CONTROLLER']; - _.each(searchPaths, function(fileType) { - // get the path values for the file - var fileTypeRoot = path.join(dir, CONST.DIR[fileType]); - var filename = viewName + '.' + CONST.FILE_EXT[fileType]; - var filepath = dirname ? path.join(dirname, filename) : filename; - - // check for platform-specific versions of the file - var baseFile = path.join(fileTypeRoot, filepath); - if (buildPlatform) { - var platformSpecificFile = path.join(fileTypeRoot, buildPlatform, filepath); - if (fs.existsSync(platformSpecificFile)) { - if (fileType === 'STYLE') { - files[fileType] = [ - { file:baseFile }, - { file:platformSpecificFile, platform:true } - ]; - } else { - files[fileType] = platformSpecificFile; - } - return; - } - } - files[fileType] = baseFile; - }); + const meta = compiler.factory + .createCompiler('component') + .resolveComponentMeta(path.join(dir, `${parseType}s`, view)); + const { componentName: viewName, subPath: dirname, files } = meta; + const { componentOutputPath, styleOutputPath } = resolveOutputPaths(viewName, dirname, manifest, files); + fileRestriction = fileRestriction || null; if (fileRestriction !== null && !matchesRestriction(files, fileRestriction)) { logger.info(' Not matching the file restriction, skipping'); return; } - _.each(['COMPONENT', 'RUNTIME_STYLE'], function(fileType) { - files[fileType] = path.join(compileConfig.dir.resources, 'alloy', CONST.DIR[fileType]); - if (dirname) { files[fileType] = path.join(files[fileType], dirname); } - files[fileType] = path.join(files[fileType], viewName + '.js'); + // generate component file + const { code, map } = compiler.compileComponent({ + file: parseType === 'controller' ? files.CONTROLLER : files.VIEW }); + let finalCode = code; + const relativeOutfile = path.relative(compileConfig.dir.project, componentOutputPath); + if (compileConfig.sourcemap !== false) { + const mapDir = path.join(compileConfig.dir.project, CONST.DIR.MAP); + const sourceMapOutputPath = `${path.join(mapDir, relativeOutfile)}.${CONST.FILE_EXT.MAP}`; + fs.outputFileSync(sourceMapOutputPath, map.toString()); + finalCode += `\n//# sourceMappingURL=file://${sourceMapOutputPath}`; + } + fs.outputFileSync(componentOutputPath, finalCode); + logger.info(` created: "${relativeOutfile}"`); + + // generate runtime style file + const styleFiles = Array.isArray(files.STYLE) ? files.STYLE : [ { file: files.STYLE } ]; + const { code: styleCode } = compiler.compileStyle(styleFiles[0]); + fs.outputFileSync(styleOutputPath, styleCode); + const relativeStylePath = path.relative(compileConfig.dir.project, styleOutputPath); + logger.info(` created: "${relativeStylePath}"`); - // we are processing a view, not just a controller - if (!noView) { - // validate view - if (!fs.existsSync(files.VIEW)) { - logger.warn('No ' + CONST.FILE_EXT.VIEW + ' view file found for view ' + files.VIEW); + if (manifest) { + // merge widget i18n and copy resources (but only once for every widget) + if (widgetIds.includes(manifest.id)) { return; } - - // load global style, if present - state.styles = styler.globalStyle || []; - - // Load the style and update the state - if (files.STYLE) { - var theStyles = _.isArray(files.STYLE) ? files.STYLE : [{file:files.STYLE}]; - _.each(theStyles, function(style) { - if (fs.existsSync(style.file)) { - logger.info(' style: "' + - path.relative(path.join(dir, CONST.DIR.STYLE), style.file) + '"'); - state.styles = styler.loadAndSortStyle(style.file, { - existingStyle: state.styles, - platform: style.platform - }); - } - }); - } - - if (theme) { - // if a theme is applied, override TSS definitions with those defined in the theme - var themeStylesDir, theStyle, themeStylesFile, psThemeStylesFile; - if (!manifest) { - // theming a "normal" controller - themeStylesDir = path.join(compileConfig.dir.themes, theme, 'styles'); - theStyle = dirname ? path.join(dirname, viewName + '.tss') : viewName + '.tss'; - themeStylesFile = path.join(themeStylesDir, theStyle); - psThemeStylesFile = path.join(themeStylesDir, buildPlatform, theStyle); - } else { - // theming a widget - themeStylesDir = path.join(compileConfig.dir.themes, theme, 'widgets', manifest.id, 'styles'); - theStyle = dirname ? path.join(dirname, viewName + '.tss') : viewName + '.tss'; - themeStylesFile = path.join(themeStylesDir, theStyle); - psThemeStylesFile = path.join(themeStylesDir, buildPlatform, theStyle); - } - - if (fs.existsSync(themeStylesFile)) { - // load theme-specific styles, overriding default definitions - logger.info(' theme: "' + path.join(theme.toUpperCase(), theStyle) + '"'); - state.styles = styler.loadAndSortStyle(themeStylesFile, { - existingStyle: state.styles, - theme: true - }); - } - if (fs.existsSync(psThemeStylesFile)) { - // load theme- and platform-specific styles, overriding default definitions - logger.info(' theme: "' + - path.join(theme.toUpperCase(), buildPlatform, theStyle) + '"'); - state.styles = styler.loadAndSortStyle(psThemeStylesFile, { - existingStyle: state.styles, - platform: true, - theme: true - }); - } - } - - // Load view from file into an XML document root node - var docRoot; - try { - logger.info(' view: "' + - path.relative(path.join(dir, CONST.DIR.VIEW), files.VIEW) + '"'); - docRoot = U.XML.getAlloyFromFile(files.VIEW); - } catch (e) { - U.die([ - e.stack, - 'Error parsing XML for view "' + view + '"' - ]); - } - - // see if autoStyle is enabled for the view - if (docRoot.hasAttribute(CONST.AUTOSTYLE_PROPERTY)) { - CU[CONST.AUTOSTYLE_PROPERTY] = - docRoot.getAttribute(CONST.AUTOSTYLE_PROPERTY) === 'true'; - } - - // see if module attribute has been set on the docRoot () tag for the view - if (docRoot.hasAttribute(CONST.DOCROOT_MODULE_PROPERTY)) { - CU[CONST.DOCROOT_MODULE_PROPERTY] = docRoot.getAttribute(CONST.DOCROOT_MODULE_PROPERTY); - } else { - CU[CONST.DOCROOT_MODULE_PROPERTY] = null; - } - - // see if baseController attribute has been set on the docRoot () tag for the view - if (docRoot.hasAttribute(CONST.DOCROOT_BASECONTROLLER_PROPERTY)) { - CU[CONST.DOCROOT_BASECONTROLLER_PROPERTY] = '"' + docRoot.getAttribute(CONST.DOCROOT_BASECONTROLLER_PROPERTY) + '"'; - } else { - CU[CONST.DOCROOT_BASECONTROLLER_PROPERTY] = null; - } - - // make sure we have a Window, TabGroup, or SplitWindow - var rootChildren = U.XML.getElementsFromNodes(docRoot.childNodes); - if (viewName === 'index' && !dirname) { - var valid = [ - 'Ti.UI.Window', - 'Ti.UI.iOS.SplitWindow', - 'Ti.UI.TabGroup', - 'Ti.UI.iOS.NavigationWindow', - 'Ti.UI.NavigationWindow' - ].concat(CONST.MODEL_ELEMENTS); - _.each(rootChildren, function(node) { - var found = true; - var args = CU.getParserArgs(node, {}, { doSetId: false }); - - if (args.fullname === 'Alloy.Require') { - var inspect = CU.inspectRequireNode(node); - for (var j = 0; j < inspect.names.length; j++) { - if (!_.includes(valid, inspect.names[j])) { - found = false; - break; - } - } - } else { - found = _.includes(valid, args.fullname); - } - - if (!found) { - U.die([ - 'Compile failed. index.xml must have a top-level container element.', - 'Valid elements: [' + valid.join(',') + ']' - ]); - } - }); - } - - // process any model/collection nodes - _.each(rootChildren, function(node, i) { - var fullname = CU.getNodeFullname(node); - var isModelElement = _.includes(CONST.MODEL_ELEMENTS, fullname); - - if (isModelElement) { - var vCode = CU.generateNode(node, state, undefined, false, true); - template.viewCode += vCode.content; - template.preCode += vCode.pre; - - // remove the model/collection nodes when done - docRoot.removeChild(node); - } - }); - - // rebuild the children list since model elements have been removed - rootChildren = U.XML.getElementsFromNodes(docRoot.childNodes); - - // process the UI nodes - _.each(rootChildren, function(node, i) { - // should we use the default id? - var defaultId = CU.isNodeForCurrentPlatform(node) ? viewName : undefined; - - // generate the code for this node - var fullname = CU.getNodeFullname(node); - template.viewCode += CU.generateNode(node, { - parent:{}, - styles:state.styles, - widgetId: manifest ? manifest.id : undefined, - parentFormFactor: node.hasAttribute('formFactor') ? node.getAttribute('formFactor') : undefined - }, defaultId, true); - }); - } - - // process the controller code - if (fs.existsSync(files.CONTROLLER)) { - logger.info(' controller: "' + - path.relative(path.join(dir, CONST.DIR.CONTROLLER), files.CONTROLLER) + '"'); - } - var cCode = CU.loadController(files.CONTROLLER); - template.parentController = (cCode.parentControllerName !== '') ? - cCode.parentControllerName : CU[CONST.DOCROOT_BASECONTROLLER_PROPERTY] || "'BaseController'"; - template.__MAPMARKER_CONTROLLER_CODE__ += cCode.controller; - template.preCode += cCode.pre; - template.ES6Mod += cCode.es6mods; - - // for each model variable in the bindings map... - _.each(styler.bindingsMap, function(mapping, modelVar) { - - // open the model binding handler - var handlerVar = CU.generateUniqueId(); - template.viewCode += 'var ' + handlerVar + ' = function() {'; - - _.each(mapping.models, function(modelVar) { - template.viewCode += modelVar + '.__transform = _.isFunction(' + modelVar + '.transform) ? ' + modelVar + '.transform() : ' + modelVar + '.toJSON();'; - }); - - CU.destroyCode += modelVar + ' && ' + ((state.parentFormFactor) ? 'is' + U.ucfirst(state.parentFormFactor) : '' ) + - modelVar + ".off('" + CONST.MODEL_BINDING_EVENTS + "'," + handlerVar + ');'; - - // for each specific conditional within the bindings map.... - _.each(_.groupBy(mapping.bindings, function(b) {return b.condition;}), function(bindings, condition) { - var bCode = ''; - - // for each binding belonging to this model/conditional pair... - _.each(bindings, function(binding) { - bCode += '$.' + binding.id + '.' + binding.prop + ' = ' + binding.val + ';'; - }); - - // if this is a legit conditional, wrap the binding code in it - if (typeof condition !== 'undefined' && condition !== 'undefined') { - bCode = 'if(' + condition + '){' + bCode + '}'; - } - template.viewCode += bCode; - - }); - template.viewCode += '};'; - template.viewCode += modelVar + ".on('" + CONST.MODEL_BINDING_EVENTS + "'," + - handlerVar + ');'; - }); - - // add destroy() function to view for cleaning up bindings - template.viewCode += 'exports.destroy = function () {' + CU.destroyCode + '};'; - - // add dataFunction of original name (if data-binding with form factor has been used) - if (!_.isEmpty(CU.dataFunctionNames)) { - _.each(Object.keys(CU.dataFunctionNames), function(funcName) { - template.viewCode += 'function ' + funcName + '() { '; - _.each(CU.dataFunctionNames[funcName], function(formFactor) { - template.viewCode += ' if(Alloy.is' + U.ucfirst(formFactor) + ') { ' + funcName + U.ucfirst(formFactor) + '(); } '; - }); - template.viewCode += '}'; - }); - } - - // add any postCode after the controller code - template.postCode += CU.postCode; - - // create generated controller module code for this view/controller or widget - var controllerCode = template.__MAPMARKER_CONTROLLER_CODE__; - delete template.__MAPMARKER_CONTROLLER_CODE__; - var code = _.template(fs.readFileSync(path.join(compileConfig.dir.template, 'component.js'), 'utf8'))(template); - - // prep the controller paths based on whether it's an app - // controller or widget controller - var targetFilepath = path.join(compileConfig.dir.resources, titaniumFolder, - path.relative(compileConfig.dir.resources, files.COMPONENT)); - var runtimeStylePath = path.join(compileConfig.dir.resources, titaniumFolder, - path.relative(compileConfig.dir.resources, files.RUNTIME_STYLE)); - if (manifest) { - fs.mkdirpSync( - path.join(compileConfig.dir.resources, titaniumFolder, 'alloy', CONST.DIR.WIDGET, - manifest.id, widgetDir) - ); - chmodr.sync(path.join(compileConfig.dir.resources, titaniumFolder, 'alloy', CONST.DIR.WIDGET, - manifest.id, widgetDir), 0755); - fs.mkdirpSync( - path.join(compileConfig.dir.resources, titaniumFolder, 'alloy', CONST.DIR.WIDGET, - manifest.id, widgetStyleDir) - ); - chmodr.sync(path.join(compileConfig.dir.resources, titaniumFolder, 'alloy', CONST.DIR.WIDGET, - manifest.id, widgetStyleDir), 0755); - - // [ALOY-967] merge "i18n" dir in widget folder CU.mergeI18N(path.join(dir, 'i18n'), path.join(compileConfig.dir.project, 'i18n'), { override: false }); - widgetIds.push(manifest.id); - CU.copyWidgetResources( [path.join(dir, CONST.DIR.ASSETS), path.join(dir, CONST.DIR.LIB)], path.join(compileConfig.dir.resources, titaniumFolder), @@ -932,95 +639,43 @@ function parseAlloyComponent(view, dir, manifest, noView, fileRestriction) { theme: theme } ); - targetFilepath = path.join( + widgetIds.push(manifest.id); + } +} + +/** + * Resolve the output paths based on whether it's an app controller or widget + * controller. + * + * @param {*} view + * @param {*} dirname + * @param {*} manifest + * @param {*} files + */ +function resolveOutputPaths(viewName, dirname, manifest, files) { + var componentOutputPath = path.join(compileConfig.dir.resources, titaniumFolder, + path.relative(compileConfig.dir.resources, files.COMPONENT)); + var styleOutputPath = path.join(compileConfig.dir.resources, titaniumFolder, + path.relative(compileConfig.dir.resources, files.RUNTIME_STYLE)); + if (manifest) { + const widgetDir = dirname ? path.join(CONST.DIR.COMPONENT, dirname) : CONST.DIR.COMPONENT; + const widgetStyleDir = dirname + ? path.join(CONST.DIR.RUNTIME_STYLE, dirname) + : CONST.DIR.RUNTIME_STYLE; + componentOutputPath = path.join( compileConfig.dir.resources, titaniumFolder, 'alloy', CONST.DIR.WIDGET, manifest.id, widgetDir, viewName + '.js' ); - runtimeStylePath = path.join( + styleOutputPath = path.join( compileConfig.dir.resources, titaniumFolder, 'alloy', CONST.DIR.WIDGET, manifest.id, widgetStyleDir, viewName + '.js' ); } - // generate the code and source map for the current controller - sourceMapper.generateCodeAndSourceMap({ - target: { - filename: path.relative(compileConfig.dir.project, files.COMPONENT), - filepath: targetFilepath, - templateContent: code - }, - data: { - __MAPMARKER_CONTROLLER_CODE__: { - filename: path.relative(compileConfig.dir.project, files.CONTROLLER), - fileContent: controllerCode - } - } - }, compileConfig); - - // initiate runtime style module creation - var relativeStylePath = path.relative(compileConfig.dir.project, runtimeStylePath); - logger.info(' created: "' + relativeStylePath + '"'); - - // skip optimize process, as the file is an alloy component - restrictionSkipOptimize = (fileRestriction !== null); - - // pre-process runtime controllers to save runtime performance - var STYLE_PLACEHOLDER = '__STYLE_PLACEHOLDER__'; - var STYLE_REGEX = new RegExp('[\'"]' + STYLE_PLACEHOLDER + '[\'"]'); - var processedStyles = []; - _.each(state.styles, function(s) { - var o = {}; - - // make sure this style entry applies to the current platform - if (s && s.queries && s.queries.platform && - !_.includes(s.queries.platform, buildPlatform)) { - return; - } - - // get the runtime processed version of the JSON-safe style - var processed = '{' + styler.processStyle(s.style, state) + '}'; - - // create a temporary style object, sans style key - _.each(s, function(v, k) { - if (k === 'queries') { - var queriesObj = {}; - - // optimize style conditionals for runtime - _.each(s[k], function(query, queryKey) { - if (queryKey === 'platform') { - // do nothing, we don't need the platform key anymore - } else if (queryKey === 'formFactor') { - queriesObj[queryKey] = 'is' + U.ucfirst(query); - } else if (queryKey === 'if') { - queriesObj[queryKey] = query; - } else { - logger.warn('Unknown device query "' + queryKey + '"'); - } - }); - - // add the queries object, if not empty - if (!_.isEmpty(queriesObj)) { - o[k] = queriesObj; - } - } else if (k !== 'style') { - o[k] = v; - } - }); - - // Create a full processed style string by inserting the processed style - // into the JSON stringifed temporary style object - o.style = STYLE_PLACEHOLDER; - processedStyles.push(JSON.stringify(o).replace(STYLE_REGEX, processed)); - }); - - // write out the pre-processed styles to runtime module files - var styleCode = 'module.exports = [' + processedStyles.join(',') + '];'; - if (manifest) { - styleCode += _.template(fs.readFileSync(path.join(alloyRoot, 'template', 'wpath.js'), 'utf8'))({ WIDGETID: manifest.id }); - } - fs.mkdirpSync(path.dirname(runtimeStylePath)); - chmodr.sync(path.dirname(runtimeStylePath), 0755); - fs.writeFileSync(runtimeStylePath, styleCode); + return { + componentOutputPath, + styleOutputPath + }; } function findModelMigrations(name, inDir) { @@ -1111,7 +766,7 @@ function processModels(dirs) { function updateFilesWithBuildLog(src, dst, opts) { // filter on retrictionPath if (opts.restrictionPath === null || _.find(opts.restrictionPath, function(f) {return f.indexOf(src) === 0;})) { - var updatedFiles = U.updateFiles(src, dst, _.extend({ isNew: buildLog.isNew }, opts)); + var updatedFiles = CU.updateFiles(src, dst, _.extend({ isNew: buildLog.isNew }, opts)); if (typeof updatedFiles == 'object' && updatedFiles.length > 0 && opts.restrictionPath !== null) { fileRestrictionUpdatedFiles = _.union(fileRestrictionUpdatedFiles, updatedFiles); @@ -1161,13 +816,11 @@ function optimizeCompiledCode(alloyConfig, paths) { }); } + // TODO: Remove once @titanium-sdk/babel-preset-app is in place while ((files = _.difference(getJsFiles(), lastFiles)).length > 0) { _.each(files, function(file) { var options = _.extend(_.clone(sourceMapper.OPTIONS_OUTPUT), { - plugins: [ - [require('./ast/builtins-plugin'), compileConfig], - [require('./ast/optimizer-plugin'), compileConfig.alloyConfig], - ] + plugins: configureBabelPlugins(compileConfig) }), fullpath = path.join(compileConfig.dir.resources, file); @@ -1176,7 +829,7 @@ function optimizeCompiledCode(alloyConfig, paths) { var result = babel.transformFileSync(fullpath, options); fs.writeFileSync(fullpath, result.code); } catch (e) { - U.die('Error transforming JS file', e); + U.die(`Error transforming JS file ${fullpath}`, e); } }); lastFiles = _.union(lastFiles, files); diff --git a/Alloy/commands/compile/parsers/Alloy.Abstract.Actions.js b/Alloy/commands/compile/parsers/Alloy.Abstract.Actions.js deleted file mode 100644 index 8f926d0a1..000000000 --- a/Alloy/commands/compile/parsers/Alloy.Abstract.Actions.js +++ /dev/null @@ -1,16 +0,0 @@ -var _ = require('lodash'); - -exports.parse = function(node, state) { - _.extend(state, { - itemArrayDefinition: { - parents: [ - 'Ti.UI.iOS.PreviewContext' - ], - children: [ - 'ALL' - ], - property: 'actions' - } - }); - return require('./Alloy.Abstract._ItemArray').parse(node, state); -}; diff --git a/Alloy/commands/compile/parsers/Alloy.Abstract.BarItemType.js b/Alloy/commands/compile/parsers/Alloy.Abstract.BarItemType.js deleted file mode 100644 index c7d2b0c6a..000000000 --- a/Alloy/commands/compile/parsers/Alloy.Abstract.BarItemType.js +++ /dev/null @@ -1,46 +0,0 @@ -var U = require('../../../utils'), - styler = require('../styler'); - -exports.parse = function(node, state) { - return require('./base').parse(node, state, parse); -}; - -function parse(node, state, args) { - if (!state.itemsArray) { - U.die('Invalid use of diff --git a/test/apps/testing/ALOY-1092/_generated/blackberry/alloy/controllers/childWindow.js b/test/apps/testing/ALOY-1092/_generated/blackberry/alloy/controllers/childWindow.js deleted file mode 100644 index 3bc6e8e1e..000000000 --- a/test/apps/testing/ALOY-1092/_generated/blackberry/alloy/controllers/childWindow.js +++ /dev/null @@ -1,35 +0,0 @@ -function __processArg(obj, key) { - var arg = null; - if (obj) { - arg = obj[key] || null; - delete obj[key]; - } - return arg; -} - -function Controller() { - require("alloy/controllers/BaseController").apply(this, Array.prototype.slice.call(arguments)); - this.__controllerPath = "childWindow"; - this.args = arguments[0] || {}; - if (arguments[0]) { - { - __processArg(arguments[0], "__parentSymbol"); - } - { - __processArg(arguments[0], "$model"); - } - { - __processArg(arguments[0], "__itemTemplate"); - } - } - var $ = this; - var exports = {}; - exports.destroy = function() {}; - _.extend($, $.__views); - arguments[0] || {}; - _.extend($, exports); -} - -var Alloy = require("alloy"), Backbone = Alloy.Backbone, _ = Alloy._; - -module.exports = Controller; \ No newline at end of file diff --git a/test/apps/testing/ALOY-1092/_generated/blackberry/alloy/controllers/index.js b/test/apps/testing/ALOY-1092/_generated/blackberry/alloy/controllers/index.js deleted file mode 100644 index ac92a9742..000000000 --- a/test/apps/testing/ALOY-1092/_generated/blackberry/alloy/controllers/index.js +++ /dev/null @@ -1,132 +0,0 @@ -function __processArg(obj, key) { - var arg = null; - if (obj) { - arg = obj[key] || null; - delete obj[key]; - } - return arg; -} - -function Controller() { - function myFunction() { - return true; - } - require("alloy/controllers/BaseController").apply(this, Array.prototype.slice.call(arguments)); - this.__controllerPath = "index"; - this.args = arguments[0] || {}; - if (arguments[0]) { - { - __processArg(arguments[0], "__parentSymbol"); - } - { - __processArg(arguments[0], "$model"); - } - { - __processArg(arguments[0], "__itemTemplate"); - } - } - var $ = this; - var exports = {}; - $.__views.index = Ti.UI.createWindow({ - layout: "vertical", - backgroundColor: "white", - id: "index" - }); - $.__views.index && $.addTopLevelView($.__views.index); - $.__views.label1 = Ti.UI.createLabel(function() { - var o = {}; - _.extend(o, { - top: 20, - left: 0, - font: { - fontSize: "14dp" - }, - color: "black" - }); - Alloy.Globals.isiPhone6 && _.extend(o, { - font: { - fontSize: "16dp" - }, - color: "green" - }); - _.extend(o, { - color: "blue", - text: "This is a label", - id: "label1" - }); - return o; - }()); - $.__views.index.add($.__views.label1); - $.__views.label2 = Ti.UI.createLabel(function() { - var o = {}; - _.extend(o, { - top: 20, - left: 0, - font: { - fontSize: "14dp" - }, - color: "black" - }); - Alloy.Globals.isiPhone6 && _.extend(o, { - font: { - fontSize: "16dp" - }, - color: "green" - }); - _.extend(o, { - color: "blue", - text: "This is also a label", - id: "label2" - }); - return o; - }()); - $.__views.index.add($.__views.label2); - $.__views.label3 = Ti.UI.createLabel(function() { - var o = {}; - _.extend(o, { - top: 20, - left: 0, - font: { - fontSize: "14dp" - }, - color: "black" - }); - Alloy.Globals.isiPhone6 && _.extend(o, { - font: { - fontSize: "16dp" - }, - color: "green" - }); - _.extend(o, { - color: "blue", - text: "Tap for new Window" - }); - myFunction() && _.extend(o, { - font: { - fontSize: "18dp" - }, - color: "red" - }); - _.extend(o, { - id: "label3" - }); - return o; - }()); - $.__views.index.add($.__views.label3); - exports.destroy = function() {}; - _.extend($, $.__views); - $.label3.addEventListener("click", function() { - var child = Alloy.createController("childWindow", { - someProperty: true - }); - console.log("__controllerPath = " + child.__controllerPath); - console.log("args = " + JSON.stringify(child.args)); - child.getView().open(); - }); - $.index.open(); - _.extend($, exports); -} - -var Alloy = require("alloy"), Backbone = Alloy.Backbone, _ = Alloy._; - -module.exports = Controller; \ No newline at end of file diff --git a/test/apps/testing/ALOY-1092/_generated/mobileweb/alloy/controllers/childWindow.js b/test/apps/testing/ALOY-1092/_generated/mobileweb/alloy/controllers/childWindow.js deleted file mode 100644 index ce2b3da73..000000000 --- a/test/apps/testing/ALOY-1092/_generated/mobileweb/alloy/controllers/childWindow.js +++ /dev/null @@ -1,96 +0,0 @@ -function __processArg(obj, key) { - var arg = null; - if (obj) { - arg = obj[key] || null; - delete obj[key]; - } - return arg; -} - -function Controller() { - function doClose() { - $.navWin.close(); - } - require("/alloy/controllers/BaseController").apply(this, Array.prototype.slice.call(arguments)); - this.__controllerPath = "childWindow"; - this.args = arguments[0] || {}; - if (arguments[0]) { - __processArg(arguments[0], "__parentSymbol"); - __processArg(arguments[0], "$model"); - __processArg(arguments[0], "__itemTemplate"); - } - var $ = this; - var exports = {}; - var __defers = {}; - $.__views.childWindow = Ti.UI.createWindow({ - backgroundColor: "#fff", - layout: "vertical", - id: "childWindow" - }); - $.__views.childWindow && $.addTopLevelView($.__views.childWindow); - $.__views.navWin = Ti.UI.createWindow({ - backgroundColor: "#fff", - layout: "vertical", - title: "Child window", - id: "navWin" - }); - $.__views.close = Ti.UI.createButton({ - id: "close", - title: "Close" - }); - doClose ? $.addListener($.__views.close, "click", doClose) : __defers["$.__views.close!click!doClose"] = true; - $.__views.navWin.leftNavButton = $.__views.close; - $.__views.argLabel = Ti.UI.createLabel(function() { - var o = {}; - Alloy.deepExtend(true, o, { - height: Ti.UI.SIZE, - width: Ti.UI.SIZE, - color: "#000", - textAlign: "center", - font: { - fontSize: "24dp", - fontWeight: "bold" - }, - text: "args.someProperty is falsey", - top: 25 - }); - $.args.someProperty && Alloy.deepExtend(true, o, { - text: "args.someProperty is truthy" - }); - Alloy.deepExtend(true, o, { - id: "argLabel" - }); - return o; - }()); - $.__views.navWin.add($.__views.argLabel); - if ($.args.someProperty) { - $.__views.argLabelTwo = Ti.UI.createLabel({ - height: Ti.UI.SIZE, - width: Ti.UI.SIZE, - color: "#000", - textAlign: "center", - font: { - fontSize: "24dp", - fontWeight: "bold" - }, - text: "XML-based if condition", - top: 25, - id: "argLabelTwo" - }); - $.__views.navWin.add($.__views.argLabelTwo); - } - $.__views.__alloyId0 = Ti.UI.MobileWeb.createNavigationGroup({ - window: $.__views.navWin, - id: "__alloyId0" - }); - $.__views.childWindow.add($.__views.__alloyId0); - exports.destroy = function() {}; - _.extend($, $.__views); - arguments[0] || {}; - __defers["$.__views.close!click!doClose"] && $.addListener($.__views.close, "click", doClose); - _.extend($, exports); -} - -var Alloy = require("/alloy"), Backbone = Alloy.Backbone, _ = Alloy._; - -module.exports = Controller; \ No newline at end of file diff --git a/test/apps/testing/ALOY-1092/_generated/mobileweb/alloy/controllers/index.js b/test/apps/testing/ALOY-1092/_generated/mobileweb/alloy/controllers/index.js deleted file mode 100644 index b73f1df67..000000000 --- a/test/apps/testing/ALOY-1092/_generated/mobileweb/alloy/controllers/index.js +++ /dev/null @@ -1,126 +0,0 @@ -function __processArg(obj, key) { - var arg = null; - if (obj) { - arg = obj[key] || null; - delete obj[key]; - } - return arg; -} - -function Controller() { - function myFunction() { - return true; - } - require("/alloy/controllers/BaseController").apply(this, Array.prototype.slice.call(arguments)); - this.__controllerPath = "index"; - this.args = arguments[0] || {}; - if (arguments[0]) { - __processArg(arguments[0], "__parentSymbol"); - __processArg(arguments[0], "$model"); - __processArg(arguments[0], "__itemTemplate"); - } - var $ = this; - var exports = {}; - $.__views.index = Ti.UI.createWindow({ - layout: "vertical", - backgroundColor: "white", - id: "index" - }); - $.__views.index && $.addTopLevelView($.__views.index); - $.__views.label1 = Ti.UI.createLabel(function() { - var o = {}; - Alloy.deepExtend(true, o, { - top: 20, - left: 0, - font: { - fontSize: "14dp" - }, - color: "black" - }); - Alloy.Globals.isiPhone6 && Alloy.deepExtend(true, o, { - font: { - fontSize: "16dp" - }, - color: "green" - }); - Alloy.deepExtend(true, o, { - color: "blue", - text: "This is a label", - id: "label1" - }); - return o; - }()); - $.__views.index.add($.__views.label1); - $.__views.label2 = Ti.UI.createLabel(function() { - var o = {}; - Alloy.deepExtend(true, o, { - top: 20, - left: 0, - font: { - fontSize: "14dp" - }, - color: "black" - }); - Alloy.Globals.isiPhone6 && Alloy.deepExtend(true, o, { - font: { - fontSize: "16dp" - }, - color: "green" - }); - Alloy.deepExtend(true, o, { - color: "blue", - text: "This is also a label", - id: "label2" - }); - return o; - }()); - $.__views.index.add($.__views.label2); - $.__views.label3 = Ti.UI.createLabel(function() { - var o = {}; - Alloy.deepExtend(true, o, { - top: 20, - left: 0, - font: { - fontSize: "14dp" - }, - color: "black" - }); - Alloy.Globals.isiPhone6 && Alloy.deepExtend(true, o, { - font: { - fontSize: "16dp" - }, - color: "green" - }); - Alloy.deepExtend(true, o, { - color: "blue", - text: "Tap for new Window" - }); - myFunction() && Alloy.deepExtend(true, o, { - font: { - fontSize: "18dp" - }, - color: "red" - }); - Alloy.deepExtend(true, o, { - id: "label3" - }); - return o; - }()); - $.__views.index.add($.__views.label3); - exports.destroy = function() {}; - _.extend($, $.__views); - $.label3.addEventListener("click", function() { - var child = Alloy.createController("childWindow", { - someProperty: true - }); - console.log("__controllerPath = " + child.__controllerPath); - console.log("args = " + JSON.stringify(child.args)); - child.getView().open(); - }); - $.index.open(); - _.extend($, exports); -} - -var Alloy = require("/alloy"), Backbone = Alloy.Backbone, _ = Alloy._; - -module.exports = Controller; \ No newline at end of file diff --git a/test/apps/testing/ALOY-1092/views/childWindow.xml b/test/apps/testing/ALOY-1092/views/childWindow.xml index 4cc581ebd..aae3d333d 100644 --- a/test/apps/testing/ALOY-1092/views/childWindow.xml +++ b/test/apps/testing/ALOY-1092/views/childWindow.xml @@ -13,18 +13,4 @@