diff --git a/demo/package.json b/demo/package.json
index 0bd9d3e46..3c13d5def 100644
--- a/demo/package.json
+++ b/demo/package.json
@@ -8,7 +8,7 @@
"dependencies": {
"minimist": "^1.2.3",
"tsickle": "file:../",
- "typescript": "5.2.2"
+ "typescript": "5.3.2"
},
"devDependencies": {
"@types/minimist": "1.2.0",
diff --git a/package.json b/package.json
index b2f9930b5..3bbb1a402 100644
--- a/package.json
+++ b/package.json
@@ -11,7 +11,7 @@
"out/src/*"
],
"peerDependencies": {
- "typescript": "~5.1.5"
+ "typescript": "~5.3.2"
},
"devDependencies": {
"@types/diff-match-patch": "^1.0.32",
@@ -28,7 +28,7 @@
"source-map-support": "^0.5.19",
"tslib": "^2.2.0",
"tslint": "^6.1.3",
- "typescript": "5.2.2"
+ "typescript": "5.3.2"
},
"scripts": {
"build": "tsc",
diff --git a/src/clutz.ts b/src/clutz.ts
index 2e1a818e8..855abab58 100644
--- a/src/clutz.ts
+++ b/src/clutz.ts
@@ -21,6 +21,11 @@ import * as googmodule from './googmodule';
import * as path from './path';
import {isDeclaredInClutzDts} from './type_translator';
+interface ClutzHost {
+ /** See compiler_host.ts */
+ rootDirsRelative(fileName: string): string;
+}
+
/**
* Constructs a ts.CustomTransformerFactory that postprocesses the .d.ts
* that are generated by ordinary TypeScript compilations to add some
@@ -28,8 +33,7 @@ import {isDeclaredInClutzDts} from './type_translator';
*/
export function makeDeclarationTransformerFactory(
typeChecker: ts.TypeChecker,
- googmoduleHost: googmodule.GoogModuleProcessorHost):
- ts.CustomTransformerFactory {
+ host: ClutzHost&googmodule.GoogModuleProcessorHost): ts.CustomTransformerFactory {
return (context: ts.TransformationContext): ts.CustomTransformer => {
return {
transformBundle(): ts.Bundle {
@@ -49,8 +53,7 @@ export function makeDeclarationTransformerFactory(
// import 'path/to/the/js_file';
// so to for that import to resolve, you need to first import the clutz
// d.ts that defines that declared module.
- const imports =
- gatherNecessaryClutzImports(googmoduleHost, typeChecker, file);
+ const imports = gatherNecessaryClutzImports(host, typeChecker, file);
let importStmts: ts.Statement[]|undefined;
if (imports.length > 0) {
importStmts = imports.map(fileName => {
@@ -66,22 +69,56 @@ export function makeDeclarationTransformerFactory(
// Construct `declare global {}` in the Clutz namespace for symbols
// Clutz might use.
const globalBlock = generateClutzAliases(
- file, googmoduleHost.pathToModuleName('', file.fileName),
- typeChecker, options);
+ file, host.pathToModuleName('', file.fileName), typeChecker,
+ options);
// Only need to transform file if we needed one of the above additions.
if (!importStmts && !globalBlock) return file;
- return ts.factory.updateSourceFile(file, [
- ...(importStmts ?? []),
- ...file.statements,
- ...(globalBlock ? [globalBlock] : []),
- ]);
+ return ts.factory.updateSourceFile(
+ file,
+ ts.setTextRange(
+ ts.factory.createNodeArray([
+ ...(importStmts ?? []),
+ ...file.statements,
+ ...(globalBlock ? [globalBlock] : []),
+ ]),
+ file.statements),
+ file.isDeclarationFile,
+ file.referencedFiles.map(
+ f => fixRelativeReference(f, file, options, host)),
+ // /// directives are ignored under bazel.
+ /*typeReferences=*/[]);
}
};
};
}
+/**
+ * Fixes a relative reference from an output file with respect to multiple
+ * rootDirs. See https://github.com/Microsoft/TypeScript/issues/8245 for
+ * details.
+ */
+function fixRelativeReference(
+ reference: ts.FileReference, origin: ts.SourceFile,
+ options: ts.CompilerOptions, host: ClutzHost): ts.FileReference {
+ if (!options.outDir || !options.rootDir) {
+ return reference;
+ }
+ const originDir = path.dirname(origin.fileName);
+ // Where TypeScript expects the output to be.
+ const expectedOutDir =
+ path.join(options.outDir, path.relative(options.rootDir, originDir));
+ const referencedFile = path.join(expectedOutDir, reference.fileName);
+ // Where the output is actually emitted.
+ const actualOutDir =
+ path.join(options.outDir, host.rootDirsRelative(originDir));
+ const fixedReference = path.relative(actualOutDir, referencedFile);
+
+ reference.fileName = fixedReference;
+ return reference;
+}
+
/** Compares two strings and returns a number suitable for use in sort(). */
function stringCompare(a: string, b: string): number {
if (a < b) return -1;
diff --git a/src/decorators.ts b/src/decorators.ts
index fb8523ad1..57e6e6903 100644
--- a/src/decorators.ts
+++ b/src/decorators.ts
@@ -98,7 +98,7 @@ export function transformDecoratorsOutputForClosurePropertyRenaming(diagnostics:
return (context: ts.TransformationContext) => {
const result: ts.Transformer = (sourceFile: ts.SourceFile) => {
let nodeNeedingGoogReflect: undefined|ts.Node = undefined;
- const visitor: ts.Visitor = (node) => {
+ const visitor = (node: ts.Node) => {
const replacementNode = rewriteDecorator(node);
if (replacementNode) {
nodeNeedingGoogReflect = node;
@@ -107,9 +107,7 @@ export function transformDecoratorsOutputForClosurePropertyRenaming(diagnostics:
return ts.visitEachChild(node, visitor, context);
};
let updatedSourceFile =
- // TODO: go/ts50upgrade - Remove after upgrade.
- // tslint:disable-next-line:no-unnecessary-type-assertion
- ts.visitNode(sourceFile, visitor, ts.isSourceFile)!;
+ ts.visitNode(sourceFile, visitor, ts.isSourceFile);
if (nodeNeedingGoogReflect !== undefined) {
const statements = [...updatedSourceFile.statements];
const googModuleIndex = statements.findIndex(isGoogModuleStatement);
diff --git a/src/enum_transformer.ts b/src/enum_transformer.ts
index 812b4fff0..4b7869bdd 100644
--- a/src/enum_transformer.ts
+++ b/src/enum_transformer.ts
@@ -19,6 +19,7 @@
* type resolve ("@type {Foo}").
*/
+import {TsickleHost} from 'tsickle';
import * as ts from 'typescript';
import * as jsdoc from './jsdoc';
@@ -95,7 +96,7 @@ export function getEnumType(typeChecker: ts.TypeChecker, enumDecl: ts.EnumDeclar
/**
* Transformer factory for the enum transformer. See fileoverview for details.
*/
-export function enumTransformer(typeChecker: ts.TypeChecker):
+export function enumTransformer(host: TsickleHost, typeChecker: ts.TypeChecker):
(context: ts.TransformationContext) => ts.Transformer {
return (context: ts.TransformationContext) => {
function visitor(node: T): T|ts.Node[] {
@@ -180,7 +181,11 @@ export function enumTransformer(typeChecker: ts.TypeChecker):
/* modifiers */ undefined,
ts.factory.createVariableDeclarationList(
[varDecl],
- /* create a const var */ ts.NodeFlags.Const)),
+ /* When using unoptimized namespaces, create a var
+ declaration, otherwise create a const var. See b/157460535 */
+ host.useDeclarationMergingTransformation ?
+ ts.NodeFlags.Const :
+ undefined)),
node),
node);
diff --git a/src/externs.ts b/src/externs.ts
index a30f6caf0..cae60d17d 100644
--- a/src/externs.ts
+++ b/src/externs.ts
@@ -295,24 +295,13 @@ export function generateExterns(
* interface Foo { x: number; }
* interface Foo { y: number; }
* we only want to emit the "\@record" for Foo on the first one.
- *
- * The exception are variable declarations, which - in externs - do not assign a value:
- * /.. \@type {...} ./
- * var someVariable;
- * /.. \@type {...} ./
- * someNamespace.someVariable;
- * If a later declaration wants to add additional properties on someVariable, tsickle must still
- * emit an assignment into the object, as it's otherwise absent.
*/
function isFirstValueDeclaration(decl: ts.DeclarationStatement): boolean {
if (!decl.name) return true;
const sym = typeChecker.getSymbolAtLocation(decl.name)!;
if (!sym.declarations || sym.declarations.length < 2) return true;
const earlierDecls = sym.declarations.slice(0, sym.declarations.indexOf(decl));
- // Either there are no earlier declarations, or all of them are variables (see above). tsickle
- // emits a value for all other declaration kinds (function for functions, classes, interfaces,
- // {} object for namespaces).
- return earlierDecls.length === 0 || earlierDecls.every(ts.isVariableDeclaration);
+ return earlierDecls.length === 0 || earlierDecls.every(d => ts.isVariableDeclaration(d) && d.getSourceFile() !== decl.getSourceFile());
}
/** Writes the actual variable statement of a Closure variable declaration. */
diff --git a/src/googmodule.ts b/src/googmodule.ts
index bf6e6d91b..fce705bec 100644
--- a/src/googmodule.ts
+++ b/src/googmodule.ts
@@ -29,11 +29,9 @@ export interface GoogModuleProcessorHost {
* Takes the import URL of an ES6 import and returns the googmodule module
* name for the imported module, iff the module is an original closure
* JavaScript file.
- *
- * Warning: If this function is present, GoogModule won't produce diagnostics
- * for multiple provides.
*/
- jsPathToModuleName?(importPath: string): string|undefined;
+ jsPathToModuleName?
+ (importPath: string): {name: string, multipleProvides: boolean}|undefined;
/**
* Takes the import URL of an ES6 import and returns the property name that
* should be stripped from the usage.
@@ -89,7 +87,8 @@ export function jsPathToNamespace(
host: GoogModuleProcessorHost, context: ts.Node,
diagnostics: ts.Diagnostic[], importPath: string,
getModuleSymbol: () => ts.Symbol | undefined): string|undefined {
- const namespace = localJsPathToNamespace(host, importPath);
+ const namespace =
+ localJsPathToNamespace(host, context, diagnostics, importPath);
if (namespace) return namespace;
const moduleSymbol = getModuleSymbol();
@@ -105,7 +104,8 @@ export function jsPathToNamespace(
* Forwards to `jsPathToModuleName` on the host if present.
*/
export function localJsPathToNamespace(
- host: GoogModuleProcessorHost, importPath: string): string|undefined {
+ host: GoogModuleProcessorHost, context: ts.Node|undefined,
+ diagnostics: ts.Diagnostic[], importPath: string): string|undefined {
if (importPath.match(/^goog:/)) {
// This is a namespace import, of the form "goog:foo.bar".
// Fix it to just "foo.bar".
@@ -113,7 +113,12 @@ export function localJsPathToNamespace(
}
if (host.jsPathToModuleName) {
- return host.jsPathToModuleName(importPath);
+ const module = host.jsPathToModuleName(importPath);
+ if (!module) return undefined;
+ if (module.multipleProvides) {
+ reportMultipleProvidesError(context, diagnostics, importPath);
+ }
+ return module.name;
}
return undefined;
@@ -394,10 +399,7 @@ function getGoogNamespaceFromClutzComments(
findLocalInDeclarations(moduleSymbol, '__clutz_multiple_provides');
if (hasMultipleProvides) {
// Report an error...
- reportDiagnostic(
- tsickleDiagnostics, context,
- `referenced JavaScript module ${
- tsImport} provides multiple namespaces and cannot be imported by path.`);
+ reportMultipleProvidesError(context, tsickleDiagnostics, tsImport);
// ... but continue producing an emit that effectively references the first
// provided symbol (to continue finding any additional errors).
}
@@ -411,6 +413,15 @@ function getGoogNamespaceFromClutzComments(
return actualNamespace;
}
+function reportMultipleProvidesError(
+ context: ts.Node|undefined, diagnostics: ts.Diagnostic[],
+ importPath: string) {
+ reportDiagnostic(
+ diagnostics, context,
+ `referenced JavaScript module ${
+ importPath} provides multiple namespaces and cannot be imported by path.`);
+}
+
/**
* Converts a TS/ES module './import/path' into a goog.module compatible
* namespace, handling regular imports and `goog:` namespace imports.
@@ -446,27 +457,6 @@ function rewriteModuleExportsAssignment(expr: ts.ExpressionStatement) {
expr);
}
-/**
- * Checks whether expr is of the form `exports.abc = identifier` and if so,
- * returns the string abc, otherwise returns null.
- */
-function isExportsAssignment(expr: ts.Expression): string|null {
- // Verify this looks something like `exports.abc = ...`.
- if (!ts.isBinaryExpression(expr)) return null;
- if (expr.operatorToken.kind !== ts.SyntaxKind.EqualsToken) return null;
-
- // Verify the left side of the expression is an access on `exports`.
- if (!ts.isPropertyAccessExpression(expr.left)) return null;
- if (!ts.isIdentifier(expr.left.expression)) return null;
- if (expr.left.expression.escapedText !== 'exports') return null;
-
- // Check whether right side of assignment is an identifier.
- if (!ts.isIdentifier(expr.right)) return null;
-
- // Return the property name as string.
- return expr.left.name.escapedText.toString();
-}
-
/**
* Convert a series of comma-separated expressions
* x = foo, y(), z.bar();
@@ -976,13 +966,19 @@ export function commonJsToGoogmoduleTransformer(
// onSubstituteNode callback.
ts.setEmitFlags(arg.right.expression, ts.EmitFlags.NoSubstitution);
- // Namespaces can merge with classes and functions. TypeScript emits
- // separate exports assignments for those. Don't emit extra ones here.
+ // Namespaces can merge with classes and functions and TypeScript emits
+ // separate exports assignments for those already. No need to add an
+ // extra one.
+ // The same is true for enums, but only if they have been transformed
+ // to closure enums.
const notAlreadyExported = matchingExports.filter(
decl => !ts.isClassDeclaration(
decl.declarationSymbol.valueDeclaration) &&
!ts.isFunctionDeclaration(
- decl.declarationSymbol.valueDeclaration));
+ decl.declarationSymbol.valueDeclaration) &&
+ !(host.transformTypesToClosure &&
+ ts.isEnumDeclaration(
+ decl.declarationSymbol.valueDeclaration)));
const exportNames = notAlreadyExported.map(decl => decl.exportName);
return {
@@ -1147,7 +1143,6 @@ export function commonJsToGoogmoduleTransformer(
return exportStmt;
}
- const exportsSeen = new Set();
const seenNamespaceOrEnumExports = new Set();
/**
@@ -1245,53 +1240,27 @@ export function commonJsToGoogmoduleTransformer(
return;
}
- // Avoid EXPORT_REPEATED_ERROR from JSCompiler. Occurs for:
- // class Foo {}
- // namespace Foo { ... }
- // export {Foo};
- // TypeScript emits 2 separate exports assignments. One after the
- // class and one after the namespace.
- // TODO(b/277272562): TypeScript 5.1 changes how exports assignments
- // are emitted, making this no longer an issue. On the other hand
- // this is unsafe. We really need to keep the _last_ (not the first)
- // export assignment in the general case. Remove this check after
- // the 5.1 upgrade.
- const exportName = isExportsAssignment(exprStmt.expression);
- if (exportName) {
- if (exportsSeen.has(exportName)) {
- stmts.push(createNotEmittedStatementWithComments(sf, exprStmt));
- return;
- }
- exportsSeen.add(exportName);
- }
-
- // TODO(b/277272562): This code works in 5.1. But breaks in 5.0,
- // which emits separate exports assignments for namespaces and enums
- // and this code would emit duplicate exports assignments. Run this
- // unconditionally after 5.1 has been released.
- if ((ts.versionMajorMinor as string) !== '5.0') {
- // Check for inline exports assignments as they are emitted for
- // exported namespaces and enums, e.g.:
- // (function (Foo) {
- // })(Foo || (exports.Foo = exports.Bar = Foo = {}));
- // and moves the exports assignments to a separate statement.
- const exportInIifeArguments =
- maybeRewriteExportsAssignmentInIifeArguments(exprStmt);
- if (exportInIifeArguments) {
- stmts.push(exportInIifeArguments.statement);
- for (const newExport of exportInIifeArguments.exports) {
- const exportName = newExport.expression.left.name.text;
- // Namespaces produce multiple exports assignments when
- // they're re-opened in the same file. Only emit the first one
- // here. This is fine because the namespace object itself
- // cannot be re-assigned later.
- if (!seenNamespaceOrEnumExports.has(exportName)) {
- stmts.push(newExport);
- seenNamespaceOrEnumExports.add(exportName);
- }
+ // Check for inline exports assignments as they are emitted for
+ // exported namespaces and enums, e.g.:
+ // (function (Foo) {
+ // })(Foo || (exports.Foo = exports.Bar = Foo = {}));
+ // and moves the exports assignments to a separate statement.
+ const exportInIifeArguments =
+ maybeRewriteExportsAssignmentInIifeArguments(exprStmt);
+ if (exportInIifeArguments) {
+ stmts.push(exportInIifeArguments.statement);
+ for (const newExport of exportInIifeArguments.exports) {
+ const exportName = newExport.expression.left.name.text;
+ // Namespaces produce multiple exports assignments when
+ // they're re-opened in the same file. Only emit the first one
+ // here. This is fine because the namespace object itself
+ // cannot be re-assigned later.
+ if (!seenNamespaceOrEnumExports.has(exportName)) {
+ stmts.push(newExport);
+ seenNamespaceOrEnumExports.add(exportName);
}
- return;
}
+ return;
}
// Delay `exports.X = X` assignments for decorated classes.
@@ -1473,7 +1442,7 @@ export function commonJsToGoogmoduleTransformer(
'requireDynamic', createSingleQuoteStringLiteral(imp));
}
- const visitForDynamicImport: ts.Visitor = (node) => {
+ const visitForDynamicImport = (node: ts.Node) => {
const replacementNode = rewriteDynamicRequire(node);
if (replacementNode) {
return replacementNode;
@@ -1482,9 +1451,7 @@ export function commonJsToGoogmoduleTransformer(
};
if (host.transformDynamicImport === 'closure') {
- // TODO: go/ts50upgrade - Remove after upgrade.
- // tslint:disable-next-line:no-unnecessary-type-assertion
- sf = ts.visitNode(sf, visitForDynamicImport, ts.isSourceFile)!;
+ sf = ts.visitNode(sf, visitForDynamicImport, ts.isSourceFile);
}
// Convert each top level statement to goog.module.
diff --git a/src/jsdoc_transformer.ts b/src/jsdoc_transformer.ts
index 6e3e5119b..5775b2b9a 100644
--- a/src/jsdoc_transformer.ts
+++ b/src/jsdoc_transformer.ts
@@ -827,8 +827,6 @@ export function jsdocTransformer(
const updatedBinding = renameArrayBindings(decl.name, aliases);
if (updatedBinding && aliases.length > 0) {
const declVisited =
- // TODO: go/ts50upgrade - Remove after upgrade.
- // tslint:disable-next-line:no-unnecessary-type-assertion
ts.visitNode(decl, visitor, ts.isVariableDeclaration)!;
const newDecl = ts.factory.updateVariableDeclaration(
declVisited, updatedBinding, declVisited.exclamationToken,
@@ -846,10 +844,9 @@ export function jsdocTransformer(
continue;
}
}
- const newDecl =
- // TODO: go/ts50upgrade - Remove after upgrade.
- // tslint:disable-next-line:no-unnecessary-type-assertion
- ts.visitNode(decl, visitor, ts.isVariableDeclaration)!;
+ const newDecl = ts.setEmitFlags(
+ ts.visitNode(decl, visitor, ts.isVariableDeclaration)!,
+ ts.EmitFlags.NoComments);
const newStmt = ts.factory.createVariableStatement(
varStmt.modifiers,
ts.factory.createVariableDeclarationList([newDecl], flags));
@@ -1322,8 +1319,6 @@ export function jsdocTransformer(
e, e.dotDotDotToken,
ts.visitNode(e.propertyName, visitor, ts.isPropertyName),
updatedBindingName,
- // TODO: go/ts50upgrade - Remove after upgrade.
- // tslint:disable-next-line:no-unnecessary-type-assertion
ts.visitNode(e.initializer, visitor) as ts.Expression));
}
return ts.factory.updateArrayBindingPattern(node, updatedElements);
@@ -1406,22 +1401,15 @@ export function jsdocTransformer(
if (ts.isBlock(node.statement)) {
updatedStatement = ts.factory.updateBlock(node.statement, [
...aliasDecls,
- // TODO: go/ts50upgrade - Remove after upgrade.
- // tslint:disable-next-line:no-unnecessary-type-assertion
...ts.visitNode(node.statement, visitor, ts.isBlock)!.statements
]);
} else {
updatedStatement = ts.factory.createBlock([
- ...aliasDecls,
- // TODO: go/ts50upgrade - Remove after upgrade.
- // tslint:disable-next-line:no-unnecessary-type-assertion
- ts.visitNode(node.statement, visitor) as ts.Statement
+ ...aliasDecls, ts.visitNode(node.statement, visitor) as ts.Statement
]);
}
return ts.factory.updateForOfStatement(
node, node.awaitModifier, updatedInitializer,
- // TODO: go/ts50upgrade - Remove after upgrade.
- // tslint:disable-next-line:no-unnecessary-type-assertion
ts.visitNode(node.expression, visitor) as ts.Expression,
updatedStatement);
}
diff --git a/src/ns_transformer.ts b/src/ns_transformer.ts
index 67300c942..129c15a3d 100644
--- a/src/ns_transformer.ts
+++ b/src/ns_transformer.ts
@@ -72,8 +72,8 @@ export function namespaceTransformer(
// transformation fails.
function transformNamespace(
ns: ts.ModuleDeclaration,
- mergedDecl: ts.ClassDeclaration|
- ts.InterfaceDeclaration): ts.Statement[] {
+ mergedDecl: ts.ClassDeclaration|ts.InterfaceDeclaration|
+ ts.EnumDeclaration): ts.Statement[] {
if (!ns.body || !ts.isModuleBlock(ns.body)) {
if (ts.isModuleDeclaration(ns)) {
error(
@@ -83,10 +83,15 @@ export function namespaceTransformer(
return [ns];
}
const nsName = getIdentifierText(ns.name as ts.Identifier);
+ const mergingWithEnum = ts.isEnumDeclaration(mergedDecl);
const transformedNsStmts: ts.Statement[] = [];
for (const stmt of ns.body.statements) {
if (ts.isEmptyStatement(stmt)) continue;
if (ts.isClassDeclaration(stmt)) {
+ if (mergingWithEnum) {
+ errorNotAllowed(stmt, 'class');
+ continue;
+ }
transformInnerDeclaration(
stmt, (classDecl, notExported, hoistedIdent) => {
return ts.factory.updateClassDeclaration(
@@ -95,12 +100,20 @@ export function namespaceTransformer(
classDecl.members);
});
} else if (ts.isEnumDeclaration(stmt)) {
+ if (mergingWithEnum) {
+ errorNotAllowed(stmt, 'enum');
+ continue;
+ }
transformInnerDeclaration(
stmt, (enumDecl, notExported, hoistedIdent) => {
return ts.factory.updateEnumDeclaration(
enumDecl, notExported, hoistedIdent, enumDecl.members);
});
} else if (ts.isInterfaceDeclaration(stmt)) {
+ if (mergingWithEnum) {
+ errorNotAllowed(stmt, 'interface');
+ continue;
+ }
transformInnerDeclaration(
stmt, (interfDecl, notExported, hoistedIdent) => {
return ts.factory.updateInterfaceDeclaration(
@@ -109,6 +122,10 @@ export function namespaceTransformer(
interfDecl.members);
});
} else if (ts.isTypeAliasDeclaration(stmt)) {
+ if (mergingWithEnum) {
+ errorNotAllowed(stmt, 'type alias');
+ continue;
+ }
transformTypeAliasDeclaration(stmt);
} else if (ts.isVariableStatement(stmt)) {
if ((ts.getCombinedNodeFlags(stmt.declarationList) &
@@ -116,13 +133,28 @@ export function namespaceTransformer(
error(
stmt,
'non-const values are not supported. (go/ts-merged-namespaces)');
+ continue;
}
if (!ts.isInterfaceDeclaration(mergedDecl)) {
error(
stmt,
'const declaration only allowed when merging with an interface (go/ts-merged-namespaces)');
+ continue;
}
transformConstDeclaration(stmt);
+ } else if (ts.isFunctionDeclaration(stmt)) {
+ if (!ts.isEnumDeclaration(mergedDecl)) {
+ error(
+ stmt,
+ 'function declaration only allowed when merging with an enum (go/ts-merged-namespaces)');
+ }
+ transformInnerDeclaration(
+ stmt, (funcDecl, notExported, hoistedIdent) => {
+ return ts.factory.updateFunctionDeclaration(
+ funcDecl, notExported, funcDecl.asteriskToken,
+ hoistedIdent, funcDecl.typeParameters,
+ funcDecl.parameters, funcDecl.type, funcDecl.body);
+ });
} else {
error(
stmt,
@@ -145,6 +177,12 @@ export function namespaceTransformer(
// Local functions follow.
+ function errorNotAllowed(stmt: ts.Statement, declKind: string) {
+ error(
+ stmt,
+ `${declKind} cannot be merged with enum declaration. (go/ts-merged-namespaces)`);
+ }
+
type DeclarationStatement = ts.Declaration&ts.DeclarationStatement;
function transformConstDeclaration(varDecl: ts.VariableStatement) {
@@ -365,12 +403,13 @@ export function namespaceTransformer(
}
if (!ts.isInterfaceDeclaration(mergedDecl) &&
- !ts.isClassDeclaration(mergedDecl)) {
- // The previous declaration is not a class or interface.
+ !ts.isClassDeclaration(mergedDecl) &&
+ !ts.isEnumDeclaration(mergedDecl)) {
+ // The previous declaration is not a class, enum, or interface.
transformedStmts.push(ns); // Nothing to do here.
error(
ns.name,
- 'merged declaration must be local class or interface. (go/ts-merged-namespaces)');
+ 'merged declaration must be local class, enum, or interface. (go/ts-merged-namespaces)');
return;
}
diff --git a/src/summary.ts b/src/summary.ts
index ffbff10fb..9f2623345 100644
--- a/src/summary.ts
+++ b/src/summary.ts
@@ -54,6 +54,7 @@ export class FileSummary {
modName: string|undefined;
autochunk = false;
enhanceable = false;
+ legacyNamespace = false;
moduleType = ModuleType.UNKNOWN;
private stringify(symbol: Symbol): string {
diff --git a/src/transformer_util.ts b/src/transformer_util.ts
index 6c60ef0dd..8489f8fe8 100644
--- a/src/transformer_util.ts
+++ b/src/transformer_util.ts
@@ -152,7 +152,7 @@ export function updateSourceFileNode(
}
sf = ts.factory.updateSourceFile(
sf,
- statements,
+ ts.setTextRange(statements, sf.statements),
sf.isDeclarationFile,
sf.referencedFiles,
sf.typeReferenceDirectives,
@@ -227,28 +227,30 @@ export function reportDebugWarning(
* @param textRange pass to overrride the text range from the node with a more specific range.
*/
export function reportDiagnostic(
- diagnostics: ts.Diagnostic[], node: ts.Node, messageText: string, textRange?: ts.TextRange,
- category = ts.DiagnosticCategory.Error) {
+ diagnostics: ts.Diagnostic[], node: ts.Node|undefined, messageText: string,
+ textRange?: ts.TextRange, category = ts.DiagnosticCategory.Error) {
diagnostics.push(createDiagnostic(node, messageText, textRange, category));
}
function createDiagnostic(
- node: ts.Node, messageText: string, textRange: ts.TextRange|undefined,
+ node: ts.Node|undefined, messageText: string,
+ textRange: ts.TextRange|undefined,
category: ts.DiagnosticCategory): ts.Diagnostic {
- let start, length: number;
+ let start: number|undefined;
+ let length: number|undefined;
// getStart on a synthesized node can crash (due to not finding an associated
// source file). Make sure to use the original node.
node = ts.getOriginalNode(node);
if (textRange) {
start = textRange.pos;
length = textRange.end - textRange.pos;
- } else {
+ } else if (node) {
// Only use getStart if node has a valid pos, as it might be synthesized.
start = node.pos >= 0 ? node.getStart() : 0;
length = node.end - node.pos;
}
return {
- file: node.getSourceFile(),
+ file: node?.getSourceFile(),
start,
length,
messageText,
@@ -431,4 +433,4 @@ export function getPreviousDeclaration(
}
}
return null;
-}
\ No newline at end of file
+}
diff --git a/src/ts_migration_exports_shim.ts b/src/ts_migration_exports_shim.ts
index ac715764b..0136ea45e 100644
--- a/src/ts_migration_exports_shim.ts
+++ b/src/ts_migration_exports_shim.ts
@@ -457,6 +457,9 @@ class Generator {
fileSummary.addStrongRequire({type: Type.CLOSURE, name: 'goog'});
fileSummary.addStrongRequire(
{type: Type.CLOSURE, name: this.srcIds.googModuleId});
+ if (maybeDeclareLegacyNameCall) {
+ fileSummary.legacyNamespace = true;
+ }
fileSummary.autochunk = isAutoChunk;
fileSummary.moduleType = ModuleType.GOOG_MODULE;
diff --git a/src/tsickle.ts b/src/tsickle.ts
index 3b10f073a..ac0db0b80 100644
--- a/src/tsickle.ts
+++ b/src/tsickle.ts
@@ -8,6 +8,7 @@
import * as ts from 'typescript';
+import * as path from './path';
import {AnnotatorHost} from './annotator_host';
import {assertAbsolute} from './cli_support';
import * as clutz from './clutz';
@@ -23,7 +24,6 @@ import {namespaceTransformer} from './ns_transformer';
import {FileSummary, SummaryGenerationProcessorHost} from './summary';
import {isDtsFileName} from './transformer_util';
import * as tsmes from './ts_migration_exports_shim';
-import {makeTsickleDeclarationMarkerTransformerFactory} from './tsickle_declaration_marker';
// Exported for users as a default impl of pathToModuleName.
export {pathToModuleName} from './cli_support';
@@ -154,6 +154,25 @@ export interface EmitTransformers {
}
+function writeWithTsickleHeader(
+ writeFile: ts.WriteFileCallback, rootDir: string) {
+ return (fileName: string, content: string, writeByteOrderMark: boolean,
+ onError: ((message: string) => void)|undefined,
+ sourceFiles: readonly ts.SourceFile[]|undefined,
+ data: ts.WriteFileCallbackData|undefined) => {
+ if (fileName.endsWith('.d.ts')) {
+ // Add tsickle header.
+ const sources =
+ sourceFiles?.map(sf => path.relative(rootDir, sf.fileName));
+ content = `//!! generated by tsickle from ${
+ sources?.join(' ') || '???'}\n${content}`;
+ }
+
+ writeFile(
+ fileName, content, writeByteOrderMark, onError, sourceFiles, data);
+ };
+}
+
/**
* @deprecated Exposed for backward compat with Angular. Use emit() instead.
*/
@@ -222,7 +241,7 @@ export function emit(
}
tsickleSourceTransformers.push(
jsdocTransformer(host, tsOptions, typeChecker, tsickleDiagnostics));
- tsickleSourceTransformers.push(enumTransformer(typeChecker));
+ tsickleSourceTransformers.push(enumTransformer(host, typeChecker));
}
if (host.transformDecorators) {
tsickleSourceTransformers.push(
@@ -254,14 +273,9 @@ export function emit(
clutz.makeDeclarationTransformerFactory(typeChecker, host));
}
- // Adds a marker to the top of tsickle-generated .d.ts files, should always go
- // last
- tsTransformers.afterDeclarations!.push(
- makeTsickleDeclarationMarkerTransformerFactory(tsOptions));
-
const {diagnostics: tsDiagnostics, emitSkipped, emittedFiles} = program.emit(
- targetSourceFile, writeFile, cancellationToken, emitOnlyDtsFiles,
- tsTransformers);
+ targetSourceFile, writeWithTsickleHeader(writeFile, tsOptions.rootDir),
+ cancellationToken, emitOnlyDtsFiles, tsTransformers);
const externs:
{[fileName: string]: {output: string, moduleNamespace: string}} = {};
diff --git a/src/tsickle_declaration_marker.ts b/src/tsickle_declaration_marker.ts
deleted file mode 100644
index 76af06e42..000000000
--- a/src/tsickle_declaration_marker.ts
+++ /dev/null
@@ -1,38 +0,0 @@
-/**
- * @license
- * Copyright Google Inc. All Rights Reserved.
- *
- * Use of this source code is governed by an MIT-style license that can be
- * found in the LICENSE file at https://angular.io/license
- */
-
-import * as ts from 'typescript';
-
-import * as path from './path';
-import {createNotEmittedStatement, updateSourceFileNode} from './transformer_util';
-
-/** Marks tsickle generated .d.ts's with a comment we can find later. */
-export function makeTsickleDeclarationMarkerTransformerFactory(
- options: ts.CompilerOptions): ts.CustomTransformerFactory {
- return (context: ts.TransformationContext): ts.CustomTransformer => {
- return {
- transformBundle(): ts.Bundle {
- // The TS API wants declaration transfomers to be able to handle Bundle,
- // but we don't support them within tsickle.
- throw new Error('did not expect to transform a bundle');
- },
- transformSourceFile(sf: ts.SourceFile): ts.SourceFile {
- if (!options.rootDir) return sf;
- let syntheticFirstStatement = createNotEmittedStatement(sf);
- syntheticFirstStatement = ts.addSyntheticTrailingComment(
- syntheticFirstStatement, ts.SyntaxKind.SingleLineCommentTrivia,
- `!! generated by tsickle from ${
- path.relative(options.rootDir, sf.fileName)}`,
- /*hasTrailingNewLine=*/ true);
- return updateSourceFileNode(sf, ts.factory.createNodeArray([
- syntheticFirstStatement, ...sf.statements
- ]));
- }
- };
- };
-}
diff --git a/src/type_translator.ts b/src/type_translator.ts
index 324ec77e8..1464a7cb4 100644
--- a/src/type_translator.ts
+++ b/src/type_translator.ts
@@ -860,6 +860,20 @@ export class TypeTranslator {
if (sigs.length === 1) {
return this.signatureToClosure(sigs[0]);
}
+ // Function has multiple declaration. Let's see if we can find a single
+ // declaration with an implementation. In this case all the other
+ // declarations are overloads and the implementation must have a
+ // signature that matches all of them.
+ const declWithBody = type.symbol.declarations?.filter(
+ (d): d is ts.FunctionLikeDeclaration =>
+ isFunctionLikeDeclaration(d) && d.body != null);
+ if (declWithBody?.length === 1) {
+ const sig =
+ this.typeChecker.getSignatureFromDeclaration(declWithBody[0]);
+ if (sig) {
+ return this.signatureToClosure(sig);
+ }
+ }
this.warn('unhandled anonymous type with multiple call signatures');
return '?';
}
@@ -1173,3 +1187,11 @@ export function restParameterType(
}
return typeArgs[0];
}
+
+function isFunctionLikeDeclaration(node: ts.Node):
+ node is ts.FunctionLikeDeclaration {
+ return ts.isFunctionDeclaration(node) || ts.isMethodDeclaration(node) ||
+ ts.isConstructorDeclaration(node) || ts.isGetAccessorDeclaration(node) ||
+ ts.isSetAccessorDeclaration(node) || ts.isFunctionExpression(node) ||
+ ts.isArrowFunction(node);
+}
diff --git a/test/googmodule_test.ts b/test/googmodule_test.ts
index a258a7bcf..4d804cbb5 100644
--- a/test/googmodule_test.ts
+++ b/test/googmodule_test.ts
@@ -13,6 +13,7 @@ import * as googmodule from '../src/googmodule';
import {ModulesManifest} from '../src/modules_manifest';
import * as testSupport from './test_support';
+import {outdent} from './test_support';
interface ResolvedNamespace {
name: string;
@@ -42,8 +43,14 @@ function processES5(
transformDynamicImport: 'closure',
};
if (pathToNamespaceMap) {
- host.jsPathToModuleName = (importPath: string) =>
- pathToNamespaceMap.get(importPath)?.name;
+ host.jsPathToModuleName = (importPath: string) => {
+ const module = pathToNamespaceMap.get(importPath);
+ if (!module) return undefined;
+ return {
+ name: module.name,
+ multipleProvides: false,
+ };
+ };
host.jsPathToStripProperty = (importPath: string) =>
pathToNamespaceMap.get(importPath)?.stripProperty;
}
@@ -71,21 +78,6 @@ function processES5(
return {output, manifest, rootDir};
}
-/**
- * Remove the first line (if empty) and unindents the all other lines by the
- * amount of leading whitespace in the second line.
- */
-function outdent(str: string) {
- const lines = str.split('\n');
- if (lines.length < 2) return str;
- if (lines.shift() !== '') return str;
- const indent = lines[0].match(/^ */)![0].length;
- for (let i = 0; i < lines.length; i++) {
- lines[i] = lines[i].substring(indent);
- }
- return lines.join('\n');
-}
-
describe('convertCommonJsToGoogModule', () => {
beforeEach(() => {
testSupport.addDiffMatchers();
diff --git a/test/test_support.ts b/test/test_support.ts
index c270ac144..6f0f2b826 100644
--- a/test/test_support.ts
+++ b/test/test_support.ts
@@ -453,3 +453,18 @@ export function pathToModuleName(
if (fileName === tslibPath()) return 'tslib';
return cliSupport.pathToModuleName(rootModulePath, context, fileName);
}
+
+/**
+ * Remove the first line (if empty) and unindents the all other lines by the
+ * amount of leading whitespace in the second line.
+ */
+export function outdent(str: string) {
+ const lines = str.split('\n');
+ if (lines.length < 2) return str;
+ if (lines.shift() !== '') return str;
+ const indent = lines[0].match(/^ */)![0].length;
+ for (let i = 0; i < lines.length; i++) {
+ lines[i] = lines[i].substring(indent);
+ }
+ return lines.join('\n');
+}
diff --git a/test/tsickle_test.ts b/test/tsickle_test.ts
index 7fbb9592a..11d59e3e7 100644
--- a/test/tsickle_test.ts
+++ b/test/tsickle_test.ts
@@ -13,14 +13,14 @@ import {assertAbsolute} from '../src/cli_support';
import * as tsickle from '../src/tsickle';
import * as testSupport from './test_support';
+import {outdent} from './test_support';
describe('emitWithTsickle', () => {
function emitWithTsickle(
tsSources: {[fileName: string]: string},
tsConfigOverride: Partial = {},
tsickleHostOverride: Partial = {},
- customTransformers?: tsickle.EmitTransformers):
- {[fileName: string]: string} {
+ customTransformers?: tsickle.EmitTransformers) {
const tsCompilerOptions: ts.CompilerOptions = {
...testSupport.compilerOptions,
target: ts.ScriptTarget.ES5,
@@ -55,13 +55,13 @@ describe('emitWithTsickle', () => {
return importPath.replace(/\/|\\/g, '.');
},
fileNameToModuleId: (fileName) => fileName.replace(/^\.\//, ''),
- ...tsickleHostOverride,
options: tsCompilerOptions,
rootDirsRelative: testSupport.relativeToTsickleRoot,
- transformDynamicImport: 'closure'
+ transformDynamicImport: 'closure',
+ ...tsickleHostOverride,
};
const jsSources: {[fileName: string]: string} = {};
- tsickle.emit(
+ const {diagnostics} = tsickle.emit(
program, tsickleHost,
(fileName: string, data: string) => {
jsSources[path.relative(tsCompilerOptions.rootDir!, fileName)] = data;
@@ -69,7 +69,7 @@ describe('emitWithTsickle', () => {
/* sourceFile */ undefined,
/* cancellationToken */ undefined, /* emitOnlyDtsFiles */ undefined,
customTransformers);
- return jsSources;
+ return {jsSources, diagnostics};
}
@@ -91,7 +91,7 @@ describe('emitWithTsickle', () => {
const tsSources = {
'a.ts': `export const x = 1;`,
};
- const jsSources = emitWithTsickle(
+ const {jsSources} = emitWithTsickle(
tsSources, undefined, {
shouldSkipTsickleProcessing: () => true,
},
@@ -106,12 +106,10 @@ describe('emitWithTsickle', () => {
'b.ts': `export * from './a';`,
};
- const jsSources = emitWithTsickle(
- tsSources, {
- preserveConstEnums: true,
- module: ts.ModuleKind.ES2015,
- },
- {googmodule: false});
+ const {jsSources} = emitWithTsickle(tsSources, {
+ preserveConstEnums: true,
+ module: ts.ModuleKind.ES2015,
+ });
expect(jsSources['b.js']).toContain(`export { Foo } from './a';`);
});
@@ -121,16 +119,62 @@ describe('emitWithTsickle', () => {
'a.ts': `export function f() : typeof f { return f; }`,
};
- const jsSources = emitWithTsickle(tsSources, {
+ const {jsSources} = emitWithTsickle(tsSources, {
module: ts.ModuleKind.ES2015,
});
- expect(jsSources['a.js']).toContain(`
-/**
- * @return {function(): ?}
- */
-export function f() { return f; }
-`);
+ expect(jsSources['a.js']).toContain(outdent(`
+ /**
+ * @return {function(): ?}
+ */
+ export function f() { return f; }
+ `));
+ });
+
+ it('reports multi-provides error with jsPathToModuleName impl', () => {
+ const tsSources = {
+ 'a.ts': `import {} from 'google3/multi/provide';`,
+ 'clutz.d.ts': `declare module 'google3/multi/provide' { export {}; }`,
+ };
+ const {diagnostics} =
+ emitWithTsickle(
+ tsSources, /* tsConfigOverride= */ undefined,
+ /* tsickleHostOverride= */ {
+ jsPathToModuleName(importPath: string) {
+ if (importPath === 'google3/multi/provide') {
+ return {
+ name: 'multi.provide',
+ multipleProvides: true,
+ };
+ }
+ return undefined;
+ }
+ });
+ expect(testSupport.formatDiagnostics(diagnostics))
+ .toContain(
+ 'referenced JavaScript module google3/multi/provide provides multiple namespaces and cannot be imported by path');
+ });
+
+ it('allows side-effect import of multi-provides module', () => {
+ const tsSources = {
+ 'a.ts': `import 'google3/multi/provide';`,
+ 'clutz.d.ts': `declare module 'google3/multi/provide' { export {}; }`,
+ };
+ const {jsSources} = emitWithTsickle(
+ tsSources, /* tsConfigOverride= */ undefined,
+ /* tsickleHostOverride= */ {
+ googmodule: true,
+ jsPathToModuleName(importPath: string) {
+ if (importPath === 'google3/multi/provide') {
+ return {
+ name: 'multi.provide',
+ multipleProvides: true,
+ };
+ }
+ return undefined;
+ },
+ });
+ expect(jsSources['a.js']).toContain(`goog.require('multi.provide');`);
});
describe('regressions', () => {
@@ -140,16 +184,15 @@ export function f() { return f; }
'a.ts': `export const x = 1;`,
'b.ts': `export * from './a';\n`,
};
- const jsSources = emitWithTsickle(
- tsSources, {
- declaration: true,
- module: ts.ModuleKind.ES2015,
- },
- {googmodule: false});
-
- expect(jsSources['b.d.ts'])
- .toEqual(`//!! generated by tsickle from b.ts
-export * from './a';\n`);
+ const {jsSources} = emitWithTsickle(tsSources, {
+ declaration: true,
+ module: ts.ModuleKind.ES2015,
+ });
+
+ expect(jsSources['b.d.ts']).toEqual(outdent(`
+ //!! generated by tsickle from b.ts
+ export * from './a';
+ `));
});
});
});
diff --git a/test_files/augment/externs.js b/test_files/augment/externs.js
index 18fb334ad..077c7e11f 100644
--- a/test_files/augment/externs.js
+++ b/test_files/augment/externs.js
@@ -8,8 +8,6 @@
var test_files$augment$angular$index_ = {};
/** @type {!test_files$augment$angular$index_.angular.IAngularStatic} */
test_files$augment$angular$index_.angular;
-/** @const */
-test_files$augment$angular$index_.angular = {};
/**
* @record
* @struct
diff --git a/test_files/clutz_imports.declaration.no_externs/clutz2_output_demo8.d.ts b/test_files/clutz_imports.declaration.no_externs/clutz2_output_demo8.d.ts
deleted file mode 100644
index 3874d54c0..000000000
--- a/test_files/clutz_imports.declaration.no_externs/clutz2_output_demo8.d.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-//!! generated by clutz2
-/**
- * @fileoverview This file contains the Clutz2 output for a simple goog.provide.
- * It was manually created and is a support file for the actual test.
- */
-
-declare namespace ಠ_ಠ.clutz {
- namespace demo8 {
- export class C {
- private noStructuralTyping_demo8$C: any;
- }
- } // namespace demo8
-} // ಠ_ಠ.clutz
-
-declare module 'goog:demo8' {
- import demo8 = ಠ_ಠ.clutz.demo8;
- export default demo8;
-}
diff --git a/test_files/clutz_imports.declaration.no_externs/clutz_output_demo1.d.ts b/test_files/clutz_imports.declaration.no_externs/clutz_output_demo1.d.ts
deleted file mode 100644
index 923e8b723..000000000
--- a/test_files/clutz_imports.declaration.no_externs/clutz_output_demo1.d.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-//!! generated by clutz.
-/**
- * @fileoverview This file contains the Clutz output for a simple goog.module.
- * It was manually created and is a support file for the actual test.
- */
-
-declare namespace ಠ_ಠ.clutz.module$exports$demo1 {
- class C {
- private noStructuralTyping_module$exports$demo1_C: any;
- foo(): void;
- }
-}
-declare module 'goog:demo1' {
-import demo1 = ಠ_ಠ.clutz.module$exports$demo1;
- export = demo1;
-}
diff --git a/test_files/clutz_imports.declaration.no_externs/clutz_output_demo2.d.ts b/test_files/clutz_imports.declaration.no_externs/clutz_output_demo2.d.ts
deleted file mode 100644
index 52c32f839..000000000
--- a/test_files/clutz_imports.declaration.no_externs/clutz_output_demo2.d.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-//!! generated by clutz.
-/**
- * @fileoverview This file contains the Clutz output for a simple goog.provide.
- * It was manually created and is a support file for the actual test.
- */
-
-declare namespace ಠ_ಠ.clutz.demo2 {
- class C {
- private noStructuralTyping_demo2_C: any;
- bar(): void;
- }
-}
-declare module 'goog:demo2' {
-import demo2 = ಠ_ಠ.clutz.demo2;
- export = demo2;
-}
diff --git a/test_files/clutz_imports.declaration.no_externs/clutz_output_demo3.d.ts b/test_files/clutz_imports.declaration.no_externs/clutz_output_demo3.d.ts
deleted file mode 100644
index 5c68d9376..000000000
--- a/test_files/clutz_imports.declaration.no_externs/clutz_output_demo3.d.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-//!! generated by clutz.
-/**
- * @fileoverview This file contains the Clutz output for a simple goog.module.
- * It was manually created and is a support file for the actual test.
- */
-
-declare namespace ಠ_ಠ.clutz {
- class module$exports$demo3 {
- private noStructuralTyping_module$exports$demo3: any;
- bar(): void;
- }
-}
-declare module 'goog:demo3' {
-import demo3 = ಠ_ಠ.clutz.module$exports$demo3;
- export default demo3;
-}
diff --git a/test_files/clutz_imports.declaration.no_externs/clutz_output_demo4.d.ts b/test_files/clutz_imports.declaration.no_externs/clutz_output_demo4.d.ts
deleted file mode 100644
index 4758a64fd..000000000
--- a/test_files/clutz_imports.declaration.no_externs/clutz_output_demo4.d.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-//!! generated by clutz.
-/**
- * @fileoverview This file contains the Clutz output for a simple goog.provide.
- * It was manually created and is a support file for the actual test.
- */
-
-declare namespace ಠ_ಠ.clutz.demo4 {
- function f(): void;
-}
-declare module 'goog:demo4' {
-import demo4 = ಠ_ಠ.clutz.demo4;
- export = demo4;
-}
diff --git a/test_files/clutz_imports.declaration.no_externs/clutz_output_demo5.d.ts b/test_files/clutz_imports.declaration.no_externs/clutz_output_demo5.d.ts
deleted file mode 100644
index 9cb9ad9ae..000000000
--- a/test_files/clutz_imports.declaration.no_externs/clutz_output_demo5.d.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-//!! generated by clutz.
-/**
- * @fileoverview This file contains the Clutz output for a simple goog.module.
- * It was manually created and is a support file for the actual test.
- */
-
-declare namespace ಠ_ಠ.clutz.module$exports$demo5 {
- class C {
- private noStructuralTyping_module$exports$demo5_C : any;
- f ( ) : void ;
- }
-}
-declare module 'goog:demo5' {
- import demo5 = ಠ_ಠ.clutz.module$exports$demo5;
- export = demo5;
-}
-
diff --git a/test_files/clutz_imports.declaration.no_externs/clutz_output_demo6.d.ts b/test_files/clutz_imports.declaration.no_externs/clutz_output_demo6.d.ts
deleted file mode 100644
index 96b67ac90..000000000
--- a/test_files/clutz_imports.declaration.no_externs/clutz_output_demo6.d.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-//!! generated by clutz.
-/**
- * @fileoverview This file contains the Clutz output for a simple goog.module,
- * with a generic class.
- * It was manually created and is a support file for the actual test.
- */
-
-declare namespace ಠ_ಠ.clutz.module$exports$demo6 {
- class C < T = any > {
- private noStructuralTyping_module$exports$demo6_C : [ T ];
- foo ( ) : void ;
- }
-}
-declare module 'goog:demo6' {
- import demo6 = ಠ_ಠ.clutz.module$exports$demo6;
- export = demo6;
-}
-
diff --git a/test_files/clutz_imports.declaration.no_externs/clutz_output_demo7.d.ts b/test_files/clutz_imports.declaration.no_externs/clutz_output_demo7.d.ts
deleted file mode 100644
index 5333dad3a..000000000
--- a/test_files/clutz_imports.declaration.no_externs/clutz_output_demo7.d.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-//!! generated by clutz.
-/**
- * @fileoverview This file contains the Clutz output for an externs file.
- * It was manually created and is a support file for the actual test.
- */
-
-declare namespace demo7 {
- class C {
- foo(): void;
- }
-}
diff --git a/test_files/clutz_imports.declaration.no_externs/user_code.d.ts b/test_files/clutz_imports.declaration.no_externs/user_code.d.ts
deleted file mode 100644
index 0a3d3ba90..000000000
--- a/test_files/clutz_imports.declaration.no_externs/user_code.d.ts
+++ /dev/null
@@ -1,53 +0,0 @@
-// test_files/clutz_imports.declaration.no_externs/user_code.ts(39,1): warning TS0: anonymous type has no symbol
-//!! generated by tsickle from test_files/clutz_imports.declaration.no_externs/user_code.ts
-import "test_files/clutz_imports.declaration.no_externs/clutz_output_demo1";
-import "test_files/clutz_imports.declaration.no_externs/clutz_output_demo2";
-import "test_files/clutz_imports.declaration.no_externs/clutz2_output_demo8";
-import "test_files/clutz_imports.declaration.no_externs/clutz_output_demo4";
-import "test_files/clutz_imports.declaration.no_externs/clutz_output_demo6";
-import "test_files/clutz_imports.declaration.no_externs/clutz_output_demo5";
-import "test_files/clutz_imports.declaration.no_externs/clutz_output_demo7";
-/**
- * @fileoverview This file simulates a TypeScript file that interacts with Clutz
- * types. The expected output is that the generated .d.ts file has explicit
- * "import" statements that refer directly to the paths that define some of
- * the Clutz symbols (either goog: or look of disapproval) referenced in the
- * public API of this file.
- */
-import * as demo1 from 'goog:demo1';
-/**
- * demo1 is exposed in the public API via an import, so we expect the output
- * d.ts to have an import of the module underlying goog:demo1.
- */
-export declare function f1(c: demo1.C): void;
-/**
- * demo2 is exposed in the public API via a direct reference to the look of
- * disapproval namespace, so we expect the output d.ts to have an import of the
- * module underlying goog:demo2.
- *
- * demo8 is the same, but the d.ts file is generated by Clutz2.
- */
-export declare function f2(c: ಠ_ಠ.clutz.demo2.C, c2: ಠ_ಠ.clutz.demo8.C): void;
-/**
- * demo4 verifies that the Clutz type via 'typeof' still produces an import
- * statement in the output. (It differs from the above in that a typeof node
- * in the TS AST contains the reference to a Clutz symbol as a value, not a
- * type.)
- */
-export type f4 = typeof ಠ_ಠ.clutz.demo4;
-export declare function f5(): ಠ_ಠ.clutz.module$exports$demo6.C<ಠ_ಠ.clutz.module$exports$demo5.C> | undefined;
-/**
- * demo7 contains typings generated from externs.
- *
- * Even though we don't reference the internal Clutz namespace here, we expect
- * the output d.ts to have an import to the demo7 file.
- */
-export declare function f6(c: demo7.C): void;
-declare global {
- namespace ಠ_ಠ.clutz {
- export { f1 as module$contents$test_files$clutz_imports$declaration$no_externs$user_code_f1, f2 as module$contents$test_files$clutz_imports$declaration$no_externs$user_code_f2, f4 as module$contents$test_files$clutz_imports$declaration$no_externs$user_code_f4, f5 as module$contents$test_files$clutz_imports$declaration$no_externs$user_code_f5, f6 as module$contents$test_files$clutz_imports$declaration$no_externs$user_code_f6 };
- export namespace module$exports$test_files$clutz_imports$declaration$no_externs$user_code {
- export { f1, f2, f4, f5, f6 };
- }
- }
-}
diff --git a/test_files/clutz_imports.declaration.no_externs/user_code.ts b/test_files/clutz_imports.declaration.no_externs/user_code.ts
deleted file mode 100644
index 9c2741eea..000000000
--- a/test_files/clutz_imports.declaration.no_externs/user_code.ts
+++ /dev/null
@@ -1,69 +0,0 @@
-/**
- * @fileoverview This file simulates a TypeScript file that interacts with Clutz
- * types. The expected output is that the generated .d.ts file has explicit
- * "import" statements that refer directly to the paths that define some of
- * the Clutz symbols (either goog: or look of disapproval) referenced in the
- * public API of this file.
- */
-
-import * as demo1 from 'goog:demo1';
-import demo3 from 'goog:demo3';
-
-/**
- * demo1 is exposed in the public API via an import, so we expect the output
- * d.ts to have an import of the module underlying goog:demo1.
- */
-export function f1(c: demo1.C) {}
-
-/**
- * demo2 is exposed in the public API via a direct reference to the look of
- * disapproval namespace, so we expect the output d.ts to have an import of the
- * module underlying goog:demo2.
- *
- * demo8 is the same, but the d.ts file is generated by Clutz2.
- */
-export function f2(c: ಠ_ಠ.clutz.demo2.C, c2: ಠ_ಠ.clutz.demo8.C) {}
-
-/**
- * demo3 is used by this module, but not exported, so we don't expect an import
- * of the underlying module in the output d.ts.
- */
-function f3(c: demo3) {}
-
-/**
- * demo4 verifies that the Clutz type via 'typeof' still produces an import
- * statement in the output. (It differs from the above in that a typeof node
- * in the TS AST contains the reference to a Clutz symbol as a value, not a
- * type.)
- */
-export type f4 = typeof ಠ_ಠ.clutz.demo4;
-
-/**
- * This next example verifies that references generated by TS are still handled.
- * The internal function here references a Clutz type, which normally would
- * stay internal-only and not affect the d.ts. But then we export a function
- * that uses inference to refer to this type.
- *
- * This is a special case because the Clutz type appears in the d.ts but it
- * is generated by a codepath in the TS compiler that causes the type to have no
- * symbol present in the TypeChecker.
- *
- * This also uses a generic, to cover one additional case.
- * We expect both demo5 and demo6 to show up in the public API of the d.ts.
- */
-function internal():
- ಠ_ಠ.clutz.module$exports$demo6.C<ಠ_ಠ.clutz.module$exports$demo5.C>|
- undefined {
- return undefined;
-}
-export function f5() {
- return internal();
-}
-
-/**
- * demo7 contains typings generated from externs.
- *
- * Even though we don't reference the internal Clutz namespace here, we expect
- * the output d.ts to have an import to the demo7 file.
- */
-export function f6(c: demo7.C) {}
diff --git a/test_files/comments/trailing_no_semicolon.js b/test_files/comments/trailing_no_semicolon.js
new file mode 100644
index 000000000..f16924b09
--- /dev/null
+++ b/test_files/comments/trailing_no_semicolon.js
@@ -0,0 +1,22 @@
+/**
+ *
+ * @fileoverview Tests that the JSDoc comment of `other` is only emitted once.
+ * Without the trailing semicolon after `noExplicitSemicolon` TypeScript seems
+ * to duplicate the trailing comment as soon as a custom transformer modifies
+ * the variable statement.
+ *
+ * Generated from: test_files/comments/trailing_no_semicolon.ts
+ */
+goog.module('test_files.comments.trailing_no_semicolon');
+var module = module || { id: 'test_files/comments/trailing_no_semicolon.ts' };
+goog.require('tslib');
+/** @type {number} */
+const noExplicitSemicolon = 0;
+/**
+ * This is a comment with a JSDoc tag
+ * JSCompiler doesn't recognize
+ *
+ * \@foobar
+ * @type {number}
+ */
+exports.other = 1;
diff --git a/test_files/comments/trailing_no_semicolon.ts b/test_files/comments/trailing_no_semicolon.ts
new file mode 100644
index 000000000..b68b9844a
--- /dev/null
+++ b/test_files/comments/trailing_no_semicolon.ts
@@ -0,0 +1,17 @@
+/**
+ * @fileoverview Tests that the JSDoc comment of `other` is only emitted once.
+ * Without the trailing semicolon after `noExplicitSemicolon` TypeScript seems
+ * to duplicate the trailing comment as soon as a custom transformer modifies
+ * the variable statement.
+ */
+
+
+const noExplicitSemicolon = 0
+
+/**
+ * This is a comment with a JSDoc tag
+ * JSCompiler doesn't recognize
+ *
+ * @foobar
+ */
+export const other = 1;
diff --git a/test_files/decl_merge/outer_enum.js b/test_files/decl_merge/outer_enum.js
new file mode 100644
index 000000000..9f3827e1a
--- /dev/null
+++ b/test_files/decl_merge/outer_enum.js
@@ -0,0 +1,31 @@
+/**
+ *
+ * @fileoverview Ensure that a function declared in a declaration
+ * merging namespace is generated as a property of the merged outer enum.
+ *
+ * Generated from: test_files/decl_merge/outer_enum.ts
+ * @suppress {uselessCode,checkTypes}
+ *
+ */
+goog.module('test_files.decl_merge.outer_enum');
+var module = module || { id: 'test_files/decl_merge/outer_enum.ts' };
+goog.require('tslib');
+/** @enum {number} */
+const E = {
+ a: 42,
+ b: 43,
+};
+exports.E = E;
+E[E.a] = 'a';
+E[E.b] = 'b';
+/**
+ * @param {string} s
+ * @return {!E}
+ */
+function E$fromString(s) {
+ return s === 'a' ? E.a : E.b;
+}
+/** @const */
+E.fromString = E$fromString;
+/** @type {!E} */
+const e = E.fromString('a');
diff --git a/test_files/decl_merge/outer_enum.ts b/test_files/decl_merge/outer_enum.ts
new file mode 100644
index 000000000..b89996cc3
--- /dev/null
+++ b/test_files/decl_merge/outer_enum.ts
@@ -0,0 +1,20 @@
+/**
+ * @fileoverview Ensure that a function declared in a declaration
+ * merging namespace is generated as a property of the merged outer enum.
+ *
+ * @suppress {uselessCode,checkTypes}
+ */
+
+export enum E {
+ a = 42,
+ b
+}
+
+// tslint:disable-next-line:no-namespace
+export namespace E {
+ export function fromString(s: string) {
+ return s === 'a' ? E.a : E.b;
+ };
+}
+
+const e = E.fromString('a');
diff --git a/test_files/decl_merge/rejected_ns.js b/test_files/decl_merge/rejected_ns.js
index 54aa1d565..2fbd3bfa2 100644
--- a/test_files/decl_merge/rejected_ns.js
+++ b/test_files/decl_merge/rejected_ns.js
@@ -1,12 +1,13 @@
-// test_files/decl_merge/rejected_ns.ts(34,1): warning TS0: type/symbol conflict for Inbetween, using {?} for now
+// test_files/decl_merge/rejected_ns.ts(32,1): warning TS0: type/symbol conflict for Inbetween, using {?} for now
// test_files/decl_merge/rejected_ns.ts(9,11): error TS0: transformation of plain namespace not supported. (go/ts-merged-namespaces)
-// test_files/decl_merge/rejected_ns.ts(13,11): error TS0: merged declaration must be local class or interface. (go/ts-merged-namespaces)
-// test_files/decl_merge/rejected_ns.ts(21,11): error TS0: merged declaration must be local class or interface. (go/ts-merged-namespaces)
-// test_files/decl_merge/rejected_ns.ts(26,3): error TS0: const declaration only allowed when merging with an interface (go/ts-merged-namespaces)
-// test_files/decl_merge/rejected_ns.ts(38,3): error TS0: non-const values are not supported. (go/ts-merged-namespaces)
-// test_files/decl_merge/rejected_ns.ts(40,9): error TS0: 'K' must be exported. (go/ts-merged-namespaces)
-// test_files/decl_merge/rejected_ns.ts(42,16): error TS0: Destructuring declarations are not supported. (go/ts-merged-namespaces)
-// test_files/decl_merge/rejected_ns.ts(47,11): error TS0: nested namespaces are not supported. (go/ts-merged-namespaces)
+// test_files/decl_merge/rejected_ns.ts(13,11): error TS0: merged declaration must be local class, enum, or interface. (go/ts-merged-namespaces)
+// test_files/decl_merge/rejected_ns.ts(19,3): error TS0: const declaration only allowed when merging with an interface (go/ts-merged-namespaces)
+// test_files/decl_merge/rejected_ns.ts(24,3): error TS0: function declaration only allowed when merging with an enum (go/ts-merged-namespaces)
+// test_files/decl_merge/rejected_ns.ts(36,3): error TS0: non-const values are not supported. (go/ts-merged-namespaces)
+// test_files/decl_merge/rejected_ns.ts(38,9): error TS0: 'K' must be exported. (go/ts-merged-namespaces)
+// test_files/decl_merge/rejected_ns.ts(40,16): error TS0: Destructuring declarations are not supported. (go/ts-merged-namespaces)
+// test_files/decl_merge/rejected_ns.ts(44,3): error TS0: function declaration only allowed when merging with an enum (go/ts-merged-namespaces)
+// test_files/decl_merge/rejected_ns.ts(48,11): error TS0: nested namespaces are not supported. (go/ts-merged-namespaces)
/**
*
* @fileoverview Test namespace transformations that are not supported
@@ -24,21 +25,21 @@ goog.require('tslib');
* @return {void}
*/
function funcToBeMerged() { }
-/** @enum {number} */
-const Colors = {
- red: 0,
- green: 1,
- blue: 2,
-};
-Colors[Colors.red] = 'red';
-Colors[Colors.green] = 'green';
-Colors[Colors.blue] = 'blue';
// Adding const values is only allowed on interfaces.
class Cabbage {
}
(function (Cabbage) {
Cabbage.C = 0;
})(Cabbage || (Cabbage = {}));
+// Adding functions is only allowed on enums.
+(function (Cabbage) {
+ /**
+ * @return {void}
+ */
+ function foo() { }
+ Cabbage.foo = foo;
+ ;
+})(Cabbage || (Cabbage = {}));
/** @type {{a: number, b: string}} */
const o = {
a: 0,
@@ -60,6 +61,13 @@ var Inbetween;
// Destructuring declarations are not allowed.
Inbetween.a = o.a, Inbetween.b = o.b;
})(Inbetween || (Inbetween = {}));
+(function (Inbetween) {
+ /**
+ * @return {void}
+ */
+ function foo() { }
+ Inbetween.foo = foo;
+})(Inbetween || (Inbetween = {}));
// Nested namespaces are not supported.
class A {
}
diff --git a/test_files/decl_merge/rejected_ns.ts b/test_files/decl_merge/rejected_ns.ts
index 2e414d803..fdb0df004 100644
--- a/test_files/decl_merge/rejected_ns.ts
+++ b/test_files/decl_merge/rejected_ns.ts
@@ -12,13 +12,6 @@ namespace notMerging {}
function funcToBeMerged() {}
namespace funcToBeMerged {}
-// Declaration merging with enums is not supported.
-enum Colors {
- red,
- green,
- blue
-}
-namespace Colors {}
// Adding const values is only allowed on interfaces.
class Cabbage {}
@@ -26,6 +19,11 @@ namespace Cabbage {
export const C = 0;
}
+// Adding functions is only allowed on enums.
+namespace Cabbage {
+ export function foo() {};
+}
+
const o = {
a: 0,
b: ''
@@ -42,6 +40,9 @@ namespace Inbetween {
export const {a, b} = o;
}
+namespace Inbetween {
+ export function foo() {}
+}
// Nested namespaces are not supported.
class A {}
namespace A.B {}
diff --git a/test_files/declare_var_and_ns/externs.js b/test_files/declare_var_and_ns/externs.js
index eb909e167..9b522a4c1 100644
--- a/test_files/declare_var_and_ns/externs.js
+++ b/test_files/declare_var_and_ns/externs.js
@@ -6,8 +6,6 @@
// Generated from: test_files/declare_var_and_ns/declare_var_and_ns.d.ts
/** @type {!globalVariable.SomeInterface} */
var globalVariable;
-/** @const */
-var globalVariable = {};
/**
* @record
* @struct
diff --git a/test_files/enum.no_nstransform/enum.js b/test_files/enum.no_nstransform/enum.js
new file mode 100644
index 000000000..7c4ae2376
--- /dev/null
+++ b/test_files/enum.no_nstransform/enum.js
@@ -0,0 +1,42 @@
+/**
+ *
+ * @fileoverview Check that enums are translated to a var declaration
+ * when namespace transformation is turned off, i.e. the build target
+ * has the attribute --allow_unoptimized_namespaces.
+ * Generated from: test_files/enum.no_nstransform/enum.ts
+ * @suppress {checkTypes,uselessCode}
+ *
+ */
+goog.module('test_files.enum.no_nstransform.enum');
+var module = module || { id: 'test_files/enum.no_nstransform/enum.ts' };
+goog.require('tslib');
+/**
+ * This enum should be translated to `var E = {...}` instead of the usual
+ * `const E = {...}`
+ * @enum {number}
+ */
+var E = {
+ e0: 0,
+ e1: 1,
+ e2: 2,
+};
+exports.E = E;
+E[E.e0] = 'e0';
+E[E.e1] = 'e1';
+E[E.e2] = 'e2';
+// We need to emit the enum as a var declaration so that declaration
+// merging with a namespace works. The unoptimized namespace is emitted
+// by tsc as a var declaration and an IIFE.
+var E;
+(function (E) {
+ /**
+ * @param {string} s
+ * @return {?}
+ */
+ function fromString(s) {
+ return E.e0;
+ }
+ E.fromString = fromString;
+})(E || (E = {}));
+/** @type {!E} */
+const foo = E.e2;
diff --git a/test_files/enum.no_nstransform/enum.ts b/test_files/enum.no_nstransform/enum.ts
new file mode 100644
index 000000000..4f829e1d3
--- /dev/null
+++ b/test_files/enum.no_nstransform/enum.ts
@@ -0,0 +1,27 @@
+/**
+ * @fileoverview Check that enums are translated to a var declaration
+ * when namespace transformation is turned off, i.e. the build target
+ * has the attribute --allow_unoptimized_namespaces.
+ * @suppress {checkTypes,uselessCode}
+ */
+
+/**
+ * This enum should be translated to `var E = {...}` instead of the usual
+ * `const E = {...}`
+ */
+export enum E {
+ e0 = 0,
+ e1,
+ e2
+}
+
+// We need to emit the enum as a var declaration so that declaration
+// merging with a namespace works. The unoptimized namespace is emitted
+// by tsc as a var declaration and an IIFE.
+export namespace E {
+ export function fromString(s: string) {
+ return E.e0;
+ }
+}
+
+const foo = E.e2;
diff --git a/test_files/enum.puretransform/enum.js b/test_files/enum.puretransform/enum.js
new file mode 100644
index 000000000..b0a8c2eb8
--- /dev/null
+++ b/test_files/enum.puretransform/enum.js
@@ -0,0 +1,21 @@
+/**
+ * @fileoverview Test devmode (i.e. no JSDoc or special enum transformer) emit
+ * for enum merged with namespace.
+ * @suppress {missingProperties}
+ */
+goog.module('test_files.enum.puretransform.enum');
+var module = module || { id: 'test_files/enum.puretransform/enum.ts' };
+goog.require('tslib');
+var E;
+(function (E) {
+ E[E["e0"] = 0] = "e0";
+ E[E["e1"] = 1] = "e1";
+ E[E["e2"] = 2] = "e2";
+})(E || (E = {}));
+exports.E = E;
+(function (E) {
+ function fromString(s) {
+ return E.e0;
+ }
+ E.fromString = fromString;
+})(E || (E = {}));
diff --git a/test_files/enum.puretransform/enum.ts b/test_files/enum.puretransform/enum.ts
new file mode 100644
index 000000000..ecca84131
--- /dev/null
+++ b/test_files/enum.puretransform/enum.ts
@@ -0,0 +1,17 @@
+/**
+ * @fileoverview Test devmode (i.e. no JSDoc or special enum transformer) emit
+ * for enum merged with namespace.
+ * @suppress {missingProperties}
+ */
+
+export enum E {
+ e0 = 0,
+ e1,
+ e2
+}
+
+export namespace E {
+ export function fromString(s: string) {
+ return E.e0;
+ }
+}
diff --git a/test_files/enum/enum.js b/test_files/enum/enum.js
index 8041302d5..e67603054 100644
--- a/test_files/enum/enum.js
+++ b/test_files/enum/enum.js
@@ -57,7 +57,8 @@ let variableUsingExportedEnum;
const ComponentIndex = {
Scheme: 1,
UserInfo: 2,
- Domain: 0,
+ // TODO: b/313666408 - Fix tsc to not duplicate comments like the following
+ Domain: 0, // Be sure to exercise the code with a 0 enum value.
// Be sure to exercise the code with a 0 enum value.
UserInfo2: 2,
};
diff --git a/test_files/enum/enum.ts b/test_files/enum/enum.ts
index 8f913933b..b070ff424 100644
--- a/test_files/enum/enum.ts
+++ b/test_files/enum/enum.ts
@@ -36,6 +36,7 @@ let variableUsingExportedEnum: EnumTest2;
enum ComponentIndex {
Scheme = 1,
UserInfo,
+ // TODO: b/313666408 - Fix tsc to not duplicate comments like the following
Domain = 0, // Be sure to exercise the code with a 0 enum value.
UserInfo2 = UserInfo,
}
diff --git a/test_files/export_destructuring/export_destructuring.js b/test_files/export_destructuring/export_destructuring.js
new file mode 100644
index 000000000..11a67dad3
--- /dev/null
+++ b/test_files/export_destructuring/export_destructuring.js
@@ -0,0 +1,33 @@
+goog.module('test_files.export_destructuring.export_destructuring');
+var module = module || { id: 'test_files/export_destructuring/export_destructuring.ts' };
+goog.require('tslib');
+var _a, _b;
+/**
+ *
+ * @fileoverview
+ * Generated from: test_files/export_destructuring/export_destructuring.ts
+ * @suppress {undefinedVars}
+ *
+ */
+/**
+ * @param {number} n
+ * @return {!Array}
+ */
+function signal(n) {
+ return [n, n + 1];
+}
+/**
+ * @param {number} n
+ * @return {{c: number, d: number}}
+ */
+function objectLiteral(n) {
+ return { c: n, d: n + 1 };
+}
+_a = signal(0);
+a__tsickle_destructured_1 = _a[0];
+b__tsickle_destructured_2 = _a[1];
+const a = /** @type {number} */ (a__tsickle_destructured_1);
+const b = /** @type {number} */ (b__tsickle_destructured_2);
+_b = objectLiteral(0);
+exports.c = _b.c;
+exports.d = _b.d;
diff --git a/test_files/export_destructuring/export_destructuring.ts b/test_files/export_destructuring/export_destructuring.ts
new file mode 100644
index 000000000..1d5f15211
--- /dev/null
+++ b/test_files/export_destructuring/export_destructuring.ts
@@ -0,0 +1,15 @@
+/**
+ * @fileoverview
+ * @suppress {undefinedVars}
+ */
+
+function signal(n: number) {
+ return [n, n + 1];
+}
+function objectLiteral(n: number) {
+ return {c: n, d: n + 1};
+}
+
+export const [a, b] = signal(0);
+
+export const {c, d} = objectLiteral(0);
diff --git a/test_files/import_by_path.declaration.no_externs/clutz_input.d.ts b/test_files/import_by_path.declaration.no_externs/clutz_input.d.ts
deleted file mode 100644
index 7dde5e336..000000000
--- a/test_files/import_by_path.declaration.no_externs/clutz_input.d.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-// Mocks for Clutz-generated .d.ts.
-
-declare namespace ಠ_ಠ.clutz.another.module {
- export class SomeClass {}
-}
-declare module 'goog:another.module' {
-import SomeClass = ಠ_ಠ.clutz.another.module.SomeClass;
- export {SomeClass};
-}
-declare module 'google3/another/file' {
-import SomeClass = ಠ_ಠ.clutz.another.module.SomeClass;
- export {SomeClass};
- const __clutz_actual_namespace: 'another.module';
-}
diff --git a/test_files/import_by_path.declaration.no_externs/decluser.d.ts b/test_files/import_by_path.declaration.no_externs/decluser.d.ts
deleted file mode 100644
index c845f22b6..000000000
--- a/test_files/import_by_path.declaration.no_externs/decluser.d.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-//!! generated by tsickle from test_files/import_by_path.declaration.no_externs/decluser.ts
-import "test_files/import_by_path.declaration.no_externs/clutz_input";
-import { SomeClass } from 'google3/another/file';
-export declare class UsingPathImports {
- someField?: SomeClass;
-}
-declare global {
- namespace ಠ_ಠ.clutz {
- export { UsingPathImports as module$contents$test_files$import_by_path$declaration$no_externs$decluser_UsingPathImports };
- export namespace module$exports$test_files$import_by_path$declaration$no_externs$decluser {
- export { UsingPathImports };
- }
- }
-}
diff --git a/test_files/import_by_path.declaration.no_externs/decluser.ts b/test_files/import_by_path.declaration.no_externs/decluser.ts
deleted file mode 100644
index 7b01a7f96..000000000
--- a/test_files/import_by_path.declaration.no_externs/decluser.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-import {SomeClass} from 'google3/another/file';
-
-export class UsingPathImports {
- someField?: SomeClass;
-}
diff --git a/test_files/import_by_path.declaration.no_externs/jsprovides.js b/test_files/import_by_path.declaration.no_externs/jsprovides.js
deleted file mode 100644
index 26ec015a9..000000000
--- a/test_files/import_by_path.declaration.no_externs/jsprovides.js
+++ /dev/null
@@ -1,7 +0,0 @@
-/**
- * @fileoverview Description of this file.
- */
-
-goog.module('another.module');
-
-exports.SomeClass = class {};
diff --git a/test_files/internal.declaration/internal.d.ts b/test_files/internal.declaration/internal.d.ts
index eae8448e9..1bd9c76a6 100644
--- a/test_files/internal.declaration/internal.d.ts
+++ b/test_files/internal.declaration/internal.d.ts
@@ -1,3 +1,8 @@
// test_files/internal.declaration/internal.ts(27,18): error TS0: transformation of plain namespace not supported. (go/ts-merged-namespaces)
//!! generated by tsickle from test_files/internal.declaration/internal.ts
+/**
+ * @fileoverview Test to reproduce that \@internal declarations are not
+ * re-exported for Clutz. There should not be any `.d.ts` aliases generated for
+ * the declarations below.
+ */
export {};
diff --git a/test_files/typeof_function_overloads/user.js b/test_files/typeof_function_overloads/user.js
new file mode 100644
index 000000000..235469fe2
--- /dev/null
+++ b/test_files/typeof_function_overloads/user.js
@@ -0,0 +1,21 @@
+/**
+ *
+ * @fileoverview Test overloaded function type emit.
+ *
+ * Generated from: test_files/typeof_function_overloads/user.ts
+ */
+goog.module('test_files.typeof_function_overloads.user');
+var module = module || { id: 'test_files/typeof_function_overloads/user.ts' };
+goog.require('tslib');
+/**
+ * @param {?=} initialValue
+ * @return {null}
+ */
+function ɵinput(initialValue) {
+ return null;
+}
+exports.ɵinput = ɵinput;
+/** @typedef {function(?=): null} */
+exports.InputFn;
+/** @type {function(?=): null} */
+exports.input = ɵinput;
diff --git a/test_files/typeof_function_overloads/user.ts b/test_files/typeof_function_overloads/user.ts
new file mode 100644
index 000000000..f4233189f
--- /dev/null
+++ b/test_files/typeof_function_overloads/user.ts
@@ -0,0 +1,11 @@
+/**
+ * @fileoverview Test overloaded function type emit.
+ */
+
+export function ɵinput(): null;
+export function ɵinput(initialValue: any): null;
+export function ɵinput(initialValue?: any): null {
+ return null;
+}
+export type InputFn = typeof ɵinput;
+export const input = ɵinput;