From d6411c27291b69f46b3b7f648d3445c9c4ba3a4a Mon Sep 17 00:00:00 2001 From: Daniel Trevino <23410540+danieltre23@users.noreply.github.com> Date: Mon, 26 Jul 2021 18:21:46 +0000 Subject: [PATCH] refactor(compiler-cli): add `BananaInBoxCheck` to the template checks (#42984) Add the implementation of a Template Check that ensures the correct use of two-way binding syntax. Generates a warning when '([foo])="bar"' is found instead of '[(foo)]="bar"'. Refs #42966 PR Close #42984 --- goldens/public-api/compiler-cli/error_code.md | 2 +- .../src/ngtsc/diagnostics/src/error_code.ts | 10 +++ .../invalid_banana_in_box/BUILD.bazel | 13 ++++ .../invalid_banana_in_box/index.ts | 65 +++++++++++++++++++ 4 files changed, 89 insertions(+), 1 deletion(-) create mode 100644 packages/compiler-cli/src/ngtsc/typecheck/extended/src/template_checks/invalid_banana_in_box/BUILD.bazel create mode 100644 packages/compiler-cli/src/ngtsc/typecheck/extended/src/template_checks/invalid_banana_in_box/index.ts diff --git a/goldens/public-api/compiler-cli/error_code.md b/goldens/public-api/compiler-cli/error_code.md index 84a4a59516..7134a7b404 100644 --- a/goldens/public-api/compiler-cli/error_code.md +++ b/goldens/public-api/compiler-cli/error_code.md @@ -34,6 +34,7 @@ export enum ErrorCode { INJECTABLE_DUPLICATE_PROV = 9001, INLINE_TCB_REQUIRED = 8900, INLINE_TYPE_CTOR_REQUIRED = 8901, + INVALID_BANANA_IN_BOX = 8101, MISSING_PIPE = 8004, MISSING_REFERENCE_TARGET = 8003, NGMODULE_DECLARATION_NOT_UNIQUE = 6007, @@ -67,7 +68,6 @@ export enum ErrorCode { WRITE_TO_READ_ONLY_VARIABLE = 8005 } - // (No @packageDocumentation comment for this package) ``` diff --git a/packages/compiler-cli/src/ngtsc/diagnostics/src/error_code.ts b/packages/compiler-cli/src/ngtsc/diagnostics/src/error_code.ts index e6dba314c2..26c5ffd587 100644 --- a/packages/compiler-cli/src/ngtsc/diagnostics/src/error_code.ts +++ b/packages/compiler-cli/src/ngtsc/diagnostics/src/error_code.ts @@ -172,6 +172,16 @@ export enum ErrorCode { */ SPLIT_TWO_WAY_BINDING = 8007, + /** + * A two way binding in a template has an incorrect syntax, + * parentheses outside brackets. For example: + * + * ``` + *
+ * ``` + */ + INVALID_BANANA_IN_BOX = 8101, + /** * The template type-checking engine would need to generate an inline type check block for a * component, but the current type-checking environment doesn't support it. diff --git a/packages/compiler-cli/src/ngtsc/typecheck/extended/src/template_checks/invalid_banana_in_box/BUILD.bazel b/packages/compiler-cli/src/ngtsc/typecheck/extended/src/template_checks/invalid_banana_in_box/BUILD.bazel new file mode 100644 index 0000000000..f2a1359185 --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/typecheck/extended/src/template_checks/invalid_banana_in_box/BUILD.bazel @@ -0,0 +1,13 @@ +load("//tools:defaults.bzl", "ts_library") + +ts_library( + name = "invalid_banana_in_box", + srcs = ["index.ts"], + visibility = ["//packages/compiler-cli/src/ngtsc/typecheck/extended:__subpackages__"], + deps = [ + "//packages/compiler", + "//packages/compiler-cli/src/ngtsc/diagnostics", + "//packages/compiler-cli/src/ngtsc/typecheck/extended/api", + "@npm//typescript", + ], +) diff --git a/packages/compiler-cli/src/ngtsc/typecheck/extended/src/template_checks/invalid_banana_in_box/index.ts b/packages/compiler-cli/src/ngtsc/typecheck/extended/src/template_checks/invalid_banana_in_box/index.ts new file mode 100644 index 0000000000..93ae48b89b --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/typecheck/extended/src/template_checks/invalid_banana_in_box/index.ts @@ -0,0 +1,65 @@ +/** + * @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 + */ + +import {TmplAstBoundEvent, TmplAstNode, TmplAstRecursiveVisitor} from '@angular/compiler'; +import * as ts from 'typescript'; +import {ErrorCode} from '../../../../../diagnostics'; +import {TemplateCheck, TemplateContext, TemplateDiagnostic} from '../../../api/api'; + +/** + * Ensures the two-way binding syntax is correct. + * Parentheses should be inside the brackets "[()]". + * Will return diagnostic information when "([])" is found. + */ +export class InvalidBananaInBoxCheck implements TemplateCheck { + code: ErrorCode.INVALID_BANANA_IN_BOX = 8101; + + run(ctx: TemplateContext, + template: TmplAstNode[]): TemplateDiagnostic[] { + const visitor = new BananaVisitor(ctx); + + return visitor.getDiagnostics(template); + } +} + +class BananaVisitor extends TmplAstRecursiveVisitor { + private diagnostics: ts.Diagnostic[] = []; + + constructor(public readonly ctx: TemplateContext) { + super(); + } + + /** + * Check for outputs with names surrounded in brackets "[]". + * The syntax '([foo])="bar"' would be interpreted as an @Output() + * with name '[foo]'. Just like '(foo)="bar"' would have the name 'foo'. + * Generate diagnostic information for the cases found. + */ + override visitBoundEvent(boundEvent: TmplAstBoundEvent) { + const name = boundEvent.name; + if (name.startsWith('[') && name.endsWith(']')) { + const boundSyntax = boundEvent.sourceSpan.toString(); + const expectedBoundSyntax = boundSyntax.replace(`(${name})`, `[(${name.slice(1, -1)})]`); + this.diagnostics.push( + this.ctx.templateTypeChecker.makeTemplateDiagnostic( + this.ctx.component, boundEvent.sourceSpan, ts.DiagnosticCategory.Warning, + ErrorCode.INVALID_BANANA_IN_BOX, + `In the two-way binding syntax the parentheses should be inside the brackets, ex. '${ + expectedBoundSyntax}'. + Find more at https://angular.io/guide/two-way-binding`)); + } + } + + getDiagnostics(template: TmplAstNode[]): ts.Diagnostic[] { + this.diagnostics = []; + for (const node of template) { + node.visit(this); + } + return this.diagnostics; + } +}