diff --git a/.aspect/rules/external_repository_action_cache/npm_translate_lock_LTE4Nzc1MDcwNjU= b/.aspect/rules/external_repository_action_cache/npm_translate_lock_LTE4Nzc1MDcwNjU= index 9a34e2c453..bd11060f2a 100755 --- a/.aspect/rules/external_repository_action_cache/npm_translate_lock_LTE4Nzc1MDcwNjU= +++ b/.aspect/rules/external_repository_action_cache/npm_translate_lock_LTE4Nzc1MDcwNjU= @@ -2,7 +2,7 @@ # Input hashes for repository rule npm_translate_lock(name = "npm", pnpm_lock = "//:pnpm-lock.yaml"). # This file should be checked into version control along with the pnpm-lock.yaml file. .npmrc=974837034 -pnpm-lock.yaml=-1736799033 +pnpm-lock.yaml=-60247795 yarn.lock=1176905511 -package.json=-1064085518 +package.json=-552185186 pnpm-workspace.yaml=1711114604 diff --git a/client/src/client.ts b/client/src/client.ts index 7da83933f5..89d53a1893 100644 --- a/client/src/client.ts +++ b/client/src/client.ts @@ -15,7 +15,7 @@ import {OpenOutputChannel, ProjectLoadingFinish, ProjectLoadingStart, SuggestStr import {GetComponentsWithTemplateFile, GetTcbRequest, GetTemplateLocationForComponent, IsInAngularProject} from '../../common/requests'; import {NodeModule, resolve} from '../../common/resolver'; -import {isInsideStringLiteral, isNotTypescriptOrInsideComponentDecorator} from './embedded_support'; +import {isInsideStringLiteral, isNotTypescriptOrSupportedDecoratorField} from './embedded_support'; interface GetTcbResponse { uri: vscode.Uri; @@ -91,7 +91,7 @@ export class AngularLanguageClient implements vscode.Disposable { document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken, next: lsp.ProvideDefinitionSignature) => { if (await this.isInAngularProject(document) && - isNotTypescriptOrInsideComponentDecorator(document, position)) { + isNotTypescriptOrSupportedDecoratorField(document, position)) { return next(document, position, token); } }, @@ -99,7 +99,7 @@ export class AngularLanguageClient implements vscode.Disposable { document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken, next) => { if (await this.isInAngularProject(document) && - isNotTypescriptOrInsideComponentDecorator(document, position)) { + isNotTypescriptOrSupportedDecoratorField(document, position)) { return next(document, position, token); } }, @@ -107,7 +107,7 @@ export class AngularLanguageClient implements vscode.Disposable { document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken, next: lsp.ProvideHoverSignature) => { if (!(await this.isInAngularProject(document)) || - !isNotTypescriptOrInsideComponentDecorator(document, position)) { + !isNotTypescriptOrSupportedDecoratorField(document, position)) { return; } @@ -131,7 +131,7 @@ export class AngularLanguageClient implements vscode.Disposable { context: vscode.SignatureHelpContext, token: vscode.CancellationToken, next: lsp.ProvideSignatureHelpSignature) => { if (await this.isInAngularProject(document) && - isNotTypescriptOrInsideComponentDecorator(document, position)) { + isNotTypescriptOrSupportedDecoratorField(document, position)) { return next(document, position, context, token); } }, @@ -141,7 +141,7 @@ export class AngularLanguageClient implements vscode.Disposable { next: lsp.ProvideCompletionItemsSignature) => { // If not in inline template, do not perform request forwarding if (!(await this.isInAngularProject(document)) || - !isNotTypescriptOrInsideComponentDecorator(document, position)) { + !isNotTypescriptOrSupportedDecoratorField(document, position)) { return; } const angularCompletionsPromise = next(document, position, context, token) as diff --git a/client/src/embedded_support.ts b/client/src/embedded_support.ts index 0e9d83d607..141922a076 100644 --- a/client/src/embedded_support.ts +++ b/client/src/embedded_support.ts @@ -8,15 +8,25 @@ import * as ts from 'typescript'; import * as vscode from 'vscode'; -/** Determines if the position is inside an inline template, templateUrl, or string in styleUrls. */ -export function isNotTypescriptOrInsideComponentDecorator( +const ANGULAR_PROPERTY_ASSIGNMENTS = new Set([ + 'template', + 'templateUrl', + 'styleUrls', + 'styleUrl', + 'host', +]); + +/** + * Determines if the position is inside a decorator + * property that supports language service features. + */ +export function isNotTypescriptOrSupportedDecoratorField( document: vscode.TextDocument, position: vscode.Position): boolean { if (document.languageId !== 'typescript') { return true; } return isPropertyAssignmentToStringOrStringInArray( - document.getText(), document.offsetAt(position), - ['template', 'templateUrl', 'styleUrls', 'styleUrl']); + document.getText(), document.offsetAt(position), ANGULAR_PROPERTY_ASSIGNMENTS); } /** @@ -62,7 +72,7 @@ export function isInsideStringLiteral( * https://github.com/Microsoft/TypeScript/issues/20055 */ function isPropertyAssignmentToStringOrStringInArray( - documentText: string, offset: number, propertyAssignmentNames: string[]): boolean { + documentText: string, offset: number, propertyAssignmentNames: Set): boolean { const scanner = ts.createScanner(ts.ScriptTarget.ESNext, true /* skipTrivia */); scanner.setText(documentText); @@ -74,7 +84,7 @@ function isPropertyAssignmentToStringOrStringInArray( let propertyAssignmentContext = false; while (token !== ts.SyntaxKind.EndOfFileToken && scanner.getStartPos() < offset) { if (lastToken === ts.SyntaxKind.Identifier && lastTokenText !== undefined && - propertyAssignmentNames.includes(lastTokenText) && token === ts.SyntaxKind.ColonToken) { + token === ts.SyntaxKind.ColonToken && propertyAssignmentNames.has(lastTokenText)) { propertyAssignmentContext = true; token = scanner.scan(); continue; diff --git a/integration/project/tsconfig.json b/integration/project/tsconfig.json index 9e9a538a08..cfecdf22a2 100644 --- a/integration/project/tsconfig.json +++ b/integration/project/tsconfig.json @@ -16,6 +16,7 @@ }, "angularCompilerOptions": { "strictTemplates": true, + "typeCheckHostBindings": true, "strictInjectionParameters": true } -} \ No newline at end of file +} diff --git a/integration/workspace/tsconfig.json b/integration/workspace/tsconfig.json index d3c1011aa5..a1df478821 100644 --- a/integration/workspace/tsconfig.json +++ b/integration/workspace/tsconfig.json @@ -24,6 +24,7 @@ "angularCompilerOptions": { "strictInjectionParameters": true, "strictInputAccessModifiers": true, - "strictTemplates": true + "strictTemplates": true, + "typeCheckHostBindings": true } } diff --git a/package.json b/package.json index f849c45360..6449b92d59 100644 --- a/package.json +++ b/package.json @@ -212,6 +212,18 @@ "source.ts" ] }, + { + "path": "./syntaxes/host-object-literal.json", + "scopeName": "host-object-literal.ng", + "injectTo": [ + "source.ts" + ], + "embeddedLanguages": { + "text.html.derivative": "html", + "expression.ng": "javascript", + "source.ts": "typescript" + } + }, { "path": "./syntaxes/template-tag.json", "scopeName": "template.tag.ng", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 48761a9274..42314ee7f7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -2147,6 +2147,7 @@ packages: id: registry.npmjs.org/@bazel/typescript/5.5.0 name: '@bazel/typescript' version: 5.5.0 + deprecated: No longer maintained, https://github.com/aspect-build/rules_ts is the recommended replacement hasBin: true requiresBuild: true peerDependencies: @@ -11042,6 +11043,7 @@ packages: name: vsce version: 1.100.1 engines: {node: '>= 10'} + deprecated: vsce has been renamed to @vscode/vsce. Install using @vscode/vsce instead. hasBin: true dependencies: azure-devops-node-api: registry.npmjs.org/azure-devops-node-api@11.2.0 diff --git a/syntaxes/BUILD.bazel b/syntaxes/BUILD.bazel index 7d75ad2a87..022c05a4ce 100644 --- a/syntaxes/BUILD.bazel +++ b/syntaxes/BUILD.bazel @@ -16,6 +16,7 @@ js_run_binary( "_template-blocks.json", "_template-tag.json", "_let-declaration.json", + "_host-object-literal.json", ] ) @@ -29,6 +30,7 @@ write_source_files( "template-blocks.json": "_template-blocks.json", "template-tag.json": "_template-tag.json", "let-declaration.json": "_let-declaration.json", + "host-object-literal.json": "_host-object-literal.json", } ) diff --git a/syntaxes/host-object-literal.json b/syntaxes/host-object-literal.json new file mode 100644 index 0000000000..05263fa193 --- /dev/null +++ b/syntaxes/host-object-literal.json @@ -0,0 +1,102 @@ +{ + "scopeName": "host-object-literal.ng", + "injectionSelector": "L:meta.decorator.ts -comment -text.html -expression.ng", + "patterns": [ + { + "include": "#hostObjectLiteral" + } + ], + "repository": { + "hostObjectLiteral": { + "begin": "(host)\\s*(:)\\s*{", + "beginCaptures": { + "1": { + "name": "meta.object-literal.key.ts" + }, + "2": { + "name": "meta.object-literal.key.ts punctuation.separator.key-value.ts" + } + }, + "contentName": "hostbindings.ng", + "end": "}", + "patterns": [ + { + "include": "#ngHostBindingDynamic" + }, + { + "include": "#ngHostBindingStatic" + }, + { + "include": "source.ts" + } + ] + }, + "ngHostBindingDynamic": { + "begin": "\\s*('|\")([\\[(].*?[\\])])(\\1)(:)", + "beginCaptures": { + "1": { + "name": "string" + }, + "2": { + "name": "entity.other.attribute-name.html" + }, + "3": { + "name": "string" + }, + "4": { + "name": "meta.object-literal.key.ts punctuation.separator.key-value.ts" + } + }, + "contentName": "hostbinding.dynamic.ng", + "patterns": [ + { + "include": "#ngHostBindingDynamicValue" + } + ], + "end": "(?=,|})" + }, + "ngHostBindingDynamicValue": { + "begin": "\\s*(`|'|\")", + "beginCaptures": { + "1": { + "name": "string" + } + }, + "patterns": [ + { + "include": "expression.ng" + } + ], + "end": "\\1", + "endCaptures": { + "0": { + "name": "string" + } + } + }, + "ngHostBindingStatic": { + "begin": "\\s*('|\")?(.*?)(\\1)?\\s*:", + "end": "(?=,|})", + "beginCaptures": { + "1": { + "name": "string" + }, + "2": { + "name": "entity.other.attribute-name.html" + }, + "3": { + "name": "string" + }, + "4": { + "name": "meta.object-literal.key.ts punctuation.separator.key-value.ts" + } + }, + "contentName": "hostbinding.static.ng", + "patterns": [ + { + "include": "source.ts" + } + ] + } + } +} diff --git a/syntaxes/src/build.ts b/syntaxes/src/build.ts index 6fc5553c8b..3beedc03dd 100644 --- a/syntaxes/src/build.ts +++ b/syntaxes/src/build.ts @@ -9,6 +9,7 @@ import * as fs from 'fs'; import {Expression} from './expression'; +import {HostObjectLiteral} from './host-object-literal'; import {InlineStyles} from './inline-styles'; import {InlineTemplate} from './inline-template'; import {Template} from './template'; @@ -59,3 +60,4 @@ build(InlineStyles, 'inline-styles'); build(TemplateBlocks, 'template-blocks'); build(TemplateTag, 'template-tag'); build(LetDeclaration, 'let-declaration'); +build(HostObjectLiteral, 'host-object-literal'); diff --git a/syntaxes/src/host-object-literal.ts b/syntaxes/src/host-object-literal.ts new file mode 100644 index 0000000000..fb989be0f2 --- /dev/null +++ b/syntaxes/src/host-object-literal.ts @@ -0,0 +1,101 @@ +/** + * @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 {GrammarDefinition} from './types'; + +/** Highlighting definition for the `host` object of a directive or component. */ +export const HostObjectLiteral: GrammarDefinition = { + scopeName: 'host-object-literal.ng', + injectionSelector: 'L:meta.decorator.ts -comment -text.html -expression.ng', + patterns: [{include: '#hostObjectLiteral'}], + repository: { + hostObjectLiteral: { + begin: /(host)\s*(:)\s*{/, + beginCaptures: { + // Key is shown as JS syntax. + 1: {name: 'meta.object-literal.key.ts'}, + // Colon is shown as JS syntax. + 2: {name: 'meta.object-literal.key.ts punctuation.separator.key-value.ts'} + }, + contentName: 'hostbindings.ng', + end: /}/, + patterns: [ + // Try to match host bindings inside the `host`. + {include: '#ngHostBindingDynamic'}, + // Try to match a static binding inside the `host`. + {include: '#ngHostBindingStatic'}, + // Include the default TS syntax so that anything that doesn't + // match the above will get the default highlighting. + {include: 'source.ts'}, + ] + }, + + // A bound property inside `host`, e.g. `[attr.foo]="expr"` or `(click)="handleClick()"`. + ngHostBindingDynamic: { + begin: /\s*('|")([\[(].*?[\])])(\1)(:)/, + beginCaptures: { + // Opening quote is shown as a string. Only allows single and double quotes, no backticks. + 1: {name: 'string'}, + // Name is shown as an HTML attribute. + 2: {name: 'entity.other.attribute-name.html'}, + // Closing quote is shown as a string. + 3: {name: 'string'}, + // Colon is shown as JS syntax. + 4: {name: 'meta.object-literal.key.ts punctuation.separator.key-value.ts'} + }, + contentName: 'hostbinding.dynamic.ng', + patterns: [ + {include: '#ngHostBindingDynamicValue'}, + ], + end: /(?=,|})/ + }, + + // Value of a bound property inside `host`. + ngHostBindingDynamicValue: { + begin: /\s*(`|'|")/, + beginCaptures: { + // Opening quote is shown as a string. Allows backticks as well. + 1: {name: 'string'}, + }, + patterns: [ + // Content is shown as an Angular expression. + {include: 'expression.ng'}, + ], + // Ends on the same kind of quote as the opening. + // @ts-ignore + end: /\1/, + endCaptures: { + // Closing quote is shown as a string. + 0: {name: 'string'}, + } + }, + + // Static value inside `host`. + ngHostBindingStatic: { + // Note that we need to allow both quoted and non-quoted keys. + begin: /\s*('|")?(.*?)(\1)?\s*:/, + end: /(?=,|})/, + beginCaptures: { + // Opening quote is shown as a string. Only allows single and double quotes, no backticks. + 1: {name: 'string'}, + // Name is shown as an HTML attribute. + 2: {name: 'entity.other.attribute-name.html'}, + // Closing quote is shown as a string. + 3: {name: 'string'}, + // Colon is shown as JS syntax. + 4: {name: 'meta.object-literal.key.ts punctuation.separator.key-value.ts'}, + }, + contentName: 'hostbinding.static.ng', + patterns: [ + // Use TypeScript highlighting for the value. This allows us to deal + // with things like escaped strings and variables correctly. + {include: 'source.ts'}, + ] + }, + } +}; diff --git a/syntaxes/test/cases.ts b/syntaxes/test/cases.ts index 54fec7e0f8..d5462ffb98 100644 --- a/syntaxes/test/cases.ts +++ b/syntaxes/test/cases.ts @@ -44,4 +44,11 @@ export const cases = [ 'grammarFiles': ['syntaxes/let-declaration.json', 'syntaxes/expression.json'], 'testFile': 'syntaxes/test/data/let-declaration.html' }, + { + 'name': 'host object literal', + 'scopeName': 'host-object-literal.ng', + 'grammarFiles': + ['syntaxes/host-object-literal.json', 'syntaxes/template.json', 'syntaxes/expression.json'], + 'testFile': 'syntaxes/test/data/host-object-literal.ts' + }, ]; diff --git a/syntaxes/test/data/host-object-literal.ts b/syntaxes/test/data/host-object-literal.ts new file mode 100644 index 0000000000..1b2a434f2f --- /dev/null +++ b/syntaxes/test/data/host-object-literal.ts @@ -0,0 +1,80 @@ +/* clang-format off */ + +@Component({ + //// Quoted static attributes + host: { + 'class': 'one two', + 'my-attr': 'my-value', + "doubleQuotes": "value", + 'backticksForValue': `my-attr-${value}`, + }, + + //// Unquoted static attributes + host: { + class: 'one two', + myAttr: "my-value", + style: `color: red;`, + }, + + //// Attribute bindings + host: { + '[attr.one]': '123 + "hello"', + '[attr.two]': '"something" + counter / 2', + }, + + //// Class bindings + host: { + '[class.one]': 'value', + '[class.two]': 'foo || bar', + }, + + //// Property bindings + host: { + '[one]': 'value', + '[two]': 'foo || bar', + '[@three]': 'animation', + }, + + //// Event listeners + host: { + '(click)': 'handleClick(123, $event)', + '(window:keydown)': 'globalKey()', + '(document:keydown)': 'globalKey()', + '(@animation.start)': 'handleStart()', + '(@animation.end)': 'handleEnd()', + }, + + //// Quotes inside the value + host: { + '(click)': 'handleClick("hello `${name}`")', + }, + + //// Expression inside object literal + host: { + ...before, + '(click)': 'handleClick("hello `${name}`")', + 'class': 'hello', + ...after, + }, + + //// Variable initializer + host: HOST_BINDINGS, + + //// Variable values + host: { + '(click)': CLICK_LISTENER + OTHER_STUFF, + 'class': (MY_CLASS + ' ' + MY_OTHER_CLASS) + ` foo-${bar + 123}`, + }, + + //// One of each + host: { + 'class': 'one two', + myAttr: "my-value", + '[attr.greeting]': '"hello " + name', + ...extras, + '[class.is-visible]': 'isVisible()', + '[id]': '_id', + '(click)': 'handleClick($event)', + }, +}) +export class TMComponent{} diff --git a/syntaxes/test/data/host-object-literal.ts.snap b/syntaxes/test/data/host-object-literal.ts.snap new file mode 100644 index 0000000000..5f3e4b4589 --- /dev/null +++ b/syntaxes/test/data/host-object-literal.ts.snap @@ -0,0 +1,427 @@ +>/* clang-format off */ +#^^^^^^^^^^^^^^^^^^^^^^^ host-object-literal.ng +> +>@Component({ +#^^^^^^^^^^^^^ host-object-literal.ng +> //// Quoted static attributes +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ host-object-literal.ng +> host: { +#^^ host-object-literal.ng +# ^^^^ host-object-literal.ng meta.object-literal.key.ts +# ^ host-object-literal.ng meta.object-literal.key.ts punctuation.separator.key-value.ts +# ^^ host-object-literal.ng +> 'class': 'one two', +#^^^^^^^^^^^^^^^^^^^^^^^^ host-object-literal.ng hostbindings.ng +> 'my-attr': 'my-value', +#^^^^^^^^^^^^^^^^^^^^^^^^^^^ host-object-literal.ng hostbindings.ng +> "doubleQuotes": "value", +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ host-object-literal.ng hostbindings.ng +> 'backticksForValue': `my-attr-${value}`, +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ host-object-literal.ng hostbindings.ng +# ^ host-object-literal.ng +# ^^^ host-object-literal.ng +> }, +#^^^^^ host-object-literal.ng +> +> //// Unquoted static attributes +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ host-object-literal.ng +> host: { +#^^ host-object-literal.ng +# ^^^^ host-object-literal.ng meta.object-literal.key.ts +# ^ host-object-literal.ng meta.object-literal.key.ts punctuation.separator.key-value.ts +# ^^ host-object-literal.ng +> class: 'one two', +#^^^^^^^^^^^^^^^^^^^^^^ host-object-literal.ng hostbindings.ng +> myAttr: "my-value", +#^^^^^^^^^^^^^^^^^^^^^^^^ host-object-literal.ng hostbindings.ng +> style: `color: red;`, +#^^^^^^^^^^^^^^^^^^^^^^^^^^ host-object-literal.ng hostbindings.ng +> }, +#^^ host-object-literal.ng hostbindings.ng +# ^ host-object-literal.ng +# ^^ host-object-literal.ng +> +> //// Attribute bindings +#^^^^^^^^^^^^^^^^^^^^^^^^^^ host-object-literal.ng +> host: { +#^^ host-object-literal.ng +# ^^^^ host-object-literal.ng meta.object-literal.key.ts +# ^ host-object-literal.ng meta.object-literal.key.ts punctuation.separator.key-value.ts +# ^^ host-object-literal.ng +> '[attr.one]': '123 + "hello"', +#^^^^ host-object-literal.ng hostbindings.ng +# ^ host-object-literal.ng hostbindings.ng string +# ^^^^^^^^^^ host-object-literal.ng hostbindings.ng entity.other.attribute-name.html +# ^ host-object-literal.ng hostbindings.ng string +# ^ host-object-literal.ng hostbindings.ng meta.object-literal.key.ts punctuation.separator.key-value.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng string +# ^^^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng constant.numeric.decimal.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng keyword.operator.arithmetic.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng string.quoted.double.ts punctuation.definition.string.begin.ts +# ^^^^^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng string.quoted.double.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng string.quoted.double.ts punctuation.definition.string.end.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng string +# ^^ host-object-literal.ng hostbindings.ng +> '[attr.two]': '"something" + counter / 2', +#^^^^ host-object-literal.ng hostbindings.ng +# ^ host-object-literal.ng hostbindings.ng string +# ^^^^^^^^^^ host-object-literal.ng hostbindings.ng entity.other.attribute-name.html +# ^ host-object-literal.ng hostbindings.ng string +# ^ host-object-literal.ng hostbindings.ng meta.object-literal.key.ts punctuation.separator.key-value.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng string +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng string.quoted.double.ts punctuation.definition.string.begin.ts +# ^^^^^^^^^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng string.quoted.double.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng string.quoted.double.ts punctuation.definition.string.end.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng keyword.operator.arithmetic.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng +# ^^^^^^^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng variable.other.readwrite.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng keyword.operator.arithmetic.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng constant.numeric.decimal.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng string +# ^^ host-object-literal.ng hostbindings.ng +> }, +#^^ host-object-literal.ng hostbindings.ng +# ^ host-object-literal.ng +# ^^ host-object-literal.ng +> +> //// Class bindings +#^^^^^^^^^^^^^^^^^^^^^^ host-object-literal.ng +> host: { +#^^ host-object-literal.ng +# ^^^^ host-object-literal.ng meta.object-literal.key.ts +# ^ host-object-literal.ng meta.object-literal.key.ts punctuation.separator.key-value.ts +# ^^ host-object-literal.ng +> '[class.one]': 'value', +#^^^^ host-object-literal.ng hostbindings.ng +# ^ host-object-literal.ng hostbindings.ng string +# ^^^^^^^^^^^ host-object-literal.ng hostbindings.ng entity.other.attribute-name.html +# ^ host-object-literal.ng hostbindings.ng string +# ^ host-object-literal.ng hostbindings.ng meta.object-literal.key.ts punctuation.separator.key-value.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng string +# ^^^^^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng variable.other.readwrite.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng string +# ^^ host-object-literal.ng hostbindings.ng +> '[class.two]': 'foo || bar', +#^^^^ host-object-literal.ng hostbindings.ng +# ^ host-object-literal.ng hostbindings.ng string +# ^^^^^^^^^^^ host-object-literal.ng hostbindings.ng entity.other.attribute-name.html +# ^ host-object-literal.ng hostbindings.ng string +# ^ host-object-literal.ng hostbindings.ng meta.object-literal.key.ts punctuation.separator.key-value.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng string +# ^^^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng variable.other.readwrite.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng +# ^^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng keyword.operator.logical.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng +# ^^^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng variable.other.readwrite.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng string +# ^^ host-object-literal.ng hostbindings.ng +> }, +#^^ host-object-literal.ng hostbindings.ng +# ^ host-object-literal.ng +# ^^ host-object-literal.ng +> +> //// Property bindings +#^^^^^^^^^^^^^^^^^^^^^^^^^ host-object-literal.ng +> host: { +#^^ host-object-literal.ng +# ^^^^ host-object-literal.ng meta.object-literal.key.ts +# ^ host-object-literal.ng meta.object-literal.key.ts punctuation.separator.key-value.ts +# ^^ host-object-literal.ng +> '[one]': 'value', +#^^^^ host-object-literal.ng hostbindings.ng +# ^ host-object-literal.ng hostbindings.ng string +# ^^^^^ host-object-literal.ng hostbindings.ng entity.other.attribute-name.html +# ^ host-object-literal.ng hostbindings.ng string +# ^ host-object-literal.ng hostbindings.ng meta.object-literal.key.ts punctuation.separator.key-value.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng string +# ^^^^^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng variable.other.readwrite.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng string +# ^^ host-object-literal.ng hostbindings.ng +> '[two]': 'foo || bar', +#^^^^ host-object-literal.ng hostbindings.ng +# ^ host-object-literal.ng hostbindings.ng string +# ^^^^^ host-object-literal.ng hostbindings.ng entity.other.attribute-name.html +# ^ host-object-literal.ng hostbindings.ng string +# ^ host-object-literal.ng hostbindings.ng meta.object-literal.key.ts punctuation.separator.key-value.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng string +# ^^^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng variable.other.readwrite.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng +# ^^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng keyword.operator.logical.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng +# ^^^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng variable.other.readwrite.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng string +# ^^ host-object-literal.ng hostbindings.ng +> '[@three]': 'animation', +#^^^^ host-object-literal.ng hostbindings.ng +# ^ host-object-literal.ng hostbindings.ng string +# ^^^^^^^^ host-object-literal.ng hostbindings.ng entity.other.attribute-name.html +# ^ host-object-literal.ng hostbindings.ng string +# ^ host-object-literal.ng hostbindings.ng meta.object-literal.key.ts punctuation.separator.key-value.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng string +# ^^^^^^^^^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng variable.other.readwrite.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng string +# ^^ host-object-literal.ng hostbindings.ng +> }, +#^^ host-object-literal.ng hostbindings.ng +# ^ host-object-literal.ng +# ^^ host-object-literal.ng +> +> //// Event listeners +#^^^^^^^^^^^^^^^^^^^^^^^ host-object-literal.ng +> host: { +#^^ host-object-literal.ng +# ^^^^ host-object-literal.ng meta.object-literal.key.ts +# ^ host-object-literal.ng meta.object-literal.key.ts punctuation.separator.key-value.ts +# ^^ host-object-literal.ng +> '(click)': 'handleClick(123, $event)', +#^^^^ host-object-literal.ng hostbindings.ng +# ^ host-object-literal.ng hostbindings.ng string +# ^^^^^^^ host-object-literal.ng hostbindings.ng entity.other.attribute-name.html +# ^ host-object-literal.ng hostbindings.ng string +# ^ host-object-literal.ng hostbindings.ng meta.object-literal.key.ts punctuation.separator.key-value.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng string +# ^^^^^^^^^^^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng entity.name.function.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng meta.brace.round.ts +# ^^^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng constant.numeric.decimal.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng punctuation.separator.comma.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng +# ^^^^^^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng variable.other.readwrite.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng meta.brace.round.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng string +# ^^ host-object-literal.ng hostbindings.ng +> '(window:keydown)': 'globalKey()', +#^^^^ host-object-literal.ng hostbindings.ng +# ^ host-object-literal.ng hostbindings.ng string +# ^^^^^^^^^^^^^^^^ host-object-literal.ng hostbindings.ng entity.other.attribute-name.html +# ^ host-object-literal.ng hostbindings.ng string +# ^ host-object-literal.ng hostbindings.ng meta.object-literal.key.ts punctuation.separator.key-value.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng string +# ^^^^^^^^^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng entity.name.function.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng meta.brace.round.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng meta.brace.round.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng string +# ^^ host-object-literal.ng hostbindings.ng +> '(document:keydown)': 'globalKey()', +#^^^^ host-object-literal.ng hostbindings.ng +# ^ host-object-literal.ng hostbindings.ng string +# ^^^^^^^^^^^^^^^^^^ host-object-literal.ng hostbindings.ng entity.other.attribute-name.html +# ^ host-object-literal.ng hostbindings.ng string +# ^ host-object-literal.ng hostbindings.ng meta.object-literal.key.ts punctuation.separator.key-value.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng string +# ^^^^^^^^^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng entity.name.function.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng meta.brace.round.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng meta.brace.round.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng string +# ^^ host-object-literal.ng hostbindings.ng +> '(@animation.start)': 'handleStart()', +#^^^^ host-object-literal.ng hostbindings.ng +# ^ host-object-literal.ng hostbindings.ng string +# ^^^^^^^^^^^^^^^^^^ host-object-literal.ng hostbindings.ng entity.other.attribute-name.html +# ^ host-object-literal.ng hostbindings.ng string +# ^ host-object-literal.ng hostbindings.ng meta.object-literal.key.ts punctuation.separator.key-value.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng string +# ^^^^^^^^^^^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng entity.name.function.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng meta.brace.round.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng meta.brace.round.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng string +# ^^ host-object-literal.ng hostbindings.ng +> '(@animation.end)': 'handleEnd()', +#^^^^ host-object-literal.ng hostbindings.ng +# ^ host-object-literal.ng hostbindings.ng string +# ^^^^^^^^^^^^^^^^ host-object-literal.ng hostbindings.ng entity.other.attribute-name.html +# ^ host-object-literal.ng hostbindings.ng string +# ^ host-object-literal.ng hostbindings.ng meta.object-literal.key.ts punctuation.separator.key-value.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng string +# ^^^^^^^^^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng entity.name.function.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng meta.brace.round.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng meta.brace.round.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng string +# ^^ host-object-literal.ng hostbindings.ng +> }, +#^^ host-object-literal.ng hostbindings.ng +# ^ host-object-literal.ng +# ^^ host-object-literal.ng +> +> //// Quotes inside the value +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ host-object-literal.ng +> host: { +#^^ host-object-literal.ng +# ^^^^ host-object-literal.ng meta.object-literal.key.ts +# ^ host-object-literal.ng meta.object-literal.key.ts punctuation.separator.key-value.ts +# ^^ host-object-literal.ng +> '(click)': 'handleClick("hello `${name}`")', +#^^^^ host-object-literal.ng hostbindings.ng +# ^ host-object-literal.ng hostbindings.ng string +# ^^^^^^^ host-object-literal.ng hostbindings.ng entity.other.attribute-name.html +# ^ host-object-literal.ng hostbindings.ng string +# ^ host-object-literal.ng hostbindings.ng meta.object-literal.key.ts punctuation.separator.key-value.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng string +# ^^^^^^^^^^^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng entity.name.function.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng meta.brace.round.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng string.quoted.double.ts punctuation.definition.string.begin.ts +# ^^^^^^^^^^^^^^^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng string.quoted.double.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng string.quoted.double.ts punctuation.definition.string.end.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng meta.brace.round.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng string +# ^^ host-object-literal.ng hostbindings.ng +> }, +#^^ host-object-literal.ng hostbindings.ng +# ^ host-object-literal.ng +# ^^ host-object-literal.ng +> +> //// Expression inside object literal +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ host-object-literal.ng +> host: { +#^^ host-object-literal.ng +# ^^^^ host-object-literal.ng meta.object-literal.key.ts +# ^ host-object-literal.ng meta.object-literal.key.ts punctuation.separator.key-value.ts +# ^^ host-object-literal.ng +> ...before, +#^^^^^^^^^^^^^^^ host-object-literal.ng hostbindings.ng +> '(click)': 'handleClick("hello `${name}`")', +#^^^^ host-object-literal.ng hostbindings.ng +# ^ host-object-literal.ng hostbindings.ng string +# ^^^^^^^ host-object-literal.ng hostbindings.ng entity.other.attribute-name.html +# ^ host-object-literal.ng hostbindings.ng string +# ^ host-object-literal.ng hostbindings.ng meta.object-literal.key.ts punctuation.separator.key-value.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng string +# ^^^^^^^^^^^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng entity.name.function.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng meta.brace.round.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng string.quoted.double.ts punctuation.definition.string.begin.ts +# ^^^^^^^^^^^^^^^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng string.quoted.double.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng string.quoted.double.ts punctuation.definition.string.end.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng meta.brace.round.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng string +# ^^ host-object-literal.ng hostbindings.ng +> 'class': 'hello', +#^^^^^^^^^^^^^^^^^^^^^^ host-object-literal.ng hostbindings.ng +> ...after, +#^^^^^^^^^^^^^^ host-object-literal.ng hostbindings.ng +> }, +#^^ host-object-literal.ng hostbindings.ng +# ^ host-object-literal.ng +# ^^ host-object-literal.ng +> +> //// Variable initializer +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^ host-object-literal.ng +> host: HOST_BINDINGS, +#^^^^^^^^^^^^^^^^^^^^^^^ host-object-literal.ng +> +> //// Variable values +#^^^^^^^^^^^^^^^^^^^^^^^ host-object-literal.ng +> host: { +#^^ host-object-literal.ng +# ^^^^ host-object-literal.ng meta.object-literal.key.ts +# ^ host-object-literal.ng meta.object-literal.key.ts punctuation.separator.key-value.ts +# ^^ host-object-literal.ng +> '(click)': CLICK_LISTENER + OTHER_STUFF, +#^^^^ host-object-literal.ng hostbindings.ng +# ^ host-object-literal.ng hostbindings.ng string +# ^^^^^^^ host-object-literal.ng hostbindings.ng entity.other.attribute-name.html +# ^ host-object-literal.ng hostbindings.ng string +# ^ host-object-literal.ng hostbindings.ng meta.object-literal.key.ts punctuation.separator.key-value.ts +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng +# ^^ host-object-literal.ng hostbindings.ng +> 'class': (MY_CLASS + ' ' + MY_OTHER_CLASS) + ` foo-${bar + 123}`, +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ host-object-literal.ng hostbindings.ng +# ^ host-object-literal.ng +# ^^^ host-object-literal.ng +> }, +#^^^^^ host-object-literal.ng +> +> //// One of each +#^^^^^^^^^^^^^^^^^^^ host-object-literal.ng +> host: { +#^^ host-object-literal.ng +# ^^^^ host-object-literal.ng meta.object-literal.key.ts +# ^ host-object-literal.ng meta.object-literal.key.ts punctuation.separator.key-value.ts +# ^^ host-object-literal.ng +> 'class': 'one two', +#^^^^^^^^^^^^^^^^^^^^^^^^ host-object-literal.ng hostbindings.ng +> myAttr: "my-value", +#^^^^^^^^^^^^^^^^^^^^^^^^ host-object-literal.ng hostbindings.ng +> '[attr.greeting]': '"hello " + name', +#^^^^ host-object-literal.ng hostbindings.ng +# ^ host-object-literal.ng hostbindings.ng string +# ^^^^^^^^^^^^^^^ host-object-literal.ng hostbindings.ng entity.other.attribute-name.html +# ^ host-object-literal.ng hostbindings.ng string +# ^ host-object-literal.ng hostbindings.ng meta.object-literal.key.ts punctuation.separator.key-value.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng string +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng string.quoted.double.ts punctuation.definition.string.begin.ts +# ^^^^^^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng string.quoted.double.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng string.quoted.double.ts punctuation.definition.string.end.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng keyword.operator.arithmetic.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng +# ^^^^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng variable.other.readwrite.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng string +# ^^ host-object-literal.ng hostbindings.ng +> ...extras, +#^^^^^^^^^^^^^^^ host-object-literal.ng hostbindings.ng +> '[class.is-visible]': 'isVisible()', +#^^^^ host-object-literal.ng hostbindings.ng +# ^ host-object-literal.ng hostbindings.ng string +# ^^^^^^^^^^^^^^^^^^ host-object-literal.ng hostbindings.ng entity.other.attribute-name.html +# ^ host-object-literal.ng hostbindings.ng string +# ^ host-object-literal.ng hostbindings.ng meta.object-literal.key.ts punctuation.separator.key-value.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng string +# ^^^^^^^^^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng entity.name.function.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng meta.brace.round.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng meta.brace.round.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng string +# ^^ host-object-literal.ng hostbindings.ng +> '[id]': '_id', +#^^^^ host-object-literal.ng hostbindings.ng +# ^ host-object-literal.ng hostbindings.ng string +# ^^^^ host-object-literal.ng hostbindings.ng entity.other.attribute-name.html +# ^ host-object-literal.ng hostbindings.ng string +# ^ host-object-literal.ng hostbindings.ng meta.object-literal.key.ts punctuation.separator.key-value.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng string +# ^^^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng variable.other.readwrite.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng string +# ^^ host-object-literal.ng hostbindings.ng +> '(click)': 'handleClick($event)', +#^^^^ host-object-literal.ng hostbindings.ng +# ^ host-object-literal.ng hostbindings.ng string +# ^^^^^^^ host-object-literal.ng hostbindings.ng entity.other.attribute-name.html +# ^ host-object-literal.ng hostbindings.ng string +# ^ host-object-literal.ng hostbindings.ng meta.object-literal.key.ts punctuation.separator.key-value.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng string +# ^^^^^^^^^^^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng entity.name.function.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng meta.brace.round.ts +# ^^^^^^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng variable.other.readwrite.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng meta.brace.round.ts +# ^ host-object-literal.ng hostbindings.ng hostbinding.dynamic.ng string +# ^^ host-object-literal.ng hostbindings.ng +> }, +#^^ host-object-literal.ng hostbindings.ng +# ^ host-object-literal.ng +# ^^ host-object-literal.ng +>}) +#^^^ host-object-literal.ng +>export class TMComponent{} +#^^^^^^^^^^^^^^^^^^^^^^^^^^^ host-object-literal.ng +> \ No newline at end of file