diff --git a/package.json b/package.json index 79e9279aa..130fd29a0 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "merge2": "^1.0.2", "temp": "^0.8.1", "tslint": "^3.15.1", - "typescript": "^2.0.0" + "typescript": "^2.1.0" }, "scripts": { "prepublish": "gulp compile", diff --git a/src/tsickle.ts b/src/tsickle.ts index 222ee1510..347d5a326 100644 --- a/src/tsickle.ts +++ b/src/tsickle.ts @@ -84,6 +84,11 @@ export function formatDiagnostics(diags: ts.Diagnostic[]): string { .join('\n'); } +/** @return true if node has the specified modifier flag set. */ +function hasModifierFlag(node: ts.Node, flag: ts.ModifierFlags): boolean { + return (ts.getCombinedModifierFlags(node) & flag) !== 0; +} + /** * TypeScript allows you to write identifiers quoted, like: * interface Foo { @@ -123,12 +128,14 @@ function getParameterName(param: ts.ParameterDeclaration, index: number): string // ignored anyway. return `__${index}`; default: - // The above list of kinds should be exhaustive. - throw new Error(`unhandled function parameter kind: ${ts.SyntaxKind[param.name.kind]}`); + // The above list of kinds is exhaustive. param.name is 'never' at this point. + let paramName = param.name as ts.Node; + throw new Error(`unhandled function parameter kind: ${ts.SyntaxKind[paramName.kind]}`); } } -const VISIBILITY_FLAGS = ts.NodeFlags.Private | ts.NodeFlags.Protected | ts.NodeFlags.Public; +const VISIBILITY_FLAGS: ts.ModifierFlags = + ts.ModifierFlags.Private | ts.ModifierFlags.Protected | ts.ModifierFlags.Public; /** * A Rewriter subclass that adds Tsickle-specific (Closure translation) functionality. @@ -183,7 +190,7 @@ class ClosureRewriter extends Rewriter { } // Add @abstract on "abstract" declarations. - if (fnDecl.flags & ts.NodeFlags.Abstract) { + if (hasModifierFlag(fnDecl, ts.ModifierFlags.Abstract)) { newDoc.push({tagName: 'abstract'}); } @@ -399,7 +406,7 @@ class Annotator extends ClosureRewriter { * emit it as is and visit its children. */ maybeProcess(node: ts.Node): boolean { - if ((node.flags & ts.NodeFlags.Ambient) || isDtsFileName(this.file.fileName)) { + if ((hasModifierFlag(node, ts.ModifierFlags.Ambient)) || isDtsFileName(this.file.fileName)) { this.externsWriter.visit(node); // An ambient declaration declares types for TypeScript's benefit, so we want to skip Tsickle // conversion of its contents. @@ -485,7 +492,7 @@ class Annotator extends ClosureRewriter { let fnDecl = node; if (!fnDecl.body) { - if ((fnDecl.flags & ts.NodeFlags.Abstract) !== 0) { + if (hasModifierFlag(fnDecl, ts.ModifierFlags.Abstract)) { this.emitFunctionType([fnDecl]); // Abstract functions look like // abstract foo(); @@ -712,7 +719,7 @@ class Annotator extends ClosureRewriter { private visitClassDeclaration(classDecl: ts.ClassDeclaration) { let jsDoc = this.getJSDoc(classDecl) || []; - if ((classDecl.flags & ts.NodeFlags.Abstract) !== 0) { + if (hasModifierFlag(classDecl, ts.ModifierFlags.Abstract)) { jsDoc.push({tagName: 'abstract'}); } this.emit('\n'); @@ -742,7 +749,7 @@ class Annotator extends ClosureRewriter { if (sym.flags & ts.SymbolFlags.Value) return; this.emit(`\n/** @record */\n`); - if (iface.flags & ts.NodeFlags.Export) this.emit('export '); + if (hasModifierFlag(iface, ts.ModifierFlags.Export)) this.emit('export '); let name = getIdentifierText(iface.name); this.emit(`function ${name}() {}\n`); if (iface.typeParameters) { @@ -775,7 +782,7 @@ class Annotator extends ClosureRewriter { ctors.push(member as ts.ConstructorDeclaration); } else if (member.kind === ts.SyntaxKind.PropertyDeclaration) { let prop = member as ts.PropertyDeclaration; - let isStatic = (prop.flags & ts.NodeFlags.Static) !== 0; + let isStatic = hasModifierFlag(prop, ts.ModifierFlags.Static); if (isStatic) { staticProps.push(prop); } else { @@ -786,7 +793,7 @@ class Annotator extends ClosureRewriter { if (ctors.length > 0) { let ctor = ctors[0]; - paramProps = ctor.parameters.filter((p) => !!(p.flags & VISIBILITY_FLAGS)); + paramProps = ctor.parameters.filter(p => hasModifierFlag(p, VISIBILITY_FLAGS)); } if (nonStaticProps.length === 0 && paramProps.length === 0 && staticProps.length === 0) { @@ -851,7 +858,7 @@ class Annotator extends ClosureRewriter { // requires us to not assign to typedef exports). Instead, emit the // "exports.foo;" line directly in that case. this.emit(`\n/** @typedef {${this.typeToClosure(node)}} */\n`); - if (node.flags & ts.NodeFlags.Export) { + if (hasModifierFlag(node, ts.ModifierFlags.Export)) { this.emit('exports.'); } else { this.emit('var '); @@ -861,7 +868,7 @@ class Annotator extends ClosureRewriter { /** Processes an EnumDeclaration or returns false for ordinary processing. */ private maybeProcessEnum(node: ts.EnumDeclaration): boolean { - if (node.flags & ts.NodeFlags.Const) { + if (hasModifierFlag(node, ts.ModifierFlags.Const)) { // const enums disappear after TS compilation and consequently need no // help from tsickle. return false; @@ -915,13 +922,10 @@ class Annotator extends ClosureRewriter { // both a typedef and an indexable object if we export it. this.emit('\n'); let name = node.name.getText(); - if (node.flags & ts.NodeFlags.Export) { - this.emit('export '); - } + const isExported = hasModifierFlag(node, ts.ModifierFlags.Export); + if (isExported) this.emit('export '); this.emit(`type ${name} = number;\n`); - if (node.flags & ts.NodeFlags.Export) { - this.emit('export '); - } + if (isExported) this.emit('export '); this.emit(`let ${name}: any = {};\n`); // Emit foo.BAR = 0; lines. diff --git a/src/type-translator.ts b/src/type-translator.ts index 1f67b5df3..f6ba9ee4d 100644 --- a/src/type-translator.ts +++ b/src/type-translator.ts @@ -37,31 +37,13 @@ export function typeToDebugString(type: ts.Type): string { let debugString = `flags:0x${type.flags.toString(16)}`; const basicTypes: ts.TypeFlags[] = [ - ts.TypeFlags.Any, - ts.TypeFlags.String, - ts.TypeFlags.Number, - ts.TypeFlags.Boolean, - ts.TypeFlags.Enum, - ts.TypeFlags.StringLiteral, - ts.TypeFlags.NumberLiteral, - ts.TypeFlags.BooleanLiteral, - ts.TypeFlags.EnumLiteral, - ts.TypeFlags.ESSymbol, - ts.TypeFlags.Void, - ts.TypeFlags.Undefined, - ts.TypeFlags.Null, - ts.TypeFlags.Never, - ts.TypeFlags.TypeParameter, - ts.TypeFlags.Class, - ts.TypeFlags.Interface, - ts.TypeFlags.Reference, - ts.TypeFlags.Tuple, - ts.TypeFlags.Union, - ts.TypeFlags.Intersection, - ts.TypeFlags.Anonymous, - ts.TypeFlags.Instantiated, - ts.TypeFlags.ThisType, - ts.TypeFlags.ObjectLiteralPatternWithComputedProperties, + ts.TypeFlags.Any, ts.TypeFlags.String, ts.TypeFlags.Number, + ts.TypeFlags.Boolean, ts.TypeFlags.Enum, ts.TypeFlags.StringLiteral, + ts.TypeFlags.NumberLiteral, ts.TypeFlags.BooleanLiteral, ts.TypeFlags.EnumLiteral, + ts.TypeFlags.ESSymbol, ts.TypeFlags.Void, ts.TypeFlags.Undefined, + ts.TypeFlags.Null, ts.TypeFlags.Never, ts.TypeFlags.TypeParameter, + ts.TypeFlags.Object, ts.TypeFlags.Union, ts.TypeFlags.Intersection, + ts.TypeFlags.Index, ts.TypeFlags.IndexedAccess, ]; for (let flag of basicTypes) { if ((type.flags & flag) !== 0) { @@ -220,13 +202,13 @@ export class TypeTranslator { if (type.symbol && this.isBlackListed(type.symbol)) return '?'; - if (type.flags & ts.TypeFlags.Class) { + if (/* TODO(ts2.1): type.flags & ts.TypeFlags.Class */ 1 === 1) { if (!type.symbol) { this.warn('class has no symbol'); return '?'; } return '!' + this.symbolToString(type.symbol); - } else if (type.flags & ts.TypeFlags.Interface) { + } else if (/* TODO(ts2.1): type.flags & ts.TypeFlags.Interface */ 1 === 1) { // Note: ts.InterfaceType has a typeParameters field, but that // specifies the parameters that the interface type *expects* // when it's used, and should not be transformed to the output. @@ -248,13 +230,14 @@ export class TypeTranslator { } } return '!' + this.symbolToString(type.symbol); - } else if (type.flags & ts.TypeFlags.Reference) { + } else if (/* TODO(ts2.1): type.flags & ts.TypeFlags.Reference */ 1 === 1) { // A reference to another type, e.g. Array refers to Array. // Emit the referenced type and any type arguments. let referenceType = type as ts.TypeReference; let typeStr = ''; - let isTuple = (referenceType.flags & ts.TypeFlags.Tuple) > 0; + // TODO(ts2.1): let isTuple = (referenceType.flags & ts.TypeFlags.Tuple) > 0; + let isTuple = true; // For unknown reasons, tuple types can be reference types containing a // reference loop. see Destructuring3 in functions.ts. // TODO(rado): handle tuples in their own branch. @@ -274,7 +257,7 @@ export class TypeTranslator { typeStr += isTuple ? `!Array` : `<${params.join(', ')}>`; } return typeStr; - } else if (type.flags & ts.TypeFlags.Anonymous) { + } else if (/* TODO(ts2.1): type.flags & ts.TypeFlags.Anonymous */ 1 === 1) { if (!type.symbol) { // This comes up when generating code for an arrow function as passed // to a generic function. The passed-in type is tagged as anonymous diff --git a/test/decorator-annotator_test.ts b/test/decorator-annotator_test.ts index 910df627f..26bfa34d4 100644 --- a/test/decorator-annotator_test.ts +++ b/test/decorator-annotator_test.ts @@ -50,7 +50,7 @@ describe( let goodSourceFile = program.getSourceFile(testCaseFileName); expect(() => convertDecorators(program.getTypeChecker(), goodSourceFile)).to.not.throw(); let badSourceFile = - ts.createSourceFile(testCaseFileName, sourceText, ts.ScriptTarget.ES6, true); + ts.createSourceFile(testCaseFileName, sourceText, ts.ScriptTarget.ES2015, true); expect(() => convertDecorators(program.getTypeChecker(), badSourceFile)).to.throw(); }); diff --git a/test/test_support.ts b/test/test_support.ts index 9c6756162..abe4bbd2a 100644 --- a/test/test_support.ts +++ b/test/test_support.ts @@ -17,7 +17,7 @@ import {toArray} from '../src/util'; /** The TypeScript compiler options used by the test suite. */ export const compilerOptions: ts.CompilerOptions = { - target: ts.ScriptTarget.ES6, + target: ts.ScriptTarget.ES2015, skipDefaultLibCheck: true, experimentalDecorators: true, emitDecoratorMetadata: true, @@ -34,7 +34,7 @@ const {cachedLibPath, cachedLib} = (function() { let host = ts.createCompilerHost(compilerOptions); let fn = host.getDefaultLibFileName(compilerOptions); let p = ts.getDefaultLibFilePath(compilerOptions); - return {cachedLibPath: p, cachedLib: host.getSourceFile(fn, ts.ScriptTarget.ES6)}; + return {cachedLibPath: p, cachedLib: host.getSourceFile(fn, ts.ScriptTarget.ES2015)}; })(); /** Creates a ts.Program from a set of input files. */