diff --git a/modules/@angular/compiler-cli/src/ng_host.ts b/modules/@angular/compiler-cli/src/ng_host.ts index 9ff1823c36..a248f34019 100644 --- a/modules/@angular/compiler-cli/src/ng_host.ts +++ b/modules/@angular/compiler-cli/src/ng_host.ts @@ -31,6 +31,8 @@ export class NgHost implements AotCompilerHost { private isGenDirChildOfRootDir: boolean; protected basePath: string; private genDir: string; + private resolverCache = new Map(); + constructor( protected program: ts.Program, protected compilerHost: ts.CompilerHost, protected options: AngularCompilerOptions, context?: NgHostContext) { @@ -138,9 +140,18 @@ export class NgHost implements AotCompilerHost { } } - private resolverCache = new Map(); + protected getSourceFile(filePath: string): ts.SourceFile { + const sf = this.program.getSourceFile(filePath); + if (!sf) { + if (this.context.fileExists(filePath)) { + const sourceText = this.context.readFile(filePath); + return ts.createSourceFile(filePath, sourceText, ts.ScriptTarget.Latest, true); + } + throw new Error(`Source file ${filePath} not present in program.`); + } + } - getMetadataFor(filePath: string): ModuleMetadata { + getMetadataFor(filePath: string): ModuleMetadata[] { if (!this.context.fileExists(filePath)) { // If the file doesn't exists then we cannot return metadata for the file. // This will occur if the user refernced a declared module for which no file @@ -150,27 +161,51 @@ export class NgHost implements AotCompilerHost { if (DTS.test(filePath)) { const metadataPath = filePath.replace(DTS, '.metadata.json'); if (this.context.fileExists(metadataPath)) { - const metadata = this.readMetadata(metadataPath); - return (Array.isArray(metadata) && metadata.length == 0) ? undefined : metadata; + return this.readMetadata(metadataPath, filePath); } } else { - const sf = this.program.getSourceFile(filePath); - if (!sf) { - if (this.context.fileExists(filePath)) { - const sourceText = this.context.readFile(filePath); - return this.metadataCollector.getMetadata( - ts.createSourceFile(filePath, sourceText, ts.ScriptTarget.Latest, true)); - } - - throw new Error(`Source file ${filePath} not present in program.`); - } - return this.metadataCollector.getMetadata(sf); + const sf = this.getSourceFile(filePath); + const metadata = this.metadataCollector.getMetadata(sf); + return metadata ? [metadata] : []; } } - readMetadata(filePath: string) { + readMetadata(filePath: string, dtsFilePath: string): ModuleMetadata[] { + let metadatas = this.resolverCache.get(filePath); + if (metadatas) { + return metadatas; + } try { - return this.resolverCache.get(filePath) || JSON.parse(this.context.readFile(filePath)); + const metadataOrMetadatas = JSON.parse(this.context.readFile(filePath)); + const metadatas = metadataOrMetadatas ? + (Array.isArray(metadataOrMetadatas) ? metadataOrMetadatas : [metadataOrMetadatas]) : + []; + const v1Metadata = metadatas.find(m => m['version'] === 1); + let v2Metadata = metadatas.find(m => m['version'] === 2); + if (!v2Metadata && v1Metadata) { + // patch up v1 to v2 by merging the metadata with metadata collected from the d.ts file + // as the only difference between the versions is whether all exports are contained in + // the metadata + v2Metadata = {'__symbolic': 'module', 'version': 2, 'metadata': {}}; + if (v1Metadata.exports) { + v2Metadata.exports = v1Metadata.exports; + } + for (let prop in v1Metadata.metadata) { + v2Metadata.metadata[prop] = v1Metadata.metadata[prop]; + } + const sourceText = this.context.readFile(dtsFilePath); + const exports = this.metadataCollector.getMetadata(this.getSourceFile(dtsFilePath)); + if (exports) { + for (let prop in exports.metadata) { + if (!v2Metadata.metadata[prop]) { + v2Metadata.metadata[prop] = exports.metadata[prop]; + } + } + } + metadatas.push(v2Metadata); + } + this.resolverCache.set(filePath, metadatas); + return metadatas; } catch (e) { console.error(`Failed to read JSON file ${filePath}`); throw e; @@ -178,15 +213,6 @@ export class NgHost implements AotCompilerHost { } loadResource(filePath: string): Promise { return this.context.readResource(filePath); } - - private getResolverMetadata(filePath: string): ModuleMetadata { - let metadata = this.resolverCache.get(filePath); - if (!metadata) { - metadata = this.getMetadataFor(filePath); - this.resolverCache.set(filePath, metadata); - } - return metadata; - } } export class NodeNgHostContext implements NgHostContext { diff --git a/modules/@angular/compiler-cli/src/path_mapped_ng_host.ts b/modules/@angular/compiler-cli/src/path_mapped_ng_host.ts index e100ea3293..23e333f337 100644 --- a/modules/@angular/compiler-cli/src/path_mapped_ng_host.ts +++ b/modules/@angular/compiler-cli/src/path_mapped_ng_host.ts @@ -116,7 +116,7 @@ export class PathMappedNgHost extends NgHost { `Unable to find any resolvable import for ${importedFile} relative to ${containingFile}`); } - getMetadataFor(filePath: string): ModuleMetadata { + getMetadataFor(filePath: string): ModuleMetadata[] { for (const root of this.options.rootDirs || []) { const rootedPath = path.join(root, filePath); if (!this.compilerHost.fileExists(rootedPath)) { @@ -128,16 +128,13 @@ export class PathMappedNgHost extends NgHost { if (DTS.test(rootedPath)) { const metadataPath = rootedPath.replace(DTS, '.metadata.json'); if (this.context.fileExists(metadataPath)) { - const metadata = this.readMetadata(metadataPath); - return (Array.isArray(metadata) && metadata.length == 0) ? undefined : metadata; + return this.readMetadata(metadataPath, rootedPath); } } else { - const sf = this.program.getSourceFile(rootedPath); - if (!sf) { - throw new Error(`Source file ${rootedPath} not present in program.`); - } + const sf = this.getSourceFile(rootedPath); sf.fileName = this.getCanonicalFileName(sf.fileName); - return this.metadataCollector.getMetadata(sf); + const metadata = this.metadataCollector.getMetadata(sf); + return metadata ? [metadata] : []; } } } diff --git a/modules/@angular/compiler-cli/test/ng_host_spec.ts b/modules/@angular/compiler-cli/test/ng_host_spec.ts index d780648e39..d90ef05869 100644 --- a/modules/@angular/compiler-cli/test/ng_host_spec.ts +++ b/modules/@angular/compiler-cli/test/ng_host_spec.ts @@ -141,8 +141,9 @@ describe('NgHost', () => { }); it('should be able to read a metadata file', () => { - expect(hostNestedGenDir.getMetadataFor('node_modules/@angular/core.d.ts')) - .toEqual({__symbolic: 'module', version: 1, metadata: {foo: {__symbolic: 'class'}}}); + expect(hostNestedGenDir.getMetadataFor('node_modules/@angular/core.d.ts')).toEqual([ + {__symbolic: 'module', version: 2, metadata: {foo: {__symbolic: 'class'}}} + ]); }); it('should be able to read metadata from an otherwise unused .d.ts file ', () => { @@ -150,12 +151,22 @@ describe('NgHost', () => { }); it('should be able to read empty metadata ', () => { - expect(hostNestedGenDir.getMetadataFor('node_modules/@angular/empty.d.ts')).toBeUndefined(); + expect(hostNestedGenDir.getMetadataFor('node_modules/@angular/empty.d.ts')).toEqual([]); }); it('should return undefined for missing modules', () => { expect(hostNestedGenDir.getMetadataFor('node_modules/@angular/missing.d.ts')).toBeUndefined(); }); + + it('should add missing v2 metadata from v1 metadata and .d.ts files', () => { + expect(hostNestedGenDir.getMetadataFor('metadata_versions/v1.d.ts')).toEqual([ + {__symbolic: 'module', version: 1, metadata: {foo: {__symbolic: 'class'}}}, { + __symbolic: 'module', + version: 2, + metadata: {foo: {__symbolic: 'class'}, bar: {__symbolic: 'class'}} + } + ]); + }); }); const dummyModule = 'export let foo: any[];'; @@ -179,12 +190,17 @@ const FILES: Entry = { '@angular': { 'core.d.ts': dummyModule, 'core.metadata.json': - `{"__symbolic":"module", "version": 1, "metadata": {"foo": {"__symbolic": "class"}}}`, + `{"__symbolic":"module", "version": 2, "metadata": {"foo": {"__symbolic": "class"}}}`, 'router': {'index.d.ts': dummyModule, 'src': {'providers.d.ts': dummyModule}}, 'unused.d.ts': dummyModule, 'empty.d.ts': 'export declare var a: string;', 'empty.metadata.json': '[]', } + }, + 'metadata_versions': { + 'v1.d.ts': 'export declare class bar {}', + 'v1.metadata.json': + `{"__symbolic":"module", "version": 1, "metadata": {"foo": {"__symbolic": "class"}}}`, } } } diff --git a/modules/@angular/compiler/src/aot/compiler_host.ts b/modules/@angular/compiler/src/aot/compiler_host.ts index f6862e056c..209ad1d6ff 100644 --- a/modules/@angular/compiler/src/aot/compiler_host.ts +++ b/modules/@angular/compiler/src/aot/compiler_host.ts @@ -22,7 +22,7 @@ export interface AotCompilerHost { * @param modulePath is a string identifier for a module as an absolute path. * @returns the metadata for the given module. */ - getMetadataFor(modulePath: string): {[key: string]: any}|{[key: string]: any}[]; + getMetadataFor(modulePath: string): {[key: string]: any}[]; /** * Converts an import into a file path. diff --git a/modules/@angular/compiler/src/aot/static_reflector.ts b/modules/@angular/compiler/src/aot/static_reflector.ts index a026b8a710..91bf085c08 100644 --- a/modules/@angular/compiler/src/aot/static_reflector.ts +++ b/modules/@angular/compiler/src/aot/static_reflector.ts @@ -11,7 +11,7 @@ import {ReflectorReader} from '../private_import_core'; import {AotCompilerHost} from './compiler_host'; import {StaticSymbol} from './static_symbol'; -const SUPPORTED_SCHEMA_VERSION = 1; +const SUPPORTED_SCHEMA_VERSION = 2; const ANGULAR_IMPORT_LOCATIONS = { coreDecorators: '@angular/core/src/metadata', diDecorators: '@angular/core/src/di/metadata', @@ -604,10 +604,15 @@ export class StaticReflector implements ReflectorReader { public getModuleMetadata(module: string): {[key: string]: any} { let moduleMetadata = this.metadataCache.get(module); if (!moduleMetadata) { - moduleMetadata = this.host.getMetadataFor(module); - if (Array.isArray(moduleMetadata)) { - moduleMetadata = moduleMetadata.find(md => md['version'] === SUPPORTED_SCHEMA_VERSION) || - moduleMetadata[0]; + const moduleMetadatas = this.host.getMetadataFor(module); + if (moduleMetadatas) { + let maxVersion = -1; + moduleMetadatas.forEach((md) => { + if (md['version'] > maxVersion) { + maxVersion = md['version']; + moduleMetadata = md; + } + }); } if (!moduleMetadata) { moduleMetadata = @@ -653,6 +658,7 @@ function expandedMessage(error: any): string { if (error.context && error.context.name) { return `Reference to a local (non-exported) symbol '${error.context.name}'. Consider exporting the symbol`; } + break; } return error.message; } diff --git a/modules/@angular/compiler/test/aot/static_reflector_spec.ts b/modules/@angular/compiler/test/aot/static_reflector_spec.ts index d2fa19ed31..03a3bb73ad 100644 --- a/modules/@angular/compiler/test/aot/static_reflector_spec.ts +++ b/modules/@angular/compiler/test/aot/static_reflector_spec.ts @@ -73,10 +73,10 @@ describe('StaticReflector', () => { ])]); }); - it('should throw and exception for unsupported metadata versions', () => { + it('should throw an exception for unsupported metadata versions', () => { expect(() => reflector.findDeclaration('src/version-error', 'e')) .toThrow(new Error( - 'Metadata version mismatch for module /tmp/src/version-error.d.ts, found version 100, expected 1')); + 'Metadata version mismatch for module /tmp/src/version-error.d.ts, found version 100, expected 2')); }); it('should get and empty annotation list for an unknown class', () => { @@ -342,13 +342,11 @@ describe('StaticReflector', () => { try { const metadata = host.getMetadataFor('/tmp/src/invalid-metadata.ts'); expect(metadata).toBeDefined(); - if (!Array.isArray(metadata)) { - const moduleMetadata: any = metadata['metadata']; - expect(moduleMetadata).toBeDefined(); - const classData: any = moduleMetadata['InvalidMetadata']; - expect(classData).toBeDefined(); - simplify(new StaticSymbol('/tmp/src/invalid-metadata.ts', ''), classData.decorators[0]); - } + const moduleMetadata: any = metadata[0]['metadata']; + expect(moduleMetadata).toBeDefined(); + const classData: any = moduleMetadata['InvalidMetadata']; + expect(classData).toBeDefined(); + simplify(new StaticSymbol('/tmp/src/invalid-metadata.ts', ''), classData.decorators[0]); } catch (e) { expect(e.fileName).toBe('/tmp/src/invalid-metadata.ts'); threw = true; @@ -376,7 +374,7 @@ describe('StaticReflector', () => { const metadata = reflector.getModuleMetadata('/tmp/src/custom-decorator-reference.ts'); expect(metadata).toEqual({ __symbolic: 'module', - version: 1, + version: 2, metadata: { Foo: { __symbolic: 'class', @@ -564,7 +562,7 @@ class MockAotCompilerHost implements AotCompilerHost { const data: {[key: string]: any} = { '/tmp/@angular/common/src/forms-deprecated/directives.d.ts': [{ '__symbolic': 'module', - 'version': 1, + 'version': 2, 'metadata': { 'FORM_DIRECTIVES': [ { @@ -577,7 +575,7 @@ class MockAotCompilerHost implements AotCompilerHost { }], '/tmp/@angular/common/src/directives/ng_for.d.ts': { '__symbolic': 'module', - 'version': 1, + 'version': 2, 'metadata': { 'NgFor': { '__symbolic': 'class', @@ -630,16 +628,16 @@ class MockAotCompilerHost implements AotCompilerHost { } }, '/tmp/@angular/core/src/linker/view_container_ref.d.ts': - {version: 1, 'metadata': {'ViewContainerRef': {'__symbolic': 'class'}}}, + {version: 2, 'metadata': {'ViewContainerRef': {'__symbolic': 'class'}}}, '/tmp/@angular/core/src/linker/template_ref.d.ts': - {version: 1, 'module': './template_ref', 'metadata': {'TemplateRef': {'__symbolic': 'class'}}}, + {version: 2, 'module': './template_ref', 'metadata': {'TemplateRef': {'__symbolic': 'class'}}}, '/tmp/@angular/core/src/change_detection/differs/iterable_differs.d.ts': - {version: 1, 'metadata': {'IterableDiffers': {'__symbolic': 'class'}}}, + {version: 2, 'metadata': {'IterableDiffers': {'__symbolic': 'class'}}}, '/tmp/@angular/core/src/change_detection/change_detector_ref.d.ts': - {version: 1, 'metadata': {'ChangeDetectorRef': {'__symbolic': 'class'}}}, + {version: 2, 'metadata': {'ChangeDetectorRef': {'__symbolic': 'class'}}}, '/tmp/src/app/hero-detail.component.d.ts': { '__symbolic': 'module', - 'version': 1, + 'version': 2, 'metadata': { 'HeroDetailComponent': { '__symbolic': 'class', @@ -790,11 +788,11 @@ class MockAotCompilerHost implements AotCompilerHost { } } }, - '/src/extern.d.ts': {'__symbolic': 'module', 'version': 1, metadata: {s: 's'}}, + '/src/extern.d.ts': {'__symbolic': 'module', 'version': 2, metadata: {s: 's'}}, '/tmp/src/version-error.d.ts': {'__symbolic': 'module', 'version': 100, metadata: {e: 's'}}, '/tmp/src/error-reporting.d.ts': { __symbolic: 'module', - version: 1, + version: 2, metadata: { SomeClass: { __symbolic: 'class', @@ -824,7 +822,7 @@ class MockAotCompilerHost implements AotCompilerHost { }, '/tmp/src/error-references.d.ts': { __symbolic: 'module', - version: 1, + version: 2, metadata: { Link1: { __symbolic: 'reference', @@ -846,7 +844,7 @@ class MockAotCompilerHost implements AotCompilerHost { }, '/tmp/src/function-declaration.d.ts': { __symbolic: 'module', - version: 1, + version: 2, metadata: { one: { __symbolic: 'function', @@ -875,7 +873,7 @@ class MockAotCompilerHost implements AotCompilerHost { }, '/tmp/src/function-reference.ts': { __symbolic: 'module', - version: 1, + version: 2, metadata: { one: { __symbolic: 'call', @@ -917,7 +915,7 @@ class MockAotCompilerHost implements AotCompilerHost { }, '/tmp/src/function-recursive.d.ts': { __symbolic: 'modules', - version: 1, + version: 2, metadata: { recursive: { __symbolic: 'function', @@ -977,7 +975,7 @@ class MockAotCompilerHost implements AotCompilerHost { }, '/tmp/src/spread.ts': { __symbolic: 'module', - version: 1, + version: 2, metadata: { spread: [0, {__symbolic: 'spread', expression: [1, 2, 3, 4]}, 5] } @@ -1113,7 +1111,7 @@ class MockAotCompilerHost implements AotCompilerHost { `, '/tmp/src/reexport/reexport.d.ts': { __symbolic: 'module', - version: 1, + version: 2, metadata: {}, exports: [ {from: './src/origin1', export: ['One', 'Two', {name: 'Three', as: 'Four'}]}, @@ -1122,7 +1120,7 @@ class MockAotCompilerHost implements AotCompilerHost { }, '/tmp/src/reexport/src/origin1.d.ts': { __symbolic: 'module', - version: 1, + version: 2, metadata: { One: {__symbolic: 'class'}, Two: {__symbolic: 'class'}, @@ -1131,26 +1129,26 @@ class MockAotCompilerHost implements AotCompilerHost { }, '/tmp/src/reexport/src/origin5.d.ts': { __symbolic: 'module', - version: 1, + version: 2, metadata: { Five: {__symbolic: 'class'}, }, }, '/tmp/src/reexport/src/origin30.d.ts': { __symbolic: 'module', - version: 1, + version: 2, metadata: { Thirty: {__symbolic: 'class'}, }, }, '/tmp/src/reexport/src/originNone.d.ts': { __symbolic: 'module', - version: 1, + version: 2, metadata: {}, }, '/tmp/src/reexport/src/reexport2.d.ts': { __symbolic: 'module', - version: 1, + version: 2, metadata: {}, exports: [{from: './originNone'}, {from: './origin30'}] } @@ -1166,9 +1164,14 @@ class MockAotCompilerHost implements AotCompilerHost { if (diagnostics && diagnostics.length) { throw Error(`Error encountered during parse of file ${moduleId}`); } - return this.collector.getMetadata(sf); + return [this.collector.getMetadata(sf)]; } } - return data[moduleId]; + const result = data[moduleId]; + if (result) { + return Array.isArray(result) ? result : [result]; + } else { + return null; + } } } diff --git a/tools/@angular/tsc-wrapped/src/collector.ts b/tools/@angular/tsc-wrapped/src/collector.ts index cdff12ce23..3852f63cfc 100644 --- a/tools/@angular/tsc-wrapped/src/collector.ts +++ b/tools/@angular/tsc-wrapped/src/collector.ts @@ -256,9 +256,11 @@ export class MetadataCollector { if (classDeclaration.name) { const className = classDeclaration.name.text; if (node.flags & ts.NodeFlags.Export) { + if (!metadata) metadata = {}; if (classDeclaration.decorators) { - if (!metadata) metadata = {}; metadata[className] = classMetadataOf(classDeclaration); + } else { + metadata[className] = {__symbolic: 'class'}; } } } @@ -269,10 +271,14 @@ export class MetadataCollector { // names substitution will be performed by the StaticReflector. const functionDeclaration = node; if (node.flags & ts.NodeFlags.Export) { + if (!metadata) metadata = {}; const maybeFunc = maybeGetSimpleFunction(functionDeclaration); if (maybeFunc) { - if (!metadata) metadata = {}; metadata[maybeFunc.name] = recordEntry(maybeFunc.func, node); + } else if (functionDeclaration.name.kind == ts.SyntaxKind.Identifier) { + const nameNode = functionDeclaration.name; + const functionName = nameNode.text; + metadata[functionName] = {__symbolic: 'function'}; } } break; diff --git a/tools/@angular/tsc-wrapped/src/schema.ts b/tools/@angular/tsc-wrapped/src/schema.ts index 60bd6db840..5097c55373 100644 --- a/tools/@angular/tsc-wrapped/src/schema.ts +++ b/tools/@angular/tsc-wrapped/src/schema.ts @@ -15,7 +15,7 @@ // semantics of the file in an array. For example, when generating a version 2 file, if version 1 // can accurately represent the metadata, generate both version 1 and version 2 in an array. -export const VERSION = 1; +export const VERSION = 2; export type MetadataEntry = ClassMetadata | FunctionMetadata | MetadataValue; diff --git a/tools/@angular/tsc-wrapped/test/collector.spec.ts b/tools/@angular/tsc-wrapped/test/collector.spec.ts index aeae23a474..9dbb4e4560 100644 --- a/tools/@angular/tsc-wrapped/test/collector.spec.ts +++ b/tools/@angular/tsc-wrapped/test/collector.spec.ts @@ -29,6 +29,7 @@ describe('Collector', () => { '/unsupported-1.ts', '/unsupported-2.ts', 'import-star.ts', + 'exported-classes.ts', 'exported-functions.ts', 'exported-enum.ts', 'exported-consts.ts', @@ -62,7 +63,7 @@ describe('Collector', () => { const metadata = collector.getMetadata(sourceFile); expect(metadata).toEqual({ __symbolic: 'module', - version: 1, + version: 2, metadata: { HeroDetailComponent: { __symbolic: 'class', @@ -103,7 +104,7 @@ describe('Collector', () => { const metadata = collector.getMetadata(sourceFile); expect(metadata).toEqual({ __symbolic: 'module', - version: 1, + version: 2, metadata: { AppComponent: { __symbolic: 'class', @@ -157,7 +158,7 @@ describe('Collector', () => { const metadata = collector.getMetadata(sourceFile); expect(metadata).toEqual({ __symbolic: 'module', - version: 1, + version: 2, metadata: { HEROES: [ {'id': 11, 'name': 'Mr. Nice'}, {'id': 12, 'name': 'Narco'}, @@ -170,13 +171,6 @@ describe('Collector', () => { }); }); - it('should return undefined for modules that have no metadata', () => { - const sourceFile = program.getSourceFile('/app/error-cases.ts'); - expect(sourceFile).toBeTruthy(sourceFile); - const metadata = collector.getMetadata(sourceFile); - expect(metadata).toBeUndefined(); - }); - let casesFile: ts.SourceFile; let casesMetadata: ModuleMetadata; @@ -238,7 +232,7 @@ describe('Collector', () => { const metadata = collector.getMetadata(unsupported1); expect(metadata).toEqual({ __symbolic: 'module', - version: 1, + version: 2, metadata: { a: {__symbolic: 'error', message: 'Destructuring not supported', line: 1, character: 16}, b: {__symbolic: 'error', message: 'Destructuring not supported', line: 1, character: 19}, @@ -275,12 +269,26 @@ describe('Collector', () => { ]); }); + it('should record all exported classes', () => { + const sourceFile = program.getSourceFile('/exported-classes.ts'); + const metadata = collector.getMetadata(sourceFile); + expect(metadata).toEqual({ + __symbolic: 'module', + version: 2, + metadata: { + SimpleClass: {__symbolic: 'class'}, + AbstractClass: {__symbolic: 'class'}, + DeclaredClass: {__symbolic: 'class'} + } + }); + }); + it('should be able to record functions', () => { const exportedFunctions = program.getSourceFile('/exported-functions.ts'); const metadata = collector.getMetadata(exportedFunctions); expect(metadata).toEqual({ __symbolic: 'module', - version: 1, + version: 2, metadata: { one: { __symbolic: 'function', @@ -328,7 +336,9 @@ describe('Collector', () => { } } } - } + }, + complexFn: {__symbolic: 'function'}, + declaredFn: {__symbolic: 'function'} } }); }); @@ -829,6 +839,11 @@ const FILES: Directory = { constructor(private f: common.NgFor) {} } `, + 'exported-classes.ts': ` + export class SimpleClass {} + export abstract class AbstractClass {} + export declare class DeclaredClass {} + `, 'exported-functions.ts': ` export function one(a: string, b: string, c: string) { return {a: a, b: b, c: c}; @@ -842,6 +857,14 @@ const FILES: Directory = { export function supportsState(): boolean { return !!window.history.pushState; } + export function complexFn(x: any): boolean { + if (x) { + return true; + } else { + return false; + } + } + export declare function declaredFn(); `, 'exported-enum.ts': ` import {constValue} from './exported-consts';