3

I am successfully building my project using the Dojo Build tool. However, I have one module squad_builder/Pilot that causes the build to fail whenever I include it, giving the following error:

error(356) The optimizer threw an exception; the module probably contains syntax errors. module identifier: /Users/ferg/Dropbox/webdev/x-wing_squadron_builder/www/js/dist/squad_builder/run_deps.js; exception: (compile time:1.247s). OPTIMIZER FAILED: InternalError: missing name after . operator

The module works fine in development and even running it through JS Lint, there's no obvious errors in it and particularly, nothing to do with a misplaced "." that I can see anywhere.

Here's the code of the module:

define( [ 'dojo/_base/declare', 

          // parents
          'dijit/TitlePane',

          // used modules
          'dojo/_base/lang',
          'dojo/_base/array',
          'dojo/dom-construct',
          'dojo/dom-style',
          'dojo/_base/fx',
          'dojo/_base/event',
          'squad_builder/actionIconParser',
          'dojo/promise/all',
          'dojo/Deferred',

          // dijits
          'dijit/form/Button',

          // stores
          // @todo only load rebels or empire store
          'squad_builder/storeBroker!rebelsStore',
          'squad_builder/storeBroker!empireStore',
          'squad_builder/storeBroker!actionsStore',
          'squad_builder/storeBroker!upgradeTypesStore',
          'squad_builder/storeBroker!setsStore',
          'squad_builder/storeBroker!shipTypesStore',

          // template
          'dojo/text!./Pilot/templates/Pilot.html' // extended TitlePane template

    ],
    function( declare, 
        TitlePane, 
        lang, array, domConstruct, domStyle, fx, event, actionIconParser, all, Deferred, 
        Button, 
        rebelsStore, empireStore, actionsStore, upgradeTypesStore, setsStore, shipTypesStore,
        template )
    {
        return declare( [ TitlePane ], 
        {
            // provided to constructor
            faction: null,

            pilotId: null,
            squadList: null,
            squadPaneId: null, // used for duplicating

            basePoints: null, // initial points
            points: null, // total points of pilot + upgrades

            _loaded: false, // flag to prevent multiple startup() calles

            allUpgradesLoaded: false,

            templateString: template,

            // A class to be applied to the root node in our template
            baseClass: 'pilotWidget dijitTitlePane',

            // used in auto-generated IDs
            declaredClass: 'squad_builder.PilotWidget',

            constructor: function()
            {
                // declared in constructor so all instances have their own copy
                this.pilotData = {};
                this.originalPilotData = {}; // used when removing upgrades so we cannot remove boost from A-Wings for example
                this.initiallySelectedUpgrades = [];
                this.upgradeButtons = [];

                // reference to squad-level caches
                this.uniqueUpgradeCache = {}; 
                this.collection = null;
            },

            // fetch the pilot data before loading template
            postMixInProperties: function()
            {
                this.inherited( arguments );

                // use pilot id to load the rest of the pilot data
                var store = this.faction == 'rebels' ? rebelsStore : empireStore,
                    data = store.get( this.pilotId ); // pilot data

                // save pilot data
                lang.mixin( this.pilotData, lang.clone( data ) ); // bugfix: needs clone or all copies of this ship will be modified by pilot modules
                this.originalPilotData = lang.clone( this.pilotData );

                // set initial points
                this.basePoints = parseInt( this.pilotData.cost ); // base points = pilot cost
                this.points = parseInt( this.pilotData.cost ); // may increase with upgrades
            },          

            postCreate: function()
            {
                // Run any parent postCreate processes - can be done at any point
                this.inherited( arguments );

                // wait until we have child widgets containing upgrades before figuring out points
                this._calculatePoints();

                // info
                this.infoDiv.innerHTML = shipTypesStore.get( this.pilotData.ship_type_id )['name'];

                if( this.pilotData.unique  )
                {
                    this.infoDiv.innerHTML += ', Unique';
                }

                if( !this.pilotData.released )
                {
                    this.infoDiv.innerHTML +=  ', Unreleased';
                }

                // switch between energy and primary stats
                if( !this.pilotData.energy )
                {
                    domStyle.set( this.energyNode, { display: 'none' } );
                }

                if( !this.pilotData.primary )
                {
                    domStyle.set( this.primaryNode, { display: 'none' } );
                }

                // ability
                if( this.pilotData.ability )
                {
                    this.abilityDiv.innerHTML = actionIconParser( this.pilotData.ability );
                }

                // add icons for actions
                this._initActions();

                // sets
                array.forEach( this.pilotData.sets, function( set )
                {
                    var setData = setsStore.get( set );
                    domConstruct.create( 'div',
                    {
                        innerHTML: setData.acronym,
                        title: setData.name
                    },
                    this.setsContainer );
                }, this );

                // clear message if any upgrades
                if( this.pilotData.upgrades.length )
                {
                    this.upgradesDiv.innerHTML = '';
                }
            },

            /*
             * Upgrades added here or watch() doesn't fire!
             */
            startup: function()
            {
                if( this._loaded == false ) // only call this once when first adding pilot, not again when sorting
                {
                    // track all upgrades
                    var allUpgradesLoadedPromises = [];

                    // upgrade buttons
                    array.forEach( this.pilotData.upgrades, function( upgradeTypeId, index )
                    {
                        var deferred = this._addUpgradeButton( upgradeTypeId, this.initiallySelectedUpgrades[ index ], index, false );
                        allUpgradesLoadedPromises.push( deferred.promise );
                    },
                    this );

                    // do we have extra upgrades (eg. added by another upgrade)?
                    var extraUpgrades = array.filter( this.initiallySelectedUpgrades, function( selectedUpgrade )
                    {
                        return selectedUpgrade instanceof Array;
                    } );

                    if( extraUpgrades.length > 0 )
                    {
                        array.forEach( extraUpgrades, function( extraUpgrade, index )
                        {
                            var deferred = this._addUpgradeButton( extraUpgrade[1], extraUpgrade[0], this.pilotData.upgrades.length + index, true );
                            allUpgradesLoadedPromises.push( deferred.promise );
                        },
                        this );
                    }

                    // track when all promises fulfilled
                    // other objects (eg. modules) can use watch('allUpgradesLoaded') to hook into this
                    all( allUpgradesLoadedPromises ).then( lang.hitch( this, function()
                    {
                        this.set( 'allUpgradesLoaded', true );
                    } ) ).otherwise( function()
                    {
                        console.warn( 'Failed to track whether upgrades loaded', arguments );
                    } );

                    // highlight
                    domStyle.set( this.containerNode, { backgroundColor: '#FFF8B5' } );
                    fx.animateProperty(
                    {
                        node: this.containerNode,
                        properties: {
                            backgroundColor: '#FFFFFF'
                        },
                        duration: 500,
                        delay: 1000
                     } ).play();

                    this._loaded = true;
                }
            },

            _initActions: function()
            {
                // show action icons    
                // in function so we can fade out old icons first...
                var show = lang.hitch( this, function()
                {
                    domStyle.set( this.actionsDiv, 'opacity', 0 );

                    array.forEach( this.pilotData.actions, function( action )
                    {
                        var actionData = actionsStore.get( action );

                        domConstruct.create( 'div',
                        {
                            className: 'icon_action ' + actionData.class_name,
                            title: actionData.name
                        },
                        this.actionsDiv );
                    },
                    this );

                    fx.fadeIn(
                    {
                        node: this.actionsDiv
                    } ).play();
                } );

                // already got icons?
                if( this.actionsDiv !== undefined && this.actionsDiv.innerHTML != '' )
                {
                    fx.fadeOut(
                    {
                        node: this.actionsDiv,
                        onEnd: lang.hitch( this, function()
                        {
                            this.actionsDiv.innerHTML = '';
                            show();
                        } )
                    } ).play();
                }   
                else
                {
                    show();
                }   
            },

            _addUpgradeButton: function( upgradeTypeId, selectedId, position, isExtra ) 
            {
                var upgradeTypeData = upgradeTypesStore.get( upgradeTypeId ), // type of upgrade tells us what upgrade store to use
                    upgradeButtonDeferred = new Deferred();

                // get specific upgrade data for this button
                require( [ 'squad_builder/PilotUpgradeButton', 'squad_builder/storeBroker!' + upgradeTypeData.store ], 
                    lang.hitch( this, function( PilotUpgradeButton, upgradeStore )
                {
                    // create button
                    var upgradeButton = new PilotUpgradeButton(
                    {
                        position: position,
                        isExtra: Boolean( isExtra ),
                        pilot: this,
                        upgradeTypeId: upgradeTypeId,
                        name: upgradeTypeData.name,
                        upgradeClass: upgradeTypeData.class,
                        upgradeStore: upgradeStore,
                        selectedId: selectedId, 

                        // reference to squadlist-level cache
                        // used to check if unique upgrades used
                        uniqueUpgradeCache: this.uniqueUpgradeCache,

                        // reference to squadpane-level collection store
                        // used to record component use
                        collection: this.collection
                    } );

                    // watch points changes
                    upgradeButton.watch( 'points', lang.hitch( this, function()
                    {
                        this._calculatePoints();
                    } ) );

                    // store reference
                    this.upgradeButtons.push( upgradeButton );

                    // place
                    upgradeButton.placeAt( this.upgradesDiv );
                    upgradeButton.startup(); // add upgrades after watch() added

                    upgradeButtonDeferred.resolve( upgradeButton );
                } ) );

                return upgradeButtonDeferred; // allows pilot._addUpgradeButton( ... ).then( ... )
            },

            _calculatePoints: function()
            {
                var points = this.get('basePoints');

                // get points from upgrade buttons
                array.forEach( this.upgradeButtons, function( upgradeButton )
                {
                    points += upgradeButton.get( 'points' );
                } );

                this.set( 'points', points );
            },

            _calculateTitle: function()
            {
                var title = this.pilotData.name;
                array.forEach( this.upgradeButtons, function( upgradeButton )
                {
                    var upgradeName = upgradeButton.get( 'selectedName' );
                    if( upgradeName )
                    {
                        title += ' + ' + upgradeName;
                    }   
                } );
                title += ' (' + this.get( 'points' ) + ')';

                this.set( 'title', title );
            },

            // for dojo/Stateful watch/get/set
            _setPointsAttr: function( value ) 
            {
                this._set( 'points', value );
                this._calculateTitle();
            },

            close: function()
            {
                this.set( 'open', false );
            },

            _onDelete: function( e )
            {
                event.stop( e );
                this.onDelete();
                this.destroyRecursive();
            },

            /**
             * Extension point
             */
            onDelete: function()
            {
            },

            _onDuplicate: function( e )
            {
                event.stop( e );
                this.onDuplicate();
                this.squadList.addPilot( this.get( 'squadPaneId' ), this.get('faction'), this.get('pilotId'), this.get('upgrades')  );
            },

            /**
             * Extension point
             */
            onDuplicate: function()
            {
            },

            _onMoveUp: function( e )
            {
                event.stop( e );
                this.onMoveUp();
                this.squadList.movePilot( this.get( 'id' ), -1  );
            },

            /**
             * Extension point
             */
            onMoveUp: function()
            {
            },

            _onMoveDown: function( e )
            {
                event.stop( e );
                this.onMoveDown();
                this.squadList.movePilot( this.get( 'id' ), 1  );
            },

            /**
             * Extension point
             */
            onMoveDown: function()
            {
            },

            /**
             * Data to save/recreate this pilot
             */
            getData: function()
            {
                return { 
                    id: this.get('pilotId'), 
                    points: this.get('points'), 
                    basePoints: this.get('basePoints'), 
                    upgrades: this.get('upgrades') 
                };
            },

            /**
             * allows: this.get('upgrades')
             */
            _getUpgradesAttr: function()
            {
                // get upgrades from buttons
                var upgrades = [];

                // upgradeButton widgets may not be instantiated when this.get('upgrades') first called 
                // if so default to...
                if( this.upgradeButtons.length == 0 ) 
                {
                    // ... initially selected upgrades
                    if( this.initiallySelectedUpgrades.length !== undefined && this.initiallySelectedUpgrades.length > 0 ) 
                    {
                        upgrades = this.initiallySelectedUpgrades;
                    }
                    // ... or create array of nulls
                    else 
                    {   
                        var numUpgrades = this.pilotData.upgrades.length,
                            i = 0;
                        while( i++ < numUpgrades )
                        {
                            upgrades.push( null );
                        }
                    }
                }
                else
                {
                    array.forEach( this.upgradeButtons, function( upgradeButton )
                    {
                        // use position from instantiation to ensure we get them in the right order
                        upgrades[ upgradeButton.get( 'position' ) ] = upgradeButton.get( 'selectedId' ); // id or null or tuple pair
                    } );
                }

                return upgrades;
            },

            _getNameAttr: function()
            {
                return this.pilotData.name;
            },

            _getPilotAttr: function()
            {
                return this.pilotData.pilot;
            },

            _setPilotAttr: function( value )
            {
                this.pilotData.pilot = value;

                // animate change
                fx.fadeOut(
                {
                    node: this.pilotNode,
                    onEnd: lang.hitch( this, function()
                    {
                        this.pilotNode.innerHTML = value;
                        fx.fadeIn(
                        {
                            node: this.pilotNode
                        } ).play();
                    } )
                } ).play();
            },

            _getShieldsAttr: function()
            {
                return this.pilotData.shields;
            },

            _setShieldsAttr: function( value )
            {
                this.pilotData.shields = value;

                // animate change
                var shieldsNode = this.shieldsNode; // was losing scope so use local var
                fx.fadeOut(
                {
                    node: shieldsNode,
                    onEnd: function()
                    {
                        shieldsNode.innerHTML = value;
                        fx.fadeIn(
                        {
                            node: shieldsNode
                        } ).play();
                    }
                } ).play();
            },

            _getAgilityAttr: function()
            {
                return this.pilotData.agility;
            },

            _setAgilityAttr: function( value )
            {
                this.pilotData.agility = value;

                // animate change
                fx.fadeOut(
                {
                    node: this.agilityNode,
                    onEnd: lang.hitch( this, function()
                    {
                        this.agilityNode.innerHTML = value;
                        fx.fadeIn(
                        {
                            node: this.agilityNode
                        } ).play();
                    } )
                } ).play();
            },

            _getHullAttr: function()
            {
                return this.pilotData.hull;
            },

            _setHullAttr: function( value )
            {
                this.pilotData.hull = value;

                // animate change
                fx.fadeOut(
                {
                    node: this.hullNode,
                    onEnd: lang.hitch( this, function()
                    {
                        this.hullNode.innerHTML = value;
                        fx.fadeIn(
                        {
                            node: this.hullNode
                        } ).play();
                    } )
                } ).play();
            },

            _getEnergyAttr: function()
            {
                return this.pilotData.energy;
            },

            _setEnergyAttr: function( value )
            {
                this.pilotData.energy = value;

                // animate change
                fx.fadeOut(
                    {
                        node: this.energyNode,
                        onEnd: lang.hitch( this, function()
                        {
                            this.energyNode.innerHTML = value;
                            fx.fadeIn(
                            {
                                node: this.energyNode
                            } ).play();
                        } )
                    } ).play();
            }

        } );
    } 
);

I've been over and over the code but I just cannot find anything that seems to match up to the error message I'm getting. Any ideas?

Charles
  • 50,943
  • 13
  • 104
  • 142
voidstate
  • 7,937
  • 4
  • 40
  • 52
  • That is an *absurd* amount of code to review for what seems to be a syntax error. What have you tried in order to cut it down before pasting all of it here? – Charles Jun 23 '14 at 05:27
  • I realise there's a lot of code there, and I didn't really think anyone would go through it line by line. But maybe someone would have an idea and posting the code would mean they wouldn't have to request it, they could just look and see if they were right. – voidstate Jun 23 '14 at 10:36
  • Anyway, I've tried running the code in the browser and it works fine and there's no errors in the console. I have run it through JS Lint and also inspected it in PHP Storm without turning up anything. I've also searched for "." and looked to see if any of them looked wrong. And before that, I had to experiment with removing modules from the build to see which one in particular was causing the problem. What else should I try? – voidstate Jun 23 '14 at 10:46

3 Answers3

3

I ran into this error because I used a JavaScript keyword as an object property. EG:

object.return.value instead of object['return'].value

1

You're probably using a reserved word as a variable, as Julian Doucette suggested. Most likely it's your use of the variable "set". Rename it to something else, say "setItem"?

array.forEach(this.pilotData.sets, function(setItem)
{
    var setData = setsStore.get(setItem);
    domConstruct.create('div',
        {
            innerHTML: setData.acronym,
            title: setData.name
        },
        this.setsContainer);
}, this);

I'd also rename "event", which is also a reserved word.

Bazmatiq
  • 614
  • 5
  • 5
1

I switched to the closure compiler to reveal the cause of a similar error. Add:

 layerOptimize: "closure",

to the profile. Then it gave me this nice error message (with a ^ under "float")

dojo.js.uncompressed.js:2991: ERROR - Parse error. invalid property id
                                    domStyle.set(configTags[c], { float: "right", clear: "both" });

instead of the unhelpful shrinksafe version that was very similar to yours. Beats looking around for what I recently changed in git.

Unfortunately, for this error message the exit code is zero for closure or shrinksafe!

Isaac Bolinger
  • 7,328
  • 11
  • 52
  • 90