diff --git a/packages/core/src/metadata/di.ts b/packages/core/src/metadata/di.ts index 607b39062c..6793b32706 100644 --- a/packages/core/src/metadata/di.ts +++ b/packages/core/src/metadata/di.ts @@ -50,7 +50,7 @@ export const ANALYZE_FOR_ENTRY_COMPONENTS = new InjectionToken('AnalyzeForE /** * Type of the Attribute decorator / constructor function. * - * + * @publicApi */ export interface AttributeDecorator { /** @@ -99,6 +99,8 @@ export interface AttributeDecorator { /** * Type of the Attribute metadata. + * + * @publicApi */ export interface Attribute { attributeName?: string; } @@ -113,6 +115,8 @@ export const Attribute: AttributeDecorator = /** * Type of the Query metadata. + * + * @publicApi */ export interface Query { descendants: boolean; @@ -181,6 +185,7 @@ export interface ContentChildrenDecorator { * * * @Annotation + * @publicApi */ export type ContentChildren = Query; @@ -237,7 +242,7 @@ export interface ContentChildDecorator { * * @see `ContentChild`. * - * + * @publicApi */ export type ContentChild = Query; @@ -246,6 +251,7 @@ export type ContentChild = Query; * * * @Annotation + * * @publicApi */ export const ContentChild: ContentChildDecorator = makePropDecorator( @@ -293,6 +299,8 @@ export interface ViewChildrenDecorator { /** * Type of the ViewChildren metadata. + * + * @publicApi */ export type ViewChildren = Query; @@ -359,6 +367,8 @@ export interface ViewChildDecorator { /** * Type of the ViewChild metadata. + * + * @publicApi */ export type ViewChild = Query; diff --git a/packages/core/src/metadata/directives.ts b/packages/core/src/metadata/directives.ts index 441eea8b37..b0ef9538c2 100644 --- a/packages/core/src/metadata/directives.ts +++ b/packages/core/src/metadata/directives.ts @@ -77,23 +77,31 @@ export interface DirectiveDecorator { new (obj: Directive): Directive; } +/** + * Directive decorator and metadata. + * + * @Annotation + * @publicApi + */ export interface Directive { /** - * The CSS selector that triggers the instantiation of a directive. + * The CSS selector that identifies this directive in a template + * and triggers instantiation of the directive. * * Declare as one of the following: * - * - `element-name`: select by element name. - * - `.class`: select by class name. - * - `[attribute]`: select by attribute name. - * - `[attribute=value]`: select by attribute name and value. - * - `:not(sub_selector)`: select only if the element does not match the `sub_selector`. - * - `selector1, selector2`: select if either `selector1` or `selector2` matches. + * - `element-name`: Select by element name. + * - `.class`: Select by class name. + * - `[attribute]`: Select by attribute name. + * - `[attribute=value]`: Select by attribute name and value. + * - `:not(sub_selector)`: Select only if the element does not match the `sub_selector`. + * - `selector1, selector2`: Select if either `selector1` or `selector2` matches. * - * Angular only allows directives to trigger on CSS selectors that do not cross element - * boundaries. For example, consider a directive with an `input[type=text]` selector. - * For the following HTML, the directive is instantiated only on the - * `` element. + * Angular only allows directives to apply on CSS selectors that do not cross + * element boundaries. + * + * For the following template HTML, a directive with an `input[type=text]` selector, + * would be instantiated only on the `` element. * * ```html *
@@ -176,8 +184,9 @@ export interface Directive { outputs?: string[]; /** - * A set of injection tokens that allow the DI system to - * provide a dependency to this directive or component. + * Configures the [injector](guide/glossary#injector) of this + * directive or component with a [token](guide/glossary#di-token) + * that maps to a [provider](guide/glossary#provider) of a dependency. */ providers?: Provider[]; @@ -247,62 +256,6 @@ export interface Directive { */ queries?: {[key: string]: any}; - /** - * If true, this directive/component will be skipped by the AOT compiler and so will always be - * compiled using JIT. - * - * This exists to support future Ivy work and has no effect currently. - */ - jit?: true; -} - -/** - * Directive decorator and metadata. - * - * @Annotation - */ -export interface Directive { - /** - * The CSS selector that identifies this directive in a template - * and triggers instantiation of the directive. - * - * Declare as one of the following: - * - * - `element-name`: Select by element name. - * - `.class`: Select by class name. - * - `[attribute]`: Select by attribute name. - * - `[attribute=value]`: Select by attribute name and value. - * - `:not(sub_selector)`: Select only if the element does not match the `sub_selector`. - * - `selector1, selector2`: Select if either `selector1` or `selector2` matches. - * - * Angular only allows directives to apply on CSS selectors that do not cross - * element boundaries. - * - * For the following template HTML, a directive with an `input[type=text]` selector, - * would be instantiated only on the `` element. - * - * ```html - * - * - * - * - * ``` - * - */ - selector?: string; - - /** - * The set of event-bound output properties. - * When an output property emits an event, an event handler attached - * to that event in the template is invoked. - * - * Each output property maps a `directiveProperty` to a `bindingProperty`: - * - `directiveProperty` specifies the component property that emits events. - * - `bindingProperty` specifies the HTML attribute the event handler is attached to. - * - */ - outputs?: string[]; - /** * Maps class properties to host element bindings for properties, * attributes, and events, using a set of key-value pairs. @@ -328,27 +281,12 @@ export interface Directive { host?: {[key: string]: string}; /** - * Configures the [injector](guide/glossary#injector) of this - * directive or component with a [token](guide/glossary#di-token) - * that maps to a [provider](guide/glossary#provider) of a dependency. - */ - providers?: Provider[]; - - /** - * The name or names that can be used in the template to assign this directive to a variable. - * For multiple names, use a comma-separated string. + * If true, this directive/component will be skipped by the AOT compiler and so will always be + * compiled using JIT. * + * This exists to support future Ivy work and has no effect currently. */ - exportAs?: string; - - /** - * Configures the queries that will be injected into the directive. - * - * Content queries are set before the `ngAfterContentInit` callback is called. - * View queries are set before the `ngAfterViewInit` callback is called. - * - */ - queries?: {[key: string]: any}; + jit?: true; } /** @@ -512,6 +450,8 @@ export interface ComponentDecorator { /** * Supplies configuration metadata for an Angular component. + * + * @publicApi */ export interface Component extends Directive { /** @@ -645,6 +585,8 @@ export interface PipeDecorator { /** * Type of the Pipe metadata. + * + * @publicApi */ export interface Pipe { /** @@ -704,7 +646,7 @@ export interface InputDecorator { /** * Type of metadata for an `Input` property. * - * + * @publicApi */ export interface Input { /** @@ -824,6 +766,8 @@ export interface OutputDecorator { /** * Type of the Output metadata. + * + * @publicApi */ export interface Output { bindingPropertyName?: string; } @@ -879,6 +823,7 @@ export interface HostBindingDecorator { /** * Type of the HostBinding metadata. * + * @publicApi */ export interface HostBinding { hostPropertyName?: string; } @@ -902,6 +847,8 @@ export interface HostListenerDecorator { /** * Type of the HostListener metadata. + * + * @publicApi */ export interface HostListener { /** diff --git a/packages/core/src/metadata/ng_module.ts b/packages/core/src/metadata/ng_module.ts index 4a672d5142..4f96b303ad 100644 --- a/packages/core/src/metadata/ng_module.ts +++ b/packages/core/src/metadata/ng_module.ts @@ -127,6 +127,8 @@ export interface NgModuleDecorator { /** * Type of the NgModule metadata. + * + * @publicApi */ export interface NgModule { /** diff --git a/packages/core/testing/src/test_bed.ts b/packages/core/testing/src/test_bed.ts index 1a123b1fa8..52c6bccdf3 100644 --- a/packages/core/testing/src/test_bed.ts +++ b/packages/core/testing/src/test_bed.ts @@ -20,6 +20,9 @@ const UNDEFINED = new Object(); let _nextRootElementId = 0; +/** + * @publicApi + */ export interface TestBed { platform: PlatformRef; @@ -35,16 +38,12 @@ export interface TestBed { * * Test modules and platforms for individual platforms are available from * '@angular//testing'. - * - * @publicApi */ initTestEnvironment( ngModule: Type|Type[], platform: PlatformRef, aotSummaries?: () => any[]): void; /** * Reset the providers for the test injector. - * - * @publicApi */ resetTestEnvironment(): void; @@ -119,8 +118,6 @@ export class TestBedViewEngine implements Injector, TestBed { * * Test modules and platforms for individual platforms are available from * '@angular//testing'. - * - * @publicApi */ static initTestEnvironment( ngModule: Type|Type[], platform: PlatformRef, @@ -132,8 +129,6 @@ export class TestBedViewEngine implements Injector, TestBed { /** * Reset the providers for the test injector. - * - * @publicApi */ static resetTestEnvironment(): void { _getTestBedViewEngine().resetTestEnvironment(); } @@ -291,8 +286,6 @@ export class TestBedViewEngine implements Injector, TestBed { * * Test modules and platforms for individual platforms are available from * '@angular//testing'. - * - * @publicApi */ initTestEnvironment( ngModule: Type|Type[], platform: PlatformRef, aotSummaries?: () => any[]): void { @@ -308,8 +301,6 @@ export class TestBedViewEngine implements Injector, TestBed { /** * Reset the providers for the test injector. - * - * @publicApi */ resetTestEnvironment(): void { this.resetTestingModule(); diff --git a/tools/public_api_guard/core/core.d.ts b/tools/public_api_guard/core/core.d.ts index 2d34bab8e5..60122730f9 100644 --- a/tools/public_api_guard/core/core.d.ts +++ b/tools/public_api_guard/core/core.d.ts @@ -47,6 +47,10 @@ export declare function asNativeElements(debugEls: DebugElement[]): any; export declare function assertPlatform(requiredToken: any): PlatformRef; +export interface Attribute { + attributeName?: string; +} + export declare const Attribute: AttributeDecorator; export declare enum ChangeDetectionStrategy { @@ -95,6 +99,21 @@ export declare type CompilerOptions = { preserveWhitespaces?: boolean; }; +export interface Component extends Directive { + animations?: any[]; + changeDetection?: ChangeDetectionStrategy; + encapsulation?: ViewEncapsulation; + entryComponents?: Array | any[]>; + interpolation?: [string, string]; + moduleId?: string; + preserveWhitespaces?: boolean; + styleUrls?: string[]; + styles?: string[]; + template?: string; + templateUrl?: string; + viewProviders?: Provider[]; +} + export declare const Component: ComponentDecorator; export interface ComponentDecorator { @@ -137,7 +156,7 @@ export interface ConstructorSansProvider { deps?: any[]; } -export declare const ContentChild: ContentChildDecorator; +export declare type ContentChild = Query; export interface ContentChildDecorator { (selector: Type | Function | string, opts?: { @@ -148,7 +167,7 @@ export interface ContentChildDecorator { }): ContentChild; } -export declare const ContentChildren: ContentChildrenDecorator; +export declare type ContentChildren = Query; export interface ContentChildrenDecorator { (selector: Type | Function | string, opts?: { @@ -242,6 +261,21 @@ export declare function defineInjector(options: { export declare function destroyPlatform(): void; +export interface Directive { + exportAs?: string; + host?: { + [key: string]: string; + }; + inputs?: string[]; + jit?: true; + outputs?: string[]; + providers?: Provider[]; + queries?: { + [key: string]: any; + }; + selector?: string; +} + export declare const Directive: DirectiveDecorator; export interface DirectiveDecorator { @@ -307,8 +341,15 @@ export interface GetTestability { findTestabilityInTree(registry: TestabilityRegistry, elem: any, findInAncestors: boolean): Testability | null; } +export interface Host { +} + export declare const Host: HostDecorator; +export interface HostBinding { + hostPropertyName?: string; +} + export declare const HostBinding: HostBindingDecorator; export interface HostDecorator { @@ -316,13 +357,26 @@ export interface HostDecorator { new (): Host; } +export interface HostListener { + args?: string[]; + eventName?: string; +} + export declare const HostListener: HostListenerDecorator; export declare function inject(token: Type | InjectionToken): T; export declare function inject(token: Type | InjectionToken, flags?: InjectFlags): T | null; +export interface Inject { + token: any; +} + export declare const Inject: InjectDecorator; +export interface Injectable { + providedIn?: Type | 'root' | null; +} + export declare const Injectable: InjectableDecorator; export interface InjectableDecorator { @@ -385,6 +439,10 @@ export interface InjectorType extends Type { ngInjectorDef: never; } +export interface Input { + bindingPropertyName?: string; +} + export declare const Input: InputDecorator; export declare function isDevMode(): boolean; @@ -480,6 +538,18 @@ export interface ModuleWithProviders = Array | Iterable; +export interface NgModule { + bootstrap?: Array | any[]>; + declarations?: Array | any[]>; + entryComponents?: Array | any[]>; + exports?: Array | any[]>; + id?: string; + imports?: Array | ModuleWithProviders<{}> | any[]>; + jit?: true; + providers?: Provider[]; + schemas?: Array; +} + export declare const NgModule: NgModuleDecorator; export declare abstract class NgModuleFactory { @@ -539,6 +609,9 @@ export interface OnInit { ngOnInit(): void; } +export interface Optional { +} + export declare const Optional: OptionalDecorator; export interface OptionalDecorator { @@ -546,10 +619,19 @@ export interface OptionalDecorator { new (): Optional; } +export interface Output { + bindingPropertyName?: string; +} + export declare const Output: OutputDecorator; export declare const PACKAGE_ROOT_URL: InjectionToken; +export interface Pipe { + name: string; + pure?: boolean; +} + export declare const Pipe: PipeDecorator; export interface PipeTransform { @@ -577,6 +659,14 @@ export interface Predicate { export declare type Provider = TypeProvider | ValueProvider | ClassProvider | ConstructorProvider | ExistingProvider | FactoryProvider | any[]; +export interface Query { + descendants: boolean; + first: boolean; + isViewQuery: boolean; + read: any; + selector: any; +} + export declare abstract class Query { } @@ -742,6 +832,9 @@ export declare enum SecurityContext { RESOURCE_URL = 5 } +export interface Self { +} + export declare const Self: SelfDecorator; export interface SelfDecorator { @@ -763,6 +856,9 @@ export interface SimpleChanges { [propName: string]: SimpleChange; } +export interface SkipSelf { +} + export declare const SkipSelf: SkipSelfDecorator; export interface SkipSelfDecorator { @@ -841,7 +937,7 @@ export declare class Version { export declare const VERSION: Version; -export declare const ViewChild: ViewChildDecorator; +export declare type ViewChild = Query; export interface ViewChildDecorator { (selector: Type | Function | string, opts?: { @@ -852,7 +948,7 @@ export interface ViewChildDecorator { }): ViewChild; } -export declare const ViewChildren: ViewChildrenDecorator; +export declare type ViewChildren = Query; export interface ViewChildrenDecorator { (selector: Type | Function | string, opts?: { diff --git a/tools/public_api_guard/core/testing.d.ts b/tools/public_api_guard/core/testing.d.ts index a7a5afa4cc..560fa43b94 100644 --- a/tools/public_api_guard/core/testing.d.ts +++ b/tools/public_api_guard/core/testing.d.ts @@ -47,6 +47,52 @@ export declare type MetadataOverride = { export declare function resetFakeAsyncZone(): void; +export interface TestBed { + ngModule: Type | Type[]; + platform: PlatformRef; + compileComponents(): Promise; + configureCompiler(config: { + providers?: any[]; + useJit?: boolean; + }): void; + configureTestingModule(moduleDef: TestModuleMetadata): void; + createComponent(component: Type): ComponentFixture; + deprecatedOverrideProvider(token: any, provider: { + useFactory?: Function; + useValue?: any; + deps?: any[]; + }): void; + /** @deprecated */ deprecatedOverrideProvider(token: any, provider: { + useFactory: Function; + deps: any[]; + }): void; + deprecatedOverrideProvider(token: any, provider: { + useValue: any; + }): void; + execute(tokens: any[], fn: Function, context?: any): any; + get(token: any, notFoundValue?: any): any; + initTestEnvironment(ngModule: Type | Type[], platform: PlatformRef, aotSummaries?: () => any[]): void; + overrideComponent(component: Type, override: MetadataOverride): void; + overrideDirective(directive: Type, override: MetadataOverride): void; + overrideModule(ngModule: Type, override: MetadataOverride): void; + overridePipe(pipe: Type, override: MetadataOverride): void; + overrideProvider(token: any, provider: { + useFactory?: Function; + useValue?: any; + deps?: any[]; + }): void; + overrideProvider(token: any, provider: { + useFactory: Function; + deps: any[]; + }): void; + overrideProvider(token: any, provider: { + useValue: any; + }): void; + overrideTemplateUsingTestingModule(component: Type, template: string): void; + resetTestEnvironment(): void; + resetTestingModule(): void; +} + export declare const TestBed: TestBedStatic; export interface TestBedStatic { diff --git a/tools/ts-api-guardian/lib/serializer.ts b/tools/ts-api-guardian/lib/serializer.ts index 772b775c1c..f575a96373 100644 --- a/tools/ts-api-guardian/lib/serializer.ts +++ b/tools/ts-api-guardian/lib/serializer.ts @@ -115,7 +115,7 @@ class ResolvedDeclarationEmitter { throw new Error(`Source file "${this.fileName}" not found`); } - let output = ''; + let output: string[] = []; const resolvedSymbols = this.getResolvedSymbols(sourceFile); // Sort all symbols so that the output is more deterministic @@ -126,42 +126,19 @@ class ResolvedDeclarationEmitter { continue; } - let decl: ts.Node|undefined = - symbol.valueDeclaration || symbol.declarations && symbol.declarations[0]; - if (!decl) { + const typeDecl = symbol.declarations && symbol.declarations[0]; + const valDecl = symbol.valueDeclaration; + if (!typeDecl && !valDecl) { this.diagnostics.push({ type: 'warn', message: `${sourceFile.fileName}: error: No declaration found for symbol "${symbol.name}"` }); continue; } - - // The declaration node may not be a complete statement, e.g. for var/const - // symbols. We need to find the complete export statement by traversing - // upwards. - while (!hasModifier(decl, ts.SyntaxKind.ExportKeyword) && decl.parent) { - decl = decl.parent; - } - - if (hasModifier(decl, ts.SyntaxKind.ExportKeyword)) { - // Make an empty line between two exports - if (output) { - output += '\n'; - } - - const jsdocComment = this.processJsDocTags(decl, this.options.exportTags); - if (jsdocComment) { - output += jsdocComment + '\n'; - } - - output += stripEmptyLines(this.emitNode(decl)) + '\n'; - } else { - // This may happen for symbols re-exported from external modules. - this.diagnostics.push({ - type: 'warn', - message: - createErrorMessage(decl, `No export declaration found for symbol "${symbol.name}"`) - }); + typeDecl && this.emitDeclaration(symbol, typeDecl, output); + if (valDecl && typeDecl.kind === ts.SyntaxKind.InterfaceDeclaration) { + // Only generate value declarations in case of interfaces. + valDecl && this.emitDeclaration(symbol, valDecl, output); } } @@ -173,7 +150,36 @@ class ResolvedDeclarationEmitter { } } - return output; + return output.join(''); + } + + emitDeclaration(symbol: ts.Symbol, decl: ts.Node, output: string[]) { + // The declaration node may not be a complete statement, e.g. for var/const + // symbols. We need to find the complete export statement by traversing + // upwards. + while (!hasModifier(decl, ts.SyntaxKind.ExportKeyword) && decl.parent) { + decl = decl.parent; + } + + if (hasModifier(decl, ts.SyntaxKind.ExportKeyword)) { + // Make an empty line between two exports + if (output.length) { + output.push('\n'); + } + + const jsdocComment = this.processJsDocTags(decl, this.options.exportTags); + if (jsdocComment) { + output.push(jsdocComment + '\n'); + } + + output.push(stripEmptyLines(this.emitNode(decl)) + '\n'); + } else { + // This may happen for symbols re-exported from external modules. + this.diagnostics.push({ + type: 'warn', + message: createErrorMessage(decl, `No export declaration found for symbol "${symbol.name}"`) + }); + } } private isExportPatternStripped(symbolName: string): boolean { diff --git a/tools/ts-api-guardian/test/fixtures/exports_type_and_value.d.ts b/tools/ts-api-guardian/test/fixtures/exports_type_and_value.d.ts new file mode 100644 index 0000000000..4e161fe44c --- /dev/null +++ b/tools/ts-api-guardian/test/fixtures/exports_type_and_value.d.ts @@ -0,0 +1,4 @@ +export interface TypeOnly { field: string; } +export interface TypeAndValue { field: string; } + +export const TypeAndValue: Function; \ No newline at end of file diff --git a/tools/ts-api-guardian/test/fixtures/exports_type_and_value_expected.d.ts b/tools/ts-api-guardian/test/fixtures/exports_type_and_value_expected.d.ts new file mode 100644 index 0000000000..63ff608813 --- /dev/null +++ b/tools/ts-api-guardian/test/fixtures/exports_type_and_value_expected.d.ts @@ -0,0 +1,5 @@ +export interface TypeAndValue { field: string; } + +export const TypeAndValue: Function; + +export interface TypeOnly { field: string; } diff --git a/tools/ts-api-guardian/test/integration_test.ts b/tools/ts-api-guardian/test/integration_test.ts index eda21210e1..282fcc086e 100644 --- a/tools/ts-api-guardian/test/integration_test.ts +++ b/tools/ts-api-guardian/test/integration_test.ts @@ -45,6 +45,12 @@ describe('integration test: public api', () => { 'test/fixtures/classes_and_interfaces_expected.d.ts'); }); + it('should include value and type', () => { + check( + 'test/fixtures/exports_type_and_value.d.ts', + 'test/fixtures/exports_type_and_value_expected.d.ts'); + }); + it('should include members reexported classes', () => { check( 'test/fixtures/reexported_classes.d.ts', 'test/fixtures/reexported_classes_expected.d.ts');