We’ve discussed this in the past.

Basically:
Before this option, all Object literals and Object access were being renamed by 
the Google Closure compiler. This caused untyped object references to be very 
fragile and tend to break when the code is minimized.

This option changes all unknown references to quoted references. This means 
object literals will have property names quoted (i.e. {“name”:”Harbs”} instead 
of {name:”Harbs”} and foo[“name”] instead of foo.name. This is the recommended 
practice by Google when renaming properties might have unwanted consequences. 
https://developers.google.com/closure/compiler/docs/api-tutorial3 
<https://developers.google.com/closure/compiler/docs/api-tutorial3>

The downside of this change is that Objects might be minimized less than 
without this option. But it’s much safer. Another downside is that it 
encourages users to use Object.

I spent many hours quoting object literals due to minimizing bugs. I expect 
this to be a pain point for lots of others too.

Harbs

> On Jun 27, 2018, at 10:57 PM, Carlos Rovira <[email protected]> wrote:
> 
> Hi
> 
> sorry, but I'd like to know more about this. I'm curious, what does this
> change?
> thanks! :)
> 
> 2018-06-27 15:55 GMT+02:00 Harbs <[email protected]>:
> 
>> Thanks for this Josh!
>> 
>> I just tested this on a very complex library project with crazy complex
>> untyped data structures. It works great!
>> 
>> I wish we had this option when I was working on my app. I spent many hours
>> chasing down minification issues that could have been fixed by this option.
>> 
>> I also think it should default to true.
>> 
>> Thanks,
>> Harbs
>> 
>>> On Jun 26, 2018, at 9:56 PM, [email protected] wrote:
>>> 
>>> This is an automated email from the ASF dual-hosted git repository.
>>> 
>>> joshtynjala pushed a commit to branch develop
>>> in repository https://gitbox.apache.org/repos/asf/royale-compiler.git
>>> 
>>> 
>>> The following commit(s) were added to refs/heads/develop by this push:
>>>    new 48d86c8  compiler-jx: added js-dynamic-access-unknown-members
>> compiler option to have emitter use dynamic bracket access when the right
>> side of a member access expression cannot be resolved to a definition.
>>> 48d86c8 is described below
>>> 
>>> commit 48d86c8c4b235ce60b282ad16d62d4ff87c3746b
>>> Author: Josh Tynjala <[email protected]>
>>> AuthorDate: Tue Jun 26 11:55:56 2018 -0700
>>> 
>>>   compiler-jx: added js-dynamic-access-unknown-members compiler option
>> to have emitter use dynamic bracket access when the right side of a member
>> access expression cannot be resolved to a definition.
>>> 
>>>   In other words, myObj.dynamicMember will become
>> myObj['dynamicMember']. Known members will use the regular dot syntax.
>> Useful for stopping the Closure compiler from renaming members that are
>> dynamic, such as members of an object literal. Defaults to false to avoid
>> breaking anything. However, I think it makes sense to have it default to
>> true instead to give developers a better user experience.
>>> ---
>>> .../royale/compiler/clients/JSConfiguration.java   | 26 ++++++++
>>> .../codegen/js/jx/MemberAccessEmitter.java         | 47 +++++++++++---
>>> .../js/royale/TestDynamicAccessUnknownMembers.java | 71
>> ++++++++++++++++++++++
>>> 3 files changed, 137 insertions(+), 7 deletions(-)
>>> 
>>> diff --git 
>>> a/compiler-jx/src/main/java/org/apache/royale/compiler/clients/JSConfiguration.java
>> b/compiler-jx/src/main/java/org/apache/royale/compiler/
>> clients/JSConfiguration.java
>>> index 0e6caf5..5433608 100644
>>> --- a/compiler-jx/src/main/java/org/apache/royale/compiler/
>> clients/JSConfiguration.java
>>> +++ b/compiler-jx/src/main/java/org/apache/royale/compiler/
>> clients/JSConfiguration.java
>>> @@ -137,6 +137,32 @@ public class JSConfiguration extends Configuration
>>>    }
>>> 
>>>    //
>>> +    // 'js-dynamic-access-unknown-members'
>>> +    //
>>> +
>>> +    private boolean jsDynamicAccessUnknownMembers = false;
>>> +
>>> +    public boolean getJsDynamicAccessUnknownMembers()
>>> +    {
>>> +        return jsDynamicAccessUnknownMembers;
>>> +    }
>>> +
>>> +    /**
>>> +     * If the definition of a member cannot be resolved, emit dynamic
>> access
>>> +     * instead of normal member access. Ensures that dynamic members
>> aren't
>>> +     * renamed.
>>> +     *
>>> +     * <code>myObject.memberAccess</code> becomes
>> <code>myObject["memberAccess"]</code>
>>> +     */
>>> +    @Config
>>> +    @Mapping("js-dynamic-access-unknown-members")
>>> +    public void setJsDynamicAccessUnknownMembers(ConfigurationValue
>> cv, boolean value)
>>> +            throws ConfigurationException
>>> +    {
>>> +        jsDynamicAccessUnknownMembers = value;
>>> +    }
>>> +
>>> +    //
>>>    // 'compiler.js-external-library-path' option
>>>    //
>>> 
>>> diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/
>> internal/codegen/js/jx/MemberAccessEmitter.java
>> b/compiler-jx/src/main/java/org/apache/royale/compiler/
>> internal/codegen/js/jx/MemberAccessEmitter.java
>>> index d308d34..b7a577c 100644
>>> --- a/compiler-jx/src/main/java/org/apache/royale/compiler/
>> internal/codegen/js/jx/MemberAccessEmitter.java
>>> +++ b/compiler-jx/src/main/java/org/apache/royale/compiler/
>> internal/codegen/js/jx/MemberAccessEmitter.java
>>> @@ -32,12 +32,14 @@ import org.apache.royale.compiler.
>> internal.codegen.js.goog.JSGoogEmitterTokens;
>>> import org.apache.royale.compiler.internal.codegen.js.jx.
>> BinaryOperatorEmitter.DatePropertiesGetters;
>>> import org.apache.royale.compiler.internal.definitions.
>> AccessorDefinition;
>>> import org.apache.royale.compiler.internal.definitions.
>> FunctionDefinition;
>>> +import org.apache.royale.compiler.internal.projects.RoyaleJSProject;
>>> import org.apache.royale.compiler.internal.tree.as.DynamicAccessNode;
>>> import org.apache.royale.compiler.internal.tree.as.FunctionCallNode;
>>> import org.apache.royale.compiler.internal.tree.as.GetterNode;
>>> import org.apache.royale.compiler.internal.tree.as.IdentifierNode;
>>> import org.apache.royale.compiler.internal.tree.as.
>> MemberAccessExpressionNode;
>>> import org.apache.royale.compiler.internal.tree.as.
>> NamespaceAccessExpressionNode;
>>> +import org.apache.royale.compiler.projects.ICompilerProject;
>>> import org.apache.royale.compiler.tree.ASTNodeID;
>>> import org.apache.royale.compiler.tree.as.IASNode;
>>> import org.apache.royale.compiler.tree.as.IExpressionNode;
>>> @@ -255,17 +257,48 @@ public class MemberAccessEmitter extends
>> JSSubEmitter implements
>>>                      getEmitter().emitClosureStart();
>>> 
>>>              continueWalk = writeLeftSide(node, leftNode, rightNode);
>>> -            if (continueWalk && !isCustomNamespace)
>>> -            {
>>> -                startMapping(node, node.getLeftOperandNode());
>>> -                write(node.getOperator().getOperatorText());
>>> -                endMapping(node);
>>> -            }
>>>        }
>>> 
>>>        if (continueWalk)
>>>        {
>>> -            getWalker().walk(node.getRightOperandNode());
>>> +                     boolean emitDynamicAccess = false;
>>> +            boolean dynamicAccessUnknownMembers = false;
>>> +            ICompilerProject project = getProject();
>>> +            if(project instanceof RoyaleJSProject)
>>> +            {
>>> +                RoyaleJSProject fjsProject = (RoyaleJSProject) project;
>>> +                if(fjsProject.config != null)
>>> +                {
>>> +                    dynamicAccessUnknownMembers = fjsProject.config.
>> getJsDynamicAccessUnknownMembers();
>>> +                }
>>> +            }
>>> +                     if (dynamicAccessUnknownMembers && rightNode
>> instanceof IIdentifierNode)
>>> +                     {
>>> +                             IIdentifierNode identifierNode =
>> (IIdentifierNode) node.getRightOperandNode();
>>> +                             IDefinition resolvedDefinition =
>> identifierNode.resolve(getProject());
>>> +                             emitDynamicAccess = resolvedDefinition ==
>> null;
>>> +                     }
>>> +                     if (emitDynamicAccess)
>>> +                     {
>>> +                             IIdentifierNode identifierNode =
>> (IIdentifierNode) node.getRightOperandNode();
>>> +                             startMapping(node, rightNode);
>>> +                             write(ASEmitterTokens.SQUARE_OPEN);
>>> +                             write(ASEmitterTokens.DOUBLE_QUOTE);
>>> +                             write(identifierNode.getName());
>>> +                             write(ASEmitterTokens.DOUBLE_QUOTE);
>>> +                             write(ASEmitterTokens.SQUARE_CLOSE);
>>> +                             endMapping(node);
>>> +                     }
>>> +                     else
>>> +                     {
>>> +                             if (!isStatic && !isCustomNamespace)
>>> +                             {
>>> +                                     startMapping(node,
>> node.getLeftOperandNode());
>>> +                                     write(node.getOperator().
>> getOperatorText());
>>> +                                     endMapping(node);
>>> +                             }
>>> +                             getWalker().walk(node.
>> getRightOperandNode());
>>> +                     }
>>>        }
>>> 
>>>        if (needClosure)
>>> diff --git a/compiler-jx/src/test/java/org/apache/royale/compiler/
>> internal/codegen/js/royale/TestDynamicAccessUnknownMembers.java
>> b/compiler-jx/src/test/java/org/apache/royale/compiler/
>> internal/codegen/js/royale/TestDynamicAccessUnknownMembers.java
>>> new file mode 100644
>>> index 0000000..64e5413
>>> --- /dev/null
>>> +++ b/compiler-jx/src/test/java/org/apache/royale/compiler/
>> internal/codegen/js/royale/TestDynamicAccessUnknownMembers.java
>>> @@ -0,0 +1,71 @@
>>> +/*
>>> + *
>>> + *  Licensed to the Apache Software Foundation (ASF) under one or more
>>> + *  contributor license agreements.  See the NOTICE file distributed
>> with
>>> + *  this work for additional information regarding copyright ownership.
>>> + *  The ASF licenses this file to You under the Apache License, Version
>> 2.0
>>> + *  (the "License"); you may not use this file except in compliance with
>>> + *  the License.  You may obtain a copy of the License at
>>> + *
>>> + *      http://www.apache.org/licenses/LICENSE-2.0
>>> + *
>>> + *  Unless required by applicable law or agreed to in writing, software
>>> + *  distributed under the License is distributed on an "AS IS" BASIS,
>>> + *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
>> implied.
>>> + *  See the License for the specific language governing permissions and
>>> + *  limitations under the License.
>>> + *
>>> + */
>>> +
>>> +package org.apache.royale.compiler.internal.codegen.js.royale;
>>> +
>>> +import org.apache.royale.compiler.driver.IBackend;
>>> +import org.apache.royale.compiler.exceptions.ConfigurationException;
>>> +import org.apache.royale.compiler.internal.driver.js.goog.
>> JSGoogConfiguration;
>>> +import org.apache.royale.compiler.internal.driver.js.royale.
>> RoyaleBackend;
>>> +import org.apache.royale.compiler.internal.projects.RoyaleJSProject;
>>> +import org.apache.royale.compiler.internal.test.ASTestBase;
>>> +import org.apache.royale.compiler.tree.as.IMemberAccessExpressionNode;
>>> +import org.junit.Test;
>>> +
>>> +public class TestDynamicAccessUnknownMembers extends ASTestBase
>>> +{
>>> +    @Override
>>> +    public void setUp()
>>> +    {
>>> +        backend = createBackend();
>>> +        project = new RoyaleJSProject(workspace, backend);
>>> +     JSGoogConfiguration config = new JSGoogConfiguration();
>>> +     try {
>>> +                     config.setJsDynamicAccessUnknownMembers(null,
>> true);
>>> +             } catch (ConfigurationException e) {
>>> +                     // TODO Auto-generated catch block
>>> +                     e.printStackTrace();
>>> +             }
>>> +     project.config = config;
>>> +        super.setUp();
>>> +     }
>>> +
>>> +    protected IBackend createBackend()
>>> +    {
>>> +        return new RoyaleBackend();
>>> +    }
>>> +
>>> +    @Test
>>> +     public void testVisitKnownMember()
>>> +    {
>>> +        IMemberAccessExpressionNode node =
>> (IMemberAccessExpressionNode) getNode(
>>> +                "public class KnownMember { public function
>> KnownMember() { this.knownMember = 4; } public var knownMember:Number; }",
>> IMemberAccessExpressionNode.class, WRAP_LEVEL_PACKAGE);
>>> +        asBlockWalker.visitMemberAccessExpression(node);
>>> +        assertOut("this.knownMember");
>>> +    }
>>> +
>>> +    @Test
>>> +     public void testVisitUnknownMember()
>>> +    {
>>> +        IMemberAccessExpressionNode node =
>> (IMemberAccessExpressionNode) getNode(
>>> +                "public dynamic class KnownMember { public function
>> UnknownMember() { this.unknownMember = 4; } public var knownMember:Number;
>> }", IMemberAccessExpressionNode.class, WRAP_LEVEL_PACKAGE);
>>> +        asBlockWalker.visitMemberAccessExpression(node);
>>> +        assertOut("this[\"unknownMember\"]");
>>> +    }
>>> +}
>>> \ No newline at end of file
>>> 
>> 
>> 
> 
> 
> -- 
> Carlos Rovira
> http://about.me/carlosrovira

Reply via email to