boo-urns
boo-urns

Reputation: 10376

How to tell Closure Compiler to preserve properties on an object

I have an object declared like this:

my.namespace.FEATURES = {
    FIRST_FEATURE = "first feature",
    SECOND_FEATURE = "second feature"
};

I use my.namespace.my.object to keep track of what kinds of features are available/implemented in my code. Every newly released version will have a modified set of features. A third-party using my minimized code will want to know what they can do in the version they have, so I supply the following function, which is exported, so that they know what they can do.

my.namespace.hasFeature = function(feature) {
    for(var prop in my.namespace.FEATURES) {
        if(my.namespace.FEATURES[prop] == feature) {
            return true;
        }
    }
    return false;
}

The problem is that the properties are getting renamed when I run Closure Compiler.

My question is: what's the best way to keep those properties preserved? I know I can export the property, but it feels kind of dirty for some reason. Is there a Closure best practice to preserve the properties of an object?

Upvotes: 3

Views: 4504

Answers (3)

John
John

Reputation: 5468

In ADVANCED mode simply quoting the keys tells the compiler not to renamed them:

my.namespace.FEATURES = {
    'FIRST_FEATURE' : "first feature",
    'SECOND_FEATURE' : "second feature"
};

Useful information about property renaming:

https://developers.google.com/closure/compiler/docs/api-tutorial3

https://github.com/google/closure-compiler/wiki/FAQ#some-of-my-properties-are-getting-renamed-but-some-arent-why

Upvotes: 4

Duncan
Duncan

Reputation: 1550

The Closure Compiler has JavaDoc style markup...
Here's the page referencing the markups: Annotating JavaScript for the Closure Compiler
To retain a field name, place /** @expose */ before the field declaration.

my.namespace.FEATURES = {
    /**@expose*/
    FIRST_FEATURE: "first feature",
    /**@expose*/
    SECOND_FEATURE: "second feature"
};

... if you need to retain the namespace, it's the same concept...

/**@expose*/
my = my || {};
/**@expose*/
my.namespace = my.namespace || {};
/**@expose*/
my.namespace.FEATURES = {
    /**@expose*/
    FIRST_FEATURE: "first feature",
    /**@expose*/
    SECOND_FEATURE: "second feature"
};

In addition to retaining the filed name, it also allows you to reference that field using dot-notation later in your code. Using obj["field"], the compiler will lose the reference if you call it with obj.field later instead of having to use strings.

Upvotes: 5

jfriend00
jfriend00

Reputation: 707328

Exporting is there for a reason - as a directive to the Closure library that this is used by outside agents so it should not be renamed. The sections here on exporting explain how you can force Closure to keep a symbol intact (with no renaming). You mostly just need to follow the directions here. There is nothing "dirty" about exporting. It is there for exactly what you need - to tell Closure that this symbol is used by an external agent and cannot be renamed.

The other trigger that can keep Closure from renaming a property is if it is accessed by a string like this:

var f = "FIRST_FEATURE";
my.namespace.FEATURES[f] = "first feature";

In that case Closure sees that your code is using strings to address a property and (since it never messes with string values) it realizes that it can't rename the FIRST_FEATURE property safely.

Upvotes: 2

Related Questions