Skip to content

Commit

Permalink
Make PolymerClassRewriter insert new nodes in MODULE_BODY nodes, not …
Browse files Browse the repository at this point in the history
…SCRIPTs

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=246018077
  • Loading branch information
lauraharker authored and blickly committed Apr 30, 2019
1 parent 2d5bbb1 commit e12413f
Show file tree
Hide file tree
Showing 3 changed files with 140 additions and 19 deletions.
2 changes: 1 addition & 1 deletion src/com/google/javascript/jscomp/ModuleImportResolver.java
Expand Up @@ -41,7 +41,7 @@ final class ModuleImportResolver {
} }


/** Returns whether this is a CALL node for goog.require(Type) or goog.forwardDeclare */ /** Returns whether this is a CALL node for goog.require(Type) or goog.forwardDeclare */
boolean isGoogModuleDependencyCall(Node value) { static boolean isGoogModuleDependencyCall(Node value) {
if (value == null || !value.isCall()) { if (value == null || !value.isCall()) {
return false; return false;
} }
Expand Down
45 changes: 33 additions & 12 deletions src/com/google/javascript/jscomp/PolymerClassRewriter.java
Expand Up @@ -73,9 +73,10 @@ final class PolymerClassRewriter {
* @param exprRoot The root expression of the call to Polymer({}). * @param exprRoot The root expression of the call to Polymer({}).
* @param cls The extracted {@link PolymerClassDefinition} for the Polymer element created by this * @param cls The extracted {@link PolymerClassDefinition} for the Polymer element created by this
* call. * call.
* @param isInGlobalOrModuleScope whether this call is either directly in a script or module body
*/ */
void rewritePolymerCall( void rewritePolymerCall(
Node exprRoot, final PolymerClassDefinition cls, boolean isInGlobalScope) { Node exprRoot, final PolymerClassDefinition cls, boolean isInGlobalOrModuleScope) {
Node objLit = checkNotNull(cls.descriptor); Node objLit = checkNotNull(cls.descriptor);


// Add {@code @lends} to the object literal. // Add {@code @lends} to the object literal.
Expand Down Expand Up @@ -135,17 +136,22 @@ void rewritePolymerCall(
Node statements = block.removeChildren(); Node statements = block.removeChildren();
Node parent = exprRoot.getParent(); Node parent = exprRoot.getParent();


// If the call to Polymer() is not in the global scope and the assignment target // Put the type declaration in to either the enclosing module scope, if in a module, or the
// is not namespaced (which likely means it's exported to the global scope), put the type // enclosing script node. Compiler support for local scopes like IIFEs is sometimes lacking but
// declaration into the global scope at the start of the current script. // module scopes are well-supported. If this is not in a module or the global scope it is likely
// // exported.
// This avoids unknown type warnings which are a result of the compiler's poor understanding of if (!isInGlobalOrModuleScope && !cls.target.isGetProp()) {
// types declared inside IIFEs or any non-global scope. We should revisit this decision as Node scriptOrModuleNode =
// the typechecker's support for non-global types improves. NodeUtil.getEnclosingNode(parent, node -> node.isScript() || node.isModuleBody());
if (!isInGlobalScope && !cls.target.isGetProp()) { if (scriptOrModuleNode.isModuleBody()
Node scriptNode = NodeUtil.getEnclosingScript(parent); && scriptOrModuleNode.getParent().getBooleanProp(Node.GOOG_MODULE)) {
scriptNode.addChildrenToFront(statements); // The goog.module('ns'); call must remain the first statement in the module.
compiler.reportChangeToChangeScope(scriptNode); Node insertionPoint = getInsertionPointForGoogModule(scriptOrModuleNode);
scriptOrModuleNode.addChildrenAfter(statements, insertionPoint);
} else {
scriptOrModuleNode.addChildrenToFront(statements);
compiler.reportChangeToChangeScope(NodeUtil.getEnclosingScript(scriptOrModuleNode));
}
} else { } else {
Node beforeRoot = exprRoot.getPrevious(); Node beforeRoot = exprRoot.getPrevious();
if (beforeRoot == null) { if (beforeRoot == null) {
Expand Down Expand Up @@ -988,4 +994,19 @@ private static boolean isParamLiteral(String param) {
} }
return false; return false;
} }

private static Node getInsertionPointForGoogModule(Node moduleBody) {
checkArgument(moduleBody.isModuleBody(), moduleBody);
Node insertionPoint = moduleBody.getFirstChild(); // goog.module('ns');
Node next = insertionPoint.getNext();
while ((NodeUtil.isNameDeclaration(next)
&& next.hasOneChild()
&& ModuleImportResolver.isGoogModuleDependencyCall(next.getFirstFirstChild()))
|| (NodeUtil.isExprCall(next)
&& ModuleImportResolver.isGoogModuleDependencyCall(next.getOnlyChild()))) {
insertionPoint = next;
next = next.getNext();
}
return insertionPoint;
}
} }
112 changes: 106 additions & 6 deletions test/com/google/javascript/jscomp/PolymerClassRewriterTest.java
Expand Up @@ -64,13 +64,15 @@ public final class PolymerClassRewriterTest extends CompilerTypeTestCase {
private Node rootNode; private Node rootNode;
private GlobalNamespace globalNamespace; private GlobalNamespace globalNamespace;
private Node polymerCall; private Node polymerCall;
private boolean inGlobalScope;


@Override @Override
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
super.setUp(); super.setUp();
polymerCall = null; polymerCall = null;
rootNode = null; rootNode = null;
inGlobalScope = true;
} }


// TODO(jlklein): Add tests for non-global definitions, interface externs, read-only setters, etc. // TODO(jlklein): Add tests for non-global definitions, interface externs, read-only setters, etc.
Expand Down Expand Up @@ -98,6 +100,103 @@ public void testVarTarget() {
"};")); "};"));
} }


@Test
public void testVarTarget_inGoogModule() {
inGlobalScope = false;
test(
lines(
"goog.module('mod');", //
"var X = Polymer({",
" is: 'x-element',",
"});"),
lines(
"goog.module('mod');",
"/** @constructor @extends {PolymerElement} @implements {PolymerXInterface} */",
"var X = function() {};",
"X = Polymer(/** @lends {X.prototype} */ {",
" is: 'x-element',",
"});"));

testSame(
lines(
"goog.module('mod');",
"var X = class extends Polymer.Element {",
" static get is() { return 'x-element'; }",
" static get properties { return { }; }",
"};"));
}

@Test
public void testVarTarget_inIifeInGoogModule() {
inGlobalScope = false;
test(
lines(
"goog.module('mod');", //
"(function() {",
" var X = Polymer({",
" is: 'x-element',",
" });",
"})();"),
lines(
"goog.module('mod');",
"/** @constructor @extends {PolymerElement} @implements {PolymerXInterface} */",
"var X = function() {};",
"(function() {",
" X = Polymer(/** @lends {X.prototype} */ {",
" is: 'x-element',",
" });",
"})();"));
}

@Test
public void testVarTarget_inGoogModuleWithRequires() {
inGlobalScope = false;
test(
lines(
"goog.module('mod');", //
"const Component = goog.require('goog.Component');",
"goog.forwardDeclare('something.else');",
"const someLocal = (function() { return 0; })();",
"var X = Polymer({",
" is: 'x-element',",
"});"),
lines(
"goog.module('mod');",
"const Component = goog.require('goog.Component');",
"goog.forwardDeclare('something.else');",
"/** @constructor @extends {PolymerElement} @implements {PolymerXInterface} */",
"var X = function() {};",
"const someLocal = (function() { return 0; })();",
"X = Polymer(/** @lends {X.prototype} */ {",
" is: 'x-element',",
"});"));
}

@Test
public void testVarTarget_inEsModule() {
test(
lines(
"var X = Polymer({", //
" is: 'x-element',",
"});",
"export {X};"),
lines(
"/** @constructor @extends {PolymerElement} @implements {PolymerXInterface} */",
"var X = function() {};",
"X = Polymer(/** @lends {X.prototype} */ {",
" is: 'x-element',",
"});",
"export {X};"));

testSame(
lines(
"var X = class extends Polymer.Element {",
" static get is() { return 'x-element'; }",
" static get properties { return { }; }",
"};",
"export {X};"));
}

@Test @Test
public void testDefaultTypeNameTarget() { public void testDefaultTypeNameTarget() {
test( test(
Expand Down Expand Up @@ -144,6 +243,7 @@ protected CompilerOptions getDefaultOptions() {
options.setWarningLevel( options.setWarningLevel(
DiagnosticGroups.INVALID_CASTS, CheckLevel.WARNING); DiagnosticGroups.INVALID_CASTS, CheckLevel.WARNING);
options.setWarningLevel(DiagnosticGroups.LINT_CHECKS, CheckLevel.WARNING); options.setWarningLevel(DiagnosticGroups.LINT_CHECKS, CheckLevel.WARNING);
options.setWarningLevel(DiagnosticGroups.MODULE_LOAD, CheckLevel.OFF);
options.setCodingConvention(getCodingConvention()); options.setCodingConvention(getCodingConvention());
options.setPreserveTypeAnnotations(true); options.setPreserveTypeAnnotations(true);
options.setPrettyPrint(true); options.setPrettyPrint(true);
Expand All @@ -153,21 +253,21 @@ protected CompilerOptions getDefaultOptions() {
private void test(String originalCode, String expectedResult) { private void test(String originalCode, String expectedResult) {
parseAndRewrite(originalCode, 1); parseAndRewrite(originalCode, 1);
Node expectedNode = compiler.parseSyntheticCode(expectedResult); Node expectedNode = compiler.parseSyntheticCode(expectedResult);
assertNode(expectedNode).isEqualTo(rootNode); assertNode(rootNode).isEqualTo(expectedNode);


parseAndRewrite(originalCode, 2); parseAndRewrite(originalCode, 2);
expectedNode = compiler.parseSyntheticCode(expectedResult); expectedNode = compiler.parseSyntheticCode(expectedResult);
assertNode(expectedNode).isEqualTo(rootNode); assertNode(rootNode).isEqualTo(expectedNode);
} }


private void testSame(String originalCode) { private void testSame(String originalCode) {
parseAndRewrite(originalCode, 1); parseAndRewrite(originalCode, 1);
Node expectedNode = compiler.parseSyntheticCode(originalCode); Node expectedNode = compiler.parseSyntheticCode(originalCode);
assertNode(expectedNode).isEqualTo(rootNode); assertNode(rootNode).isEqualTo(expectedNode);


parseAndRewrite(originalCode, 2); parseAndRewrite(originalCode, 2);
expectedNode = compiler.parseSyntheticCode(originalCode); expectedNode = compiler.parseSyntheticCode(originalCode);
assertNode(expectedNode).isEqualTo(rootNode); assertNode(rootNode).isEqualTo(expectedNode);
} }


private void parseAndRewrite(String code, int version) { private void parseAndRewrite(String code, int version) {
Expand Down Expand Up @@ -203,9 +303,9 @@ public void visit(Node node) {
Node parent = polymerCall.getParent(); Node parent = polymerCall.getParent();
Node grandparent = parent.getParent(); Node grandparent = parent.getParent();
if (NodeUtil.isNameDeclaration(grandparent) || parent.isAssign()) { if (NodeUtil.isNameDeclaration(grandparent) || parent.isAssign()) {
rewriter.rewritePolymerCall(grandparent, classDef, true); rewriter.rewritePolymerCall(grandparent, classDef, inGlobalScope);
} else { } else {
rewriter.rewritePolymerCall(parent, classDef, true); rewriter.rewritePolymerCall(parent, classDef, inGlobalScope);
} }
} }


Expand Down

0 comments on commit e12413f

Please sign in to comment.