From 96f1cb3094447d9a3aa49586b21b44a9e5df85d9 Mon Sep 17 00:00:00 2001 From: Jan Kuehle Date: Fri, 26 Jan 2024 08:16:02 -0800 Subject: [PATCH] Fix const enum exports Align const enum exports with TypeScript. That is: - preserveConstEnums is disabled --> only export the type, runtime values are elided - preserveConstEnums is enabled --> export the value if the const enum is declared in a .ts file from the same compilation unit; otherwise export type only When is preserveConstEnums enabled, isolatedModules is likely enabled, too. isolatedModules prevents const enum usage when the enum comes from .d.ts files. Star re-exports are allowed, though. It's possible the enum is then imported from a compilation unit that does not use isolatedModules. That unit needs the type info, so it's important to always export the type. But that unit won't access the value because const enums are inlined. PiperOrigin-RevId: 601770954 --- demo/package.json | 2 +- package.json | 4 +- src/clutz.ts | 59 +- src/decorators.ts | 6 +- src/enum_transformer.ts | 9 +- src/externs.ts | 13 +- src/googmodule.ts | 137 ++-- src/jsdoc_transformer.ts | 52 +- src/ns_transformer.ts | 49 +- src/summary.ts | 1 + src/transformer_util.ts | 18 +- src/ts_migration_exports_shim.ts | 3 + src/tsickle.ts | 36 +- src/tsickle_declaration_marker.ts | 38 -- src/type_translator.ts | 22 + test/googmodule_test.ts | 26 +- test/test_support.ts | 15 + test/tsickle_test.ts | 153 +++-- test_files/augment/externs.js | 2 - .../clutz2_output_demo8.d.ts | 18 - .../clutz_output_demo1.d.ts | 16 - .../clutz_output_demo2.d.ts | 16 - .../clutz_output_demo3.d.ts | 16 - .../clutz_output_demo4.d.ts | 13 - .../clutz_output_demo5.d.ts | 17 - .../clutz_output_demo6.d.ts | 18 - .../clutz_output_demo7.d.ts | 11 - .../user_code.d.ts | 53 -- .../user_code.ts | 69 -- test_files/comments/trailing_no_semicolon.js | 22 + test_files/comments/trailing_no_semicolon.ts | 17 + test_files/decl_merge/outer_enum.js | 31 + test_files/decl_merge/outer_enum.ts | 20 + test_files/decl_merge/rejected_ns.js | 42 +- test_files/decl_merge/rejected_ns.ts | 15 +- test_files/declare_var_and_ns/externs.js | 2 - test_files/enum.no_nstransform/enum.js | 42 ++ test_files/enum.no_nstransform/enum.ts | 27 + test_files/enum.puretransform/enum.js | 21 + test_files/enum.puretransform/enum.ts | 17 + test_files/enum/enum.js | 3 +- test_files/enum/enum.ts | 1 + test_files/export/export.js | 2 + test_files/export/export_helper.js | 2 + test_files/export/export_star_imported.js | 2 + .../export_destructuring.js | 28 + .../export_destructuring.ts | 11 + .../clutz_input.d.ts | 14 - .../decluser.d.ts | 14 - .../decluser.ts | 5 - .../jsprovides.js | 7 - test_files/internal.declaration/internal.d.ts | 5 + test_files/typeof_function_overloads/user.js | 21 + test_files/typeof_function_overloads/user.ts | 11 + yarn.lock | 603 ++++++++++++++++++ 55 files changed, 1303 insertions(+), 574 deletions(-) delete mode 100644 src/tsickle_declaration_marker.ts delete mode 100644 test_files/clutz_imports.declaration.no_externs/clutz2_output_demo8.d.ts delete mode 100644 test_files/clutz_imports.declaration.no_externs/clutz_output_demo1.d.ts delete mode 100644 test_files/clutz_imports.declaration.no_externs/clutz_output_demo2.d.ts delete mode 100644 test_files/clutz_imports.declaration.no_externs/clutz_output_demo3.d.ts delete mode 100644 test_files/clutz_imports.declaration.no_externs/clutz_output_demo4.d.ts delete mode 100644 test_files/clutz_imports.declaration.no_externs/clutz_output_demo5.d.ts delete mode 100644 test_files/clutz_imports.declaration.no_externs/clutz_output_demo6.d.ts delete mode 100644 test_files/clutz_imports.declaration.no_externs/clutz_output_demo7.d.ts delete mode 100644 test_files/clutz_imports.declaration.no_externs/user_code.d.ts delete mode 100644 test_files/clutz_imports.declaration.no_externs/user_code.ts create mode 100644 test_files/comments/trailing_no_semicolon.js create mode 100644 test_files/comments/trailing_no_semicolon.ts create mode 100644 test_files/decl_merge/outer_enum.js create mode 100644 test_files/decl_merge/outer_enum.ts create mode 100644 test_files/enum.no_nstransform/enum.js create mode 100644 test_files/enum.no_nstransform/enum.ts create mode 100644 test_files/enum.puretransform/enum.js create mode 100644 test_files/enum.puretransform/enum.ts create mode 100644 test_files/export_destructuring/export_destructuring.js create mode 100644 test_files/export_destructuring/export_destructuring.ts delete mode 100644 test_files/import_by_path.declaration.no_externs/clutz_input.d.ts delete mode 100644 test_files/import_by_path.declaration.no_externs/decluser.d.ts delete mode 100644 test_files/import_by_path.declaration.no_externs/decluser.ts delete mode 100644 test_files/import_by_path.declaration.no_externs/jsprovides.js create mode 100644 test_files/typeof_function_overloads/user.js create mode 100644 test_files/typeof_function_overloads/user.ts create mode 100644 yarn.lock 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..a8bd94289 100644 --- a/src/jsdoc_transformer.ts +++ b/src/jsdoc_transformer.ts @@ -791,7 +791,8 @@ export function jsdocTransformer( ts.setSyntheticLeadingComments(commentHolder, leading.filter(c => c.text[0] !== '*')); stmts.push(commentHolder); } - + const isExported = varStmt.modifiers?.some( + (modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword); for (const decl of varStmt.declarationList.declarations) { const localTags: jsdoc.Tag[] = []; if (tags) { @@ -827,14 +828,14 @@ 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, declVisited.type, declVisited.initializer); const newStmt = ts.factory.createVariableStatement( - varStmt.modifiers, + varStmt.modifiers?.filter( + (modifier) => + modifier.kind !== ts.SyntaxKind.ExportKeyword), ts.factory.createVariableDeclarationList([newDecl], flags)); if (localTags.length) { addCommentOn( @@ -842,14 +843,13 @@ export function jsdocTransformer( } stmts.push(newStmt); stmts.push(...createArrayBindingAliases( - varStmt.declarationList.flags, aliases)); + varStmt.declarationList.flags, aliases, isExported)); 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)); @@ -1116,8 +1116,12 @@ export function jsdocTransformer( // Note: We create explicit exports of type symbols for closure in visitExportDeclaration. return false; } - if (!tsOptions.preserveConstEnums && sym.flags & ts.SymbolFlags.ConstEnum) { - return false; + if (sym.flags & ts.SymbolFlags.ConstEnum) { + if (tsOptions.preserveConstEnums) { + return !sym.valueDeclaration!.getSourceFile().isDeclarationFile; + } else { + return false; + } } return true; } @@ -1172,7 +1176,7 @@ export function jsdocTransformer( exportDecl = ts.factory.updateExportDeclaration( exportDecl, exportDecl.modifiers, isTypeOnlyExport, ts.factory.createNamedExports(exportSpecifiers), - exportDecl.moduleSpecifier, exportDecl.assertClause); + exportDecl.moduleSpecifier, exportDecl.attributes); } else if (ts.isNamedExports(exportDecl.exportClause)) { // export {a, b, c} from 'abc'; for (const exp of exportDecl.exportClause.elements) { @@ -1192,7 +1196,9 @@ export function jsdocTransformer( } const isTypeAlias = (aliasedSymbol.flags & ts.SymbolFlags.Value) === 0 && (aliasedSymbol.flags & (ts.SymbolFlags.TypeAlias | ts.SymbolFlags.Interface)) !== 0; - if (!isTypeAlias) continue; + const isConstEnum = + (aliasedSymbol.flags & ts.SymbolFlags.ConstEnum) !== 0; + if (!isTypeAlias && !isConstEnum) continue; const typeName = moduleTypeTranslator.symbolsToAliasedNames.get(aliasedSymbol) || aliasedSymbol.name; const stmt = ts.factory.createExpressionStatement( @@ -1322,8 +1328,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); @@ -1336,8 +1340,8 @@ export function jsdocTransformer( * controls const/let/var in particular. */ function createArrayBindingAliases( - flags: ts.NodeFlags, - aliases: Array<[ts.Identifier, ts.Identifier]>): ts.Statement[] { + flags: ts.NodeFlags, aliases: Array<[ts.Identifier, ts.Identifier]>, + needsExport = false): ts.Statement[] { const aliasDecls: ts.Statement[] = []; for (const [oldName, aliasName] of aliases) { const typeStr = @@ -1354,7 +1358,10 @@ export function jsdocTransformer( /* type? */ undefined, closureCastExpr)], flags); const varStmt = ts.factory.createVariableStatement( - /*modifiers*/ undefined, varDeclList); + needsExport ? + [ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)] : + undefined, + varDeclList); aliasDecls.push(varStmt); } return aliasDecls; @@ -1406,22 +1413,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..c6f825471 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,14 +24,13 @@ 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'; // Retained here for API compatibility. export {getGeneratedExterns} from './externs'; -export {FileMap, ModulesManifest} from './modules_manifest'; -export {FileSummary, ModuleType, Symbol, Type} from './summary'; +export {type FileMap, ModulesManifest} from './modules_manifest'; +export {FileSummary, ModuleType, type Symbol, Type} from './summary'; export interface TsickleHost extends googmodule.GoogModuleProcessorHost, tsmes.TsMigrationExportsShimProcessorHost, @@ -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..2b6e84ed5 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, }, @@ -100,20 +100,56 @@ describe('emitWithTsickle', () => { expect(jsSources['a.js']).toContain('exports.x = 2;'); }); - it('should export const enums when preserveConstEnums is true', () => { - const tsSources = { - 'a.ts': `export const enum Foo { Bar };`, - 'b.ts': `export * from './a';`, - }; + describe('const enum exports', () => { + it('should export value when preserveConstEnums is enabled (from .ts file)', () => { + const tsSources = { + // Simulate a.ts, b.ts and c.ts being in the same compilation unit. + 'a.ts': `export const enum Foo { Bar }`, + 'b.ts': `export * from './a';`, + 'c.ts': `export {Foo as Bar} from './a';`, + }; + + const {jsSources} = emitWithTsickle(tsSources, { + preserveConstEnums: true, + module: ts.ModuleKind.ES2015, + }); + + expect(jsSources['b.js']).toContain(`export { Foo } from './a';`); + expect(jsSources['c.js']).toContain(`export { Foo as Bar } from './a';`); + }); - const jsSources = emitWithTsickle( - tsSources, { - preserveConstEnums: true, - module: ts.ModuleKind.ES2015, - }, - {googmodule: false}); + it('should export type when preserveConstEnums is enabled (from .d.ts file)', () => { + const tsSources = { + // Simulate a.d.ts coming from a different compilation unit. + 'a.d.ts': `export declare const enum Foo { Bar = 0 }`, + 'b.ts': `export * from './a';`, + 'c.ts': `export {Foo as Bar} from './a';`, + }; + + const {jsSources} = emitWithTsickle(tsSources, { + preserveConstEnums: true, + module: ts.ModuleKind.ES2015, + }); + + expect(jsSources['b.js']).toContain(`exports.Foo; // re-export typedef`); + expect(jsSources['c.js']).toContain(`exports.Bar; // re-export typedef`); + }); + + it('should export type when preserveConstEnums is disabled', () => { + const tsSources = { + 'a.ts': `export const enum Foo { Bar }`, + 'b.ts': `export * from './a';`, + 'c.ts': `export {Foo as Bar} from './a';`, + }; - expect(jsSources['b.js']).toContain(`export { Foo } from './a';`); + const {jsSources} = emitWithTsickle(tsSources, { + preserveConstEnums: false, + module: ts.ModuleKind.ES2015, + }); + + expect(jsSources['b.js']).toContain(`exports.Foo; // re-export typedef`); + expect(jsSources['c.js']).toContain(`exports.Bar; // re-export typedef`); + }); }); it('should not go into an infinite loop with a self-referential type', () => { @@ -121,16 +157,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 +222,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/export.js b/test_files/export/export.js index 614faff4b..85df4d44b 100644 --- a/test_files/export/export.js +++ b/test_files/export/export.js @@ -21,6 +21,8 @@ exports.RenamedTypeDef; // re-export typedef exports.TypeDef; // re-export typedef /** @typedef {!tsickle_export_helper_1.Interface} */ exports.Interface; // re-export typedef +/** @typedef {!tsickle_export_helper_1.ConstEnum} */ +exports.ConstEnum; // re-export typedef /** @typedef {!tsickle_export_helper_1.DeclaredType} */ exports.DeclaredType; // re-export typedef /** @typedef {!tsickle_export_helper_1.DeclaredInterface} */ diff --git a/test_files/export/export_helper.js b/test_files/export/export_helper.js index 5cad2eee1..637d2dc59 100644 --- a/test_files/export/export_helper.js +++ b/test_files/export/export_helper.js @@ -16,6 +16,8 @@ exports.export4 = export_helper_2_1.export4; exports.TypeDef; // re-export typedef /** @typedef {!tsickle_export_helper_2_1.Interface} */ exports.Interface; // re-export typedef +/** @typedef {!tsickle_export_helper_2_1.ConstEnum} */ +exports.ConstEnum; // re-export typedef /** @typedef {!tsickle_export_helper_2_1.DeclaredType} */ exports.DeclaredType; // re-export typedef /** @typedef {!tsickle_export_helper_2_1.DeclaredInterface} */ diff --git a/test_files/export/export_star_imported.js b/test_files/export/export_star_imported.js index 574f72e86..9691e435d 100644 --- a/test_files/export/export_star_imported.js +++ b/test_files/export/export_star_imported.js @@ -22,6 +22,8 @@ exports.RenamedTypeDef; // re-export typedef exports.TypeDef; // re-export typedef /** @typedef {!tsickle_export_helper_1.Interface} */ exports.Interface; // re-export typedef +/** @typedef {!tsickle_export_helper_1.ConstEnum} */ +exports.ConstEnum; // re-export typedef /** @typedef {!tsickle_export_helper_1.DeclaredType} */ exports.DeclaredType; // re-export typedef /** @typedef {!tsickle_export_helper_1.DeclaredInterface} */ diff --git a/test_files/export_destructuring/export_destructuring.js b/test_files/export_destructuring/export_destructuring.js new file mode 100644 index 000000000..5958c9f94 --- /dev/null +++ b/test_files/export_destructuring/export_destructuring.js @@ -0,0 +1,28 @@ +goog.module('test_files.export_destructuring.export_destructuring'); +var module = module || { id: 'test_files/export_destructuring/export_destructuring.ts' }; +goog.require('tslib'); +var _a; +/** + * @fileoverview added by tsickle + * Generated from: test_files/export_destructuring/export_destructuring.ts + */ +/** + * @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 }; +} +const [a__tsickle_destructured_1, b__tsickle_destructured_2] = signal(0); +exports.a = /** @type {number} */ (a__tsickle_destructured_1); +exports.b = /** @type {number} */ (b__tsickle_destructured_2); +_a = objectLiteral(0); +exports.c = _a.c; +exports.d = _a.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..87fcaff10 --- /dev/null +++ b/test_files/export_destructuring/export_destructuring.ts @@ -0,0 +1,11 @@ + +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; diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 000000000..6489d7c35 --- /dev/null +++ b/yarn.lock @@ -0,0 +1,603 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@babel/code-frame@^7.0.0": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.13.tgz#dcfc826beef65e75c50e21d3837d7d95798dd658" + integrity sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g== + dependencies: + "@babel/highlight" "^7.12.13" + +"@babel/helper-validator-identifier@^7.14.0": + version "7.14.0" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.0.tgz#d26cad8a47c65286b15df1547319a5d0bcf27288" + integrity sha512-V3ts7zMSu5lfiwWDVWzRDGIN+lnCEUdaXgtVHJgLb1rGaA6jMrtB9EmE7L18foXJIE8Un/A/h6NJfGQp/e1J4A== + +"@babel/highlight@^7.12.13": + version "7.14.0" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.14.0.tgz#3197e375711ef6bf834e67d0daec88e4f46113cf" + integrity sha512-YSCOwxvTYEIMSGaBQb5kDDsCopDdiUGsqpatp3fOlI4+2HQSkTmEVWnVuySdAC5EWCqSWWTv0ib63RjR7dTBdg== + dependencies: + "@babel/helper-validator-identifier" "^7.14.0" + chalk "^2.0.0" + js-tokens "^4.0.0" + +"@types/diff-match-patch@^1.0.32": + version "1.0.32" + resolved "https://registry.yarnpkg.com/@types/diff-match-patch/-/diff-match-patch-1.0.32.tgz#d9c3b8c914aa8229485351db4865328337a3d09f" + integrity sha512-bPYT5ECFiblzsVzyURaNhljBH2Gh1t9LowgUwciMrNAhFewLkHT2H0Mto07Y4/3KCOGZHRQll3CTtQZ0X11D/A== + +"@types/events@*": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7" + integrity sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g== + +"@types/glob@5.0.35": + version "5.0.35" + resolved "https://registry.yarnpkg.com/@types/glob/-/glob-5.0.35.tgz#1ae151c802cece940443b5ac246925c85189f32a" + integrity sha512-wc+VveszMLyMWFvXLkloixT4n0harUIVZjnpzztaZ0nKLuul7Z32iMt2fUFGAaZ4y1XWjFRMtCI5ewvyh4aIeg== + dependencies: + "@types/events" "*" + "@types/minimatch" "*" + "@types/node" "*" + +"@types/jasmine@^3.7.7": + version "3.7.7" + resolved "https://registry.yarnpkg.com/@types/jasmine/-/jasmine-3.7.7.tgz#56718af036be3c9f86eca560a22e39440b2b0784" + integrity sha512-yZzGe1d1T0y+imXDZ79F030nn8qbmiwpWKCZKvKN0KbTzwXAVYShUxkIxu1ba+vhIdabTGVGCfbtZC0oOam8TQ== + +"@types/minimatch@*": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.4.tgz#f0ec25dbf2f0e4b18647313ac031134ca5b24b21" + integrity sha512-1z8k4wzFnNjVK/tlxvrWuK5WMt6mydWWP7+zvH5eFep4oj+UkrfiJTRtjCeBXNpwaA/FYqqtb4/QS4ianFpIRA== + +"@types/minimist@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.1.tgz#283f669ff76d7b8260df8ab7a4262cc83d988256" + integrity sha512-fZQQafSREFyuZcdWFAExYjBiCL7AUCdgsk80iO0q4yihYYdcIiH28CcuPTGFgLOCC8RlW49GSQxdHwZP+I7CNg== + +"@types/node@*": + version "15.12.1" + resolved "https://registry.yarnpkg.com/@types/node/-/node-15.12.1.tgz#9b60797dee1895383a725f828a869c86c6caa5c2" + integrity sha512-zyxJM8I1c9q5sRMtVF+zdd13Jt6RU4r4qfhTd7lQubyThvLfx6yYekWSQjGCGV2Tkecgxnlpl/DNlb6Hg+dmEw== + +"@types/node@^10.5.6": + version "10.17.60" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.60.tgz#35f3d6213daed95da7f0f73e75bcc6980e90597b" + integrity sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw== + +"@types/source-map-support@^0.5.3": + version "0.5.3" + resolved "https://registry.yarnpkg.com/@types/source-map-support/-/source-map-support-0.5.3.tgz#acb6b3e499c20692552d16934c16162c84594e16" + integrity sha512-fvjMjVH8Rmokw2dWh1dkj90iX5R8FPjeZzjNH+6eFXReh0QnHFf1YBl3B0CF0RohIAA3SDRJsGeeUWKl6d7HqA== + dependencies: + source-map "^0.6.0" + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +buffer-from@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" + integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== + +builtin-modules@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" + integrity sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8= + +chalk@2.x, chalk@^2.0.0, chalk@^2.3.0: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +clone-buffer@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/clone-buffer/-/clone-buffer-1.0.0.tgz#e3e25b207ac4e701af721e2cb5a16792cac3dc58" + integrity sha1-4+JbIHrE5wGvch4staFnksrD3Fg= + +clone-stats@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/clone-stats/-/clone-stats-1.0.0.tgz#b3782dff8bb5474e18b9b6bf0fdfe782f8777680" + integrity sha1-s3gt/4u1R04Yuba/D9/ngvh3doA= + +clone@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f" + integrity sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18= + +cloneable-readable@^1.0.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/cloneable-readable/-/cloneable-readable-1.1.3.tgz#120a00cb053bfb63a222e709f9683ea2e11d8cec" + integrity sha512-2EF8zTQOxYq70Y4XKtorQupqF0m49MBz2/yf5Bj+MHjvpG3Hy7sImifnqD6UA+TKYxeSV+u6qqQPawN5UvnpKQ== + dependencies: + inherits "^2.0.1" + process-nextick-args "^2.0.0" + readable-stream "^2.3.5" + +coffeescript@~1.12.7: + version "1.12.7" + resolved "https://registry.yarnpkg.com/coffeescript/-/coffeescript-1.12.7.tgz#e57ee4c4867cf7f606bfc4a0f2d550c0981ddd27" + integrity sha512-pLXHFxQMPklVoEekowk8b3erNynC+DVJzChxS/LCBBgR6/8AJkHivkm//zbowcfc7BTCAjryuhx6gPqPRfsFoA== + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= + +commander@^2.12.1: + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + +core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= + +diff-match-patch@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/diff-match-patch/-/diff-match-patch-1.0.5.tgz#abb584d5f10cd1196dfc55aa03701592ae3f7b37" + integrity sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw== + +diff@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" + integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= + +esprima@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +gaze@~1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/gaze/-/gaze-1.1.3.tgz#c441733e13b927ac8c0ff0b4c3b033f28812924a" + integrity sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g== + dependencies: + globule "^1.0.0" + +glob@7.1.2: + version "7.1.2" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" + integrity sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^7.1.1, glob@^7.1.6, glob@~7.1.1: + version "7.1.7" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90" + integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +globule@^1.0.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/globule/-/globule-1.3.2.tgz#d8bdd9e9e4eef8f96e245999a5dee7eb5d8529c4" + integrity sha512-7IDTQTIu2xzXkT+6mlluidnWo+BypnbSoEVVQCGfzqnl5Ik8d3e1d4wycb8Rj9tWW+Z39uPWsdlquqiqPCd/pA== + dependencies: + glob "~7.1.1" + lodash "~4.17.10" + minimatch "~3.0.2" + +google-closure-compiler-java@^20190929.0.0: + version "20190929.0.0" + resolved "https://registry.yarnpkg.com/google-closure-compiler-java/-/google-closure-compiler-java-20190929.0.0.tgz#faa2c5750982a79c8a4c27999164842502d6b80a" + integrity sha512-fDThDeix5BDIQrP1ESznDq6VDLxY539JF2Hhm+/+XfgXz/kfxWB6RIcsHF+pI4QdNYEEaUGsE3gvF0bYpesUUQ== + +google-closure-compiler-js@^20190929.0.0: + version "20190929.0.0" + resolved "https://registry.yarnpkg.com/google-closure-compiler-js/-/google-closure-compiler-js-20190929.0.0.tgz#6b62c7122fcce86a978a5496fb593949452edefe" + integrity sha512-IB9GJCJPGcSNZWtferd15lA9InUaab9oWPZhJssZN3z/nsHPzV9SqKJLj2oajmcaf2uINhlOIsCVWZwC+AbwVA== + +google-closure-compiler-linux@^20190929.0.0: + version "20190929.0.0" + resolved "https://registry.yarnpkg.com/google-closure-compiler-linux/-/google-closure-compiler-linux-20190929.0.0.tgz#394b29e8c294498be34f5e86eb3f38fa5d2abe6a" + integrity sha512-gu/H1z7MqC43rXnGGoUyGdb12kTFpkDNw0huKj1ScXNvHgq5fQteicQKd7EpiKOIlMBJbJOKoVFNpU1nrAfNvQ== + +google-closure-compiler-osx@^20190929.0.0: + version "20190929.0.0" + resolved "https://registry.yarnpkg.com/google-closure-compiler-osx/-/google-closure-compiler-osx-20190929.0.0.tgz#06e501a0c7ae78b6bc16c260ba137c82bb9d933f" + integrity sha512-SZbp2BOhwjrJdrShZ4HrtBHOEJyKvOtka47uXyo83AdZMX22EV04z+mQCMFHtBautgG/mCsL8eX75nlMPXzkjg== + +google-closure-compiler-windows@^20190929.0.0: + version "20190929.0.0" + resolved "https://registry.yarnpkg.com/google-closure-compiler-windows/-/google-closure-compiler-windows-20190929.0.0.tgz#d6ab1ff5c74d87302884cc7691349d2f14e73b51" + integrity sha512-b1azZx19cQnYqwof+4KxWcjjOJ88QeDDIvmjCmuAZjXG5UC0os/1cutg0AeK3gZnXAsaQwAh3szy+QGKT6IgWw== + +google-closure-compiler@^20190929.0.0: + version "20190929.0.0" + resolved "https://registry.yarnpkg.com/google-closure-compiler/-/google-closure-compiler-20190929.0.0.tgz#9ddd9150e852fe6486e7840ba8277e67ee50ec72" + integrity sha512-psPXU3rfTbx4WsTOxtxCnNQqZdphdH1fS7KbqISJ3Bk1G6WMFapnCUHdnXsFz96i/XrVaTxjwUfrNdoz/F+PsA== + dependencies: + chalk "2.x" + google-closure-compiler-java "^20190929.0.0" + google-closure-compiler-js "^20190929.0.0" + minimist "1.x" + vinyl "2.x" + vinyl-sourcemaps-apply "^0.2.0" + optionalDependencies: + google-closure-compiler-linux "^20190929.0.0" + google-closure-compiler-osx "^20190929.0.0" + google-closure-compiler-windows "^20190929.0.0" + +growl@^1.10.5: + version "1.10.5" + resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" + integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA== + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= + +has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@^2.0.1, inherits@~2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +is-core-module@^2.2.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.4.0.tgz#8e9fc8e15027b011418026e98f0e6f4d86305cc1" + integrity sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A== + dependencies: + has "^1.0.3" + +isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= + +jasmine-core@~3.7.0: + version "3.7.1" + resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-3.7.1.tgz#0401327f6249eac993d47bbfa18d4e8efacfb561" + integrity sha512-DH3oYDS/AUvvr22+xUBW62m1Xoy7tUlY1tsxKEJvl5JeJ7q8zd1K5bUwiOxdH+erj6l2vAMM3hV25Xs9/WrmuQ== + +jasmine-growl-reporter@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/jasmine-growl-reporter/-/jasmine-growl-reporter-2.0.0.tgz#4943a2481193d66a8a68ee2f38b6c360fb037859" + integrity sha512-RYwVfPaGgxQQSHDOt6jQ99/KAkFQ/Fiwg/AzBS+uO9A4UhGhxb7hwXaUUSU/Zs0MxBoFNqmIRC+7P4/+5O3lXg== + dependencies: + growl "^1.10.5" + +jasmine-node@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/jasmine-node/-/jasmine-node-3.0.0.tgz#f12b6fdd24633402ec23e8ea6fef6ffbcb464f90" + integrity sha512-vUa5Q7bQYwHHqi6FlJYndiKqZp+d+c3MKe0QUMwwrC4JRmoRV3zkg0buxB/uQ6qLh0NO34TNstpAnvaZ6xGlAA== + dependencies: + coffeescript "~1.12.7" + gaze "~1.1.2" + jasmine-growl-reporter "~2.0.0" + jasmine-reporters "~1.0.0" + mkdirp "~0.3.5" + requirejs "~2.3.6" + underscore "~1.9.1" + walkdir "~0.0.12" + +jasmine-reporters@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/jasmine-reporters/-/jasmine-reporters-1.0.2.tgz#ab613ed5977dc7487e85b3c12f6a8ea8db2ade31" + integrity sha1-q2E+1Zd9x0h+hbPBL2qOqNsq3jE= + dependencies: + mkdirp "~0.3.5" + +jasmine@^3.7.0: + version "3.7.0" + resolved "https://registry.yarnpkg.com/jasmine/-/jasmine-3.7.0.tgz#d36638c0c815e6ad5666676e386d79e2ccb70835" + integrity sha512-wlzGQ+cIFzMEsI+wDqmOwvnjTvolLFwlcpYLCqSPPH0prOQaW3P+IzMhHYn934l1imNvw07oCyX+vGUv3wmtSQ== + dependencies: + glob "^7.1.6" + jasmine-core "~3.7.0" + +js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@^3.13.1: + version "3.14.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" + integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +lodash@~4.17.10: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +minimatch@^3.0.4, minimatch@~3.0.2: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== + dependencies: + brace-expansion "^1.1.7" + +minimist@1.x, minimist@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" + integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== + +mkdirp@^0.5.3: + version "0.5.5" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" + integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== + dependencies: + minimist "^1.2.5" + +mkdirp@~0.3.5: + version "0.3.5" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.3.5.tgz#de3e5f8961c88c787ee1368df849ac4413eca8d7" + integrity sha1-3j5fiWHIjHh+4TaN+EmsRBPsqNc= + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + dependencies: + wrappy "1" + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + +path-parse@^1.0.6: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +process-nextick-args@^2.0.0, process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + +readable-stream@^2.3.5: + version "2.3.7" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" + integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +remove-trailing-separator@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" + integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= + +replace-ext@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-1.0.1.tgz#2d6d996d04a15855d967443631dd5f77825b016a" + integrity sha512-yD5BHCe7quCgBph4rMQ+0KkIRKwWCrHDOX1p1Gp6HwjPM5kVoCdKGNhN7ydqqsX6lJEnQDKZ/tFMiEdQ1dvPEw== + +requirejs@~2.3.6: + version "2.3.6" + resolved "https://registry.yarnpkg.com/requirejs/-/requirejs-2.3.6.tgz#e5093d9601c2829251258c0b9445d4d19fa9e7c9" + integrity sha512-ipEzlWQe6RK3jkzikgCupiTbTvm4S0/CAU5GlgptkN5SO6F3u0UD0K18wy6ErDqiCyP4J4YYe1HuAShvsxePLg== + +resolve@^1.3.2: + version "1.20.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975" + integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A== + dependencies: + is-core-module "^2.2.0" + path-parse "^1.0.6" + +safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +semver@^5.3.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" + integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== + +source-map-support@^0.5.19: + version "0.5.19" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61" + integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map@^0.5.1: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= + +source-map@^0.6.0: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +source-map@^0.7.3: + version "0.7.3" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" + integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +tslib@^1.13.0, tslib@^1.8.1: + version "1.14.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" + integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== + +tslib@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.2.0.tgz#fb2c475977e35e241311ede2693cee1ec6698f5c" + integrity sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w== + +tslint@^6.1.3: + version "6.1.3" + resolved "https://registry.yarnpkg.com/tslint/-/tslint-6.1.3.tgz#5c23b2eccc32487d5523bd3a470e9aa31789d904" + integrity sha512-IbR4nkT96EQOvKE2PW/djGz8iGNeJ4rF2mBfiYaR/nvUWYKJhLwimoJKgjIFEIDibBtOevj7BqCRL4oHeWWUCg== + dependencies: + "@babel/code-frame" "^7.0.0" + builtin-modules "^1.1.1" + chalk "^2.3.0" + commander "^2.12.1" + diff "^4.0.1" + glob "^7.1.1" + js-yaml "^3.13.1" + minimatch "^3.0.4" + mkdirp "^0.5.3" + resolve "^1.3.2" + semver "^5.3.0" + tslib "^1.13.0" + tsutils "^2.29.0" + +tsutils@^2.29.0: + version "2.29.0" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.29.0.tgz#32b488501467acbedd4b85498673a0812aca0b99" + integrity sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA== + dependencies: + tslib "^1.8.1" + +typescript@~4.3: + version "4.3.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.3.2.tgz#399ab18aac45802d6f2498de5054fcbbe716a805" + integrity sha512-zZ4hShnmnoVnAHpVHWpTcxdv7dWP60S2FsydQLV8V5PbS3FifjWFFRiHSWpDJahly88PRyV5teTSLoq4eG7mKw== + +underscore@~1.9.1: + version "1.9.2" + resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.9.2.tgz#0c8d6f536d6f378a5af264a72f7bec50feb7cf2f" + integrity sha512-D39qtimx0c1fI3ya1Lnhk3E9nONswSKhnffBI0gME9C99fYOkNi04xs8K6pePLhvl1frbDemkaBQ5ikWllR2HQ== + +util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= + +vinyl-sourcemaps-apply@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/vinyl-sourcemaps-apply/-/vinyl-sourcemaps-apply-0.2.1.tgz#ab6549d61d172c2b1b87be5c508d239c8ef87705" + integrity sha1-q2VJ1h0XLCsbh75cUI0jnI74dwU= + dependencies: + source-map "^0.5.1" + +vinyl@2.x: + version "2.2.1" + resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-2.2.1.tgz#23cfb8bbab5ece3803aa2c0a1eb28af7cbba1974" + integrity sha512-LII3bXRFBZLlezoG5FfZVcXflZgWP/4dCwKtxd5ky9+LOtM4CS3bIRQsmR1KMnMW07jpE8fqR2lcxPZ+8sJIcw== + dependencies: + clone "^2.1.1" + clone-buffer "^1.0.0" + clone-stats "^1.0.0" + cloneable-readable "^1.0.0" + remove-trailing-separator "^1.0.1" + replace-ext "^1.0.0" + +walkdir@~0.0.12: + version "0.0.12" + resolved "https://registry.yarnpkg.com/walkdir/-/walkdir-0.0.12.tgz#2f24f1ade64aab1e458591d4442c8868356e9281" + integrity sha512-HFhaD4mMWPzFSqhpyDG48KDdrjfn409YQuVW7ckZYhW4sE87mYtWifdB/+73RA7+p4s4K18n5Jfx1kHthE1gBw== + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=