Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion aio/content/guide/build.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ export class AppComponent {

## Configure target-specific file replacements

The main CLI configuration file, `angular.json`, contains a `fileReplacements` section in the configuration for each build target, which allows you to replace any file with a target-specific version of that file.
The main CLI configuration file, `angular.json`, contains a `fileReplacements` section in the configuration for each build target, which allows you to replace any file in the TypeScript program with a target-specific version of that file.
This is useful for including target-specific code or variables in a build that targets a specific environment, such as production or staging.

By default no files are replaced.
Expand Down
Binary file added aio/content/images/bios/eliraneliassy.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 9 additions & 0 deletions aio/content/marketing/contributors.json
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,14 @@
"bio": "Raul works as a CEO and Front-end Architect at Byte Default for companies around the world helping them to build high-performance web apps. In his spare time he's usually working on Videogular, involved in local meetups, speaking at conferences and contributing to open source projects.",
"groups": ["GDE"]
},
"eliraneliassy": {
"name": "Eliran Eliassy",
"picture": "eliraneliassy.jpg",
"twitter": "eliraneliassy",
"website": "https://eliassy.dev",
"bio": "Eliran is an Experienced FE developer, located in Tel Aviv, Israel. He is a developer, trainer, and consultant with a focus on Angular and the eco-system around it. He gives talks and workshops on Angular, RXJS, NGRX, and related technologies. As an active part of the community, he is constantly involved in growing it and interacting with the members. Eliran is one of the Organisers of AngularUP Annual Conference in Tel Aviv and also an organizer and leading the Angular meetup & community in Israel. He often speaks at conferences and meetups and also writes for AngualrInDepth.com.",
"groups": ["GDE"]
},
"eusoj": {
"name": "Josue Gutierrez",
"picture": "josue.jpg",
Expand Down Expand Up @@ -928,3 +936,4 @@
"groups": ["GDE"]
}
}

2 changes: 1 addition & 1 deletion aio/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"build-local-with-viewengine": "yarn ~~build",
"prebuild-local-with-viewengine-ci": "node scripts/switch-to-viewengine && yarn setup-local-ci",
"build-local-with-viewengine-ci": "yarn ~~build --progress=false",
"extract-cli-command-docs": "node tools/transforms/cli-docs-package/extract-cli-commands.js c366e223b",
"extract-cli-command-docs": "node tools/transforms/cli-docs-package/extract-cli-commands.js e33d85e00",
"lint": "yarn check-env && yarn docs-lint && ng lint && yarn example-lint && yarn tools-lint",
"test": "yarn check-env && ng test",
"pree2e": "yarn check-env && yarn update-webdriver",
Expand Down
6 changes: 0 additions & 6 deletions goldens/circular-deps/packages.json
Original file line number Diff line number Diff line change
Expand Up @@ -382,12 +382,6 @@
"packages/forms/src/directives/validators.ts",
"packages/forms/src/validators.ts"
],
[
"packages/language-service/src/completions.ts",
"packages/language-service/src/template.ts",
"packages/language-service/src/typescript_host.ts",
"packages/language-service/src/language_service.ts"
],
[
"packages/language-service/src/template.ts",
"packages/language-service/src/typescript_host.ts"
Expand Down
3 changes: 2 additions & 1 deletion goldens/public-api/core/core.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,8 @@ export declare class ErrorHandler {
export declare interface EventEmitter<T> extends Subject<T> {
new (isAsync?: boolean): EventEmitter<T>;
emit(value?: T): void;
subscribe(generatorOrNext?: any, error?: any, complete?: any): Subscription;
subscribe(next?: (value: T) => void, error?: (error: any) => void, complete?: () => void): Subscription;
subscribe(observerOrNext?: any, error?: any, complete?: any): Subscription;
}

export declare const EventEmitter: {
Expand Down
10 changes: 10 additions & 0 deletions packages/common/test/pipes/async_pipe_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,16 @@ import {SpyChangeDetectorRef} from '../spies';
});
});

describe('Subscribable', () => {
it('should infer the type from the subscribable', () => {
const ref = new SpyChangeDetectorRef() as any;
const pipe = new AsyncPipe(ref);
const emitter = new EventEmitter<{name: 'T'}>();
// The following line will fail to compile if the type cannot be inferred.
const name = pipe.transform(emitter)?.name;
});
});

describe('Promise', () => {
const message = {};
let pipe: AsyncPipe;
Expand Down
5 changes: 4 additions & 1 deletion packages/compiler-cli/src/ngtsc/testing/fake_core/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,10 @@ export const CUSTOM_ELEMENTS_SCHEMA: any = false;
export const NO_ERRORS_SCHEMA: any = false;

export class EventEmitter<T> {
subscribe(generatorOrNext?: any, error?: any, complete?: any): unknown {
subscribe(next?: (value: T) => void, error?: (error: any) => void, complete?: () => void):
unknown;
subscribe(observerOrNext?: any, error?: any, complete?: any): unknown;
subscribe(observerOrNext?: any, error?: any, complete?: any): unknown {
return null;
}
}
Expand Down
3 changes: 2 additions & 1 deletion packages/compiler-cli/src/ngtsc/typecheck/test/test_utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,8 @@ export function angularCoreDts(): TestFile {
}

export declare class EventEmitter<T> {
subscribe(generatorOrNext?: any, error?: any, complete?: any): unknown;
subscribe(next?: (value: T) => void, error?: (error: any) => void, complete?: () => void): unknown;
subscribe(observerOrNext?: any, error?: any, complete?: any): unknown;
}

export declare type NgIterable<T> = Array<T> | Iterable<T>;
Expand Down
50 changes: 30 additions & 20 deletions packages/core/src/event_emitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,15 +81,25 @@ export interface EventEmitter<T> extends Subject<T> {
* @param value The value to emit.
*/
emit(value?: T): void;

/**
* Registers handlers for events emitted by this instance.
* @param next When supplied, a custom handler for emitted events.
* @param error When supplied, a custom handler for an error notification from this emitter.
* @param complete When supplied, a custom handler for a completion notification from this
* emitter.
*/
subscribe(next?: (value: T) => void, error?: (error: any) => void, complete?: () => void):
Subscription;
/**
* Registers handlers for events emitted by this instance.
* @param generatorOrNext When supplied, a custom handler for emitted events.
* @param error When supplied, a custom handler for an error notification
* from this emitter.
* @param complete When supplied, a custom handler for a completion
* notification from this emitter.
* @param observerOrNext When supplied, a custom handler for emitted events, or an observer
* object.
* @param error When supplied, a custom handler for an error notification from this emitter.
* @param complete When supplied, a custom handler for a completion notification from this
* emitter.
*/
subscribe(generatorOrNext?: any, error?: any, complete?: any): Subscription;
subscribe(observerOrNext?: any, error?: any, complete?: any): Subscription;
}

class EventEmitter_ extends Subject<any> {
Expand All @@ -104,38 +114,38 @@ class EventEmitter_ extends Subject<any> {
super.next(value);
}

subscribe(generatorOrNext?: any, error?: any, complete?: any): Subscription {
subscribe(observerOrNext?: any, error?: any, complete?: any): Subscription {
let schedulerFn: (t: any) => any;
let errorFn = (err: any): any => null;
let completeFn = (): any => null;

if (generatorOrNext && typeof generatorOrNext === 'object') {
if (observerOrNext && typeof observerOrNext === 'object') {
schedulerFn = this.__isAsync ? (value: any) => {
setTimeout(() => generatorOrNext.next(value));
setTimeout(() => observerOrNext.next(value));
} : (value: any) => {
generatorOrNext.next(value);
observerOrNext.next(value);
};

if (generatorOrNext.error) {
if (observerOrNext.error) {
errorFn = this.__isAsync ? (err) => {
setTimeout(() => generatorOrNext.error(err));
setTimeout(() => observerOrNext.error(err));
} : (err) => {
generatorOrNext.error(err);
observerOrNext.error(err);
};
}

if (generatorOrNext.complete) {
if (observerOrNext.complete) {
completeFn = this.__isAsync ? () => {
setTimeout(() => generatorOrNext.complete());
setTimeout(() => observerOrNext.complete());
} : () => {
generatorOrNext.complete();
observerOrNext.complete();
};
}
} else {
schedulerFn = this.__isAsync ? (value: any) => {
setTimeout(() => generatorOrNext(value));
setTimeout(() => observerOrNext(value));
} : (value: any) => {
generatorOrNext(value);
observerOrNext(value);
};

if (error) {
Expand All @@ -157,8 +167,8 @@ class EventEmitter_ extends Subject<any> {

const sink = super.subscribe(schedulerFn, errorFn, completeFn);

if (generatorOrNext instanceof Subscription) {
generatorOrNext.add(sink);
if (observerOrNext instanceof Subscription) {
observerOrNext.add(sink);
}

return sink;
Expand Down
38 changes: 11 additions & 27 deletions packages/forms/src/directives/ng_control_status.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,44 +12,28 @@ import {AbstractControlDirective} from './abstract_control_directive';
import {ControlContainer} from './control_container';
import {NgControl} from './ng_control';

type AnyControlStatus = 'untouched'|'touched'|'pristine'|'dirty'|'valid'|'invalid'|'pending';

export class AbstractControlStatus {
private _cd: AbstractControlDirective|null;

constructor(cd: AbstractControlDirective|null) {
this._cd = cd;
}

get ngClassUntouched(): boolean {
return this._cd?.control?.untouched ?? false;
}
get ngClassTouched(): boolean {
return this._cd?.control?.touched ?? false;
}
get ngClassPristine(): boolean {
return this._cd?.control?.pristine ?? false;
}
get ngClassDirty(): boolean {
return this._cd?.control?.dirty ?? false;
}
get ngClassValid(): boolean {
return this._cd?.control?.valid ?? false;
}
get ngClassInvalid(): boolean {
return this._cd?.control?.invalid ?? false;
}
get ngClassPending(): boolean {
return this._cd?.control?.pending ?? false;
is(status: AnyControlStatus): boolean {
return !!this._cd?.control?.[status];
}
}

export const ngControlStatusHost = {
'[class.ng-untouched]': 'ngClassUntouched',
'[class.ng-touched]': 'ngClassTouched',
'[class.ng-pristine]': 'ngClassPristine',
'[class.ng-dirty]': 'ngClassDirty',
'[class.ng-valid]': 'ngClassValid',
'[class.ng-invalid]': 'ngClassInvalid',
'[class.ng-pending]': 'ngClassPending',
'[class.ng-untouched]': 'is("untouched")',
'[class.ng-touched]': 'is("touched")',
'[class.ng-pristine]': 'is("pristine")',
'[class.ng-dirty]': 'is("dirty")',
'[class.ng-valid]': 'is("valid")',
'[class.ng-invalid]': 'is("invalid")',
'[class.ng-pending]': 'is("pending")',
};

/**
Expand Down
14 changes: 12 additions & 2 deletions packages/language-service/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,28 @@ load("//tools:defaults.bzl", "pkg_npm", "ts_library")

package(default_visibility = ["//visibility:public"])

ts_library(
name = "api",
srcs = [
"api.ts",
],
deps = [
"@npm//typescript",
],
)

ts_library(
name = "language-service",
srcs = glob(
srcs = ["index.ts"] + glob(
[
"*.ts",
"src/**/*.ts",
],
exclude = [
"src/ts_utils.ts",
],
),
deps = [
":api",
":ts_utils",
"//packages:types",
"//packages/compiler",
Expand Down
42 changes: 42 additions & 0 deletions packages/language-service/api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/**
* @license
* Copyright Google LLC 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
*/

/**
* @module
* @description
* Entry point for all public APIs of the language service package.
*/

import * as ts from 'typescript';

export type GetTcbResponse = {
/**
* The filename of the SourceFile this typecheck block belongs to.
* The filename is entirely opaque and unstable, useful only for debugging
* purposes.
*/
fileName: string,
/** The content of the SourceFile this typecheck block belongs to. */
content: string,
/**
* Spans over node(s) in the typecheck block corresponding to the
* TS code generated for template node under the current cursor position.
*
* When the cursor position is over a source for which there is no generated
* code, `selections` is empty.
*/
selections: ts.TextSpan[],
}|undefined;

/**
* `NgLanguageService` describes an instance of an Angular language service,
* whose API surface is a strict superset of TypeScript's language service.
*/
export interface NgLanguageService extends ts.LanguageService {
getTcb(fileName: string, position: number): GetTcbResponse;
}
3 changes: 2 additions & 1 deletion packages/language-service/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@
* found in the LICENSE file at https://angular.io/license
*/

export * from './language-service';
export * from './api';
export {create, getExternalFiles} from './src/ts_plugin';
1 change: 1 addition & 0 deletions packages/language-service/ivy/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ ts_library(
"//packages/compiler-cli/src/ngtsc/typecheck",
"//packages/compiler-cli/src/ngtsc/typecheck/api",
"//packages/compiler-cli/src/ngtsc/util",
"//packages/language-service:api",
"@npm//@types/node",
"@npm//typescript",
],
Expand Down
20 changes: 1 addition & 19 deletions packages/language-service/ivy/language_service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {TypeCheckShimGenerator} from '@angular/compiler-cli/src/ngtsc/typecheck'
import {OptimizeFor, TypeCheckingProgramStrategy} from '@angular/compiler-cli/src/ngtsc/typecheck/api';
import {findFirstMatchingNode} from '@angular/compiler-cli/src/ngtsc/typecheck/src/comments';
import * as ts from 'typescript/lib/tsserverlibrary';
import {GetTcbResponse} from '../api';

import {LanguageServiceAdapter, LSParseConfigHost} from './adapters';
import {CompilerFactory} from './compiler_factory';
Expand All @@ -25,25 +26,6 @@ import {ReferencesAndRenameBuilder} from './references';
import {getTargetAtPosition, TargetContext, TargetNodeKind} from './template_target';
import {getTemplateInfoAtPosition, isTypeScriptFile} from './utils';

export type GetTcbResponse = {
/**
* The filename of the SourceFile this typecheck block belongs to.
* The filename is entirely opaque and unstable, useful only for debugging
* purposes.
*/
fileName: string,
/** The content of the SourceFile this typecheck block belongs to. */
content: string,
/**
* Spans over node(s) in the typecheck block corresponding to the
* TS code generated for template node under the current cursor position.
*
* When the cursor position is over a source for which there is no generated
* code, `selections` is empty.
*/
selections: ts.TextSpan[],
}|undefined;

export class LanguageService {
private options: CompilerOptions;
readonly compilerFactory: CompilerFactory;
Expand Down
7 changes: 2 additions & 5 deletions packages/language-service/ivy/ts_plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,8 @@
*/

import * as ts from 'typescript/lib/tsserverlibrary';
import {GetTcbResponse, LanguageService} from './language_service';

export interface NgLanguageService extends ts.LanguageService {
getTcb(fileName: string, position: number): GetTcbResponse;
}
import {GetTcbResponse, NgLanguageService} from '../api';
import {LanguageService} from './language_service';

export function create(info: ts.server.PluginCreateInfo): NgLanguageService {
const {project, languageService: tsLS, config} = info;
Expand Down
Loading