@Test public void canUseModuleInternalTypedefsInJsDoc() { CompilerUtil compiler = createCompiler(path("foo.js")); compiler.compile( createSourceFile( path("foo.js"), "/** @typedef {{x: number}} */", "var Variable;", "", "/**", " * @param {Variable} a .", " * @param {Variable} b .", " * @return {Variable} .", " */", "exports.add = function(a, b) {", " return {x: a.x + b.x};", "};")); Scope scope = compiler.getCompiler().getTopScope(); Var var = scope.getVar("module$foo"); JSType type = var.getInitialValue().getJSType().toObjectType().getPropertyType("add"); assertTrue(type.isFunctionType()); JSDocInfo info = type.getJSDocInfo(); Node node = info.getTypeNodes().iterator().next(); assertTrue(node.isString()); assertEquals("$jscomp.scope.Variable", node.getString()); assertEquals("Variable", node.getProp(Node.ORIGINALNAME_PROP)); }
@Test public void savesOriginalTypeNameInJsDoc() { CompilerUtil compiler = createCompiler(path("foo.js")); compiler.compile( createSourceFile( path("foo.js"), "/** @constructor */", "var Builder = function(){};", "/** @return {!Builder} . */", "Builder.prototype.returnThis = function() { return this; };", "exports.Builder = Builder")); Scope scope = compiler.getCompiler().getTopScope(); Var var = scope.getVar("module$foo"); JSType type = var.getInitialValue().getJSType().findPropertyType("Builder"); assertTrue(type.isConstructor()); type = type.toObjectType().getTypeOfThis(); assertEquals("$jscomp.scope.Builder", type.toString()); type = type.toObjectType().getPropertyType("returnThis"); assertTrue(type.toString(), type.isFunctionType()); JSDocInfo info = type.getJSDocInfo(); assertNotNull(info); Node node = getOnlyElement(info.getTypeNodes()); assertEquals(Token.BANG, node.getType()); node = node.getFirstChild(); assertTrue(node.isString()); assertEquals("$jscomp.scope.Builder", node.getString()); assertEquals("Builder", node.getProp(Node.ORIGINALNAME_PROP)); }
@Test public void exportedInternalVarInheritsJsDocInfo() { CompilerUtil compiler = createCompiler(path("foo.js")); compiler.compile( createSourceFile( path("foo.js"), "/**", " * @constructor", " */", "var Greeter = function(){};", "/**", " * @param {string} name .", " * @return {string} .", " */", "Greeter.prototype.sayHi = function(name) {", " return 'Hello, ' + name;", "};", "", "exports.Greeter = Greeter")); JSType exportedGreeter = compiler .getCompiler() .getTopScope() .getVar("module$foo") .getType() .findPropertyType("Greeter"); assertTrue(exportedGreeter.isConstructor()); }
@Test public void canReferenceConstructorDefinedInTheGlobalScope() { CompilerUtil compiler = createCompiler(path("x/bar.js")); compiler.compile( createSourceFile(path("x/foo.js"), "/** @constructor */", "function Foo() {}"), createSourceFile( path("x/bar.js"), "/** @type {function(new: Foo)} */", "exports.Foo = Foo;")); Scope scope = compiler.getCompiler().getTopScope(); Var var = scope.getVar("module$x$bar"); JSType type = var.getInitialValue().getJSType().findPropertyType("Foo"); assertTrue(type.isConstructor()); type = type.toObjectType().getTypeOfThis(); assertEquals("Foo", type.toString()); }
@Test public void canReferenceConstructorExportedByAnotherModule() { CompilerUtil compiler = createCompiler(path("x/foo.js"), path("x/bar.js")); compiler.compile( createSourceFile(path("x/foo.js"), "/** @constructor */", "exports.Foo = function(){};"), createSourceFile( path("x/bar.js"), "var foo = require('./foo');", "/** @type {function(new: foo.Foo)} */", "exports.Foo = foo.Foo;")); Scope scope = compiler.getCompiler().getTopScope(); Var var = scope.getVar("module$x$bar"); JSType type = var.getInitialValue().getJSType().findPropertyType("Foo"); assertTrue(type.isConstructor()); type = type.toObjectType().getTypeOfThis(); assertEquals("module$x$foo.Foo", type.toString()); }
@Test public void canReferenceExportedTypeReferences() { CompilerUtil compiler = createCompiler(path("foo/bar.js"), path("foo/baz.js")); compiler.compile( createSourceFile(path("foo/bar.js"), "/** @constructor */", "exports.foo = function(){};"), createSourceFile( path("foo/baz.js"), "var bar = require('./bar');", "var foo = require('./bar').foo;", "/** @type {!bar.foo} */", "var a = new bar.foo();", "/** @type {!foo} */", "var b = new foo();")); assertThat(compiler.toSource()) .startsWith( lines( "var $jscomp = {};", "$jscomp.scope = {};", "var module$foo$bar = {};", "module$foo$bar.foo = function() {", "};", "var module$foo$baz = {};", "$jscomp.scope.a = new module$foo$bar.foo;", "$jscomp.scope.b = new module$foo$bar.foo;")); ObjectType scope = compiler .getCompiler() .getTopScope() .getVar("$jscomp") .getType() .findPropertyType("scope") .toObjectType(); assertEquals("module$foo$bar.foo", scope.getPropertyType("a").getDisplayName()); assertEquals("module$foo$bar.foo", scope.getPropertyType("b").getDisplayName()); }