From d8c497515ac981d8903d9c37190be39bde60ca51 Mon Sep 17 00:00:00 2001 From: Ahn Date: Thu, 12 Nov 2020 21:26:48 +0100 Subject: [PATCH] fix(compiler): fallback to ES2015 when no target is defined Closes #622 --- .../my-lib/src/lib/disableable.directive.ts | 36 ++++++ .../my-lib/src/lib/my-lib.component.ts | 15 ++- .../ng-jest-compiler.spec.ts.snap | 110 ++++++++---------- .../__snapshots__/ng-jest-config.spec.ts.snap | 4 +- src/compiler/ngcc-jest-processor.ts | 9 +- src/config/ng-jest-config.ts | 4 +- 6 files changed, 105 insertions(+), 73 deletions(-) create mode 100644 e2e/test-app-v10/projects/my-lib/src/lib/disableable.directive.ts diff --git a/e2e/test-app-v10/projects/my-lib/src/lib/disableable.directive.ts b/e2e/test-app-v10/projects/my-lib/src/lib/disableable.directive.ts new file mode 100644 index 0000000000..e76023b55d --- /dev/null +++ b/e2e/test-app-v10/projects/my-lib/src/lib/disableable.directive.ts @@ -0,0 +1,36 @@ +import { Directive, ElementRef, Input } from '@angular/core'; + +/** + * A base class for components that can be disabled, and that store their disabled + * state in the HTML element. This prevents the HTML element from being focused or clicked, + * and can be used for CSS selectors. + */ +@Directive() +export abstract class DisableableDirective { + + /** Binds to the HTML disabled property OR disabled attribute, if present. */ + @Input() + public set disabled(v: boolean) { + const elt = this.elementRef.nativeElement; + const disabledProp = (elt as any).disabled; + if (typeof (disabledProp) === 'boolean') { + // Set disabled property + (elt as any).disabled = v; + return; + } + + // Set disabled attribute + elt.setAttribute('disabled', v.toString()); + } + public get disabled(): boolean { + const elt = this.elementRef.nativeElement; + const disabledProp = (elt as any).disabled; + if (typeof (disabledProp) === 'boolean') { + return disabledProp; + } + const disabledAttr = elt.getAttribute('disabled'); + return disabledAttr === 'true'; + } + + constructor(public elementRef: ElementRef) { } +} diff --git a/e2e/test-app-v10/projects/my-lib/src/lib/my-lib.component.ts b/e2e/test-app-v10/projects/my-lib/src/lib/my-lib.component.ts index d3581b5516..6042f24bad 100644 --- a/e2e/test-app-v10/projects/my-lib/src/lib/my-lib.component.ts +++ b/e2e/test-app-v10/projects/my-lib/src/lib/my-lib.component.ts @@ -1,4 +1,6 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, ElementRef, OnInit } from '@angular/core'; + +import { DisableableDirective } from './disableable.directive'; @Component({ selector: 'lib-my-lib', @@ -10,11 +12,18 @@ import { Component, OnInit } from '@angular/core'; styles: [ ] }) -export class MyLibComponent implements OnInit { +export class MyLibComponent extends DisableableDirective implements OnInit { - constructor() { } + constructor(public elementRef: ElementRef) { + super(elementRef); + } ngOnInit(): void { } + toggle(): void { + if (!super.disabled) { + console.log('test'); + } + } } diff --git a/src/__tests__/__snapshots__/ng-jest-compiler.spec.ts.snap b/src/__tests__/__snapshots__/ng-jest-compiler.spec.ts.snap index 8ed5a51912..083bee1369 100644 --- a/src/__tests__/__snapshots__/ng-jest-compiler.spec.ts.snap +++ b/src/__tests__/__snapshots__/ng-jest-compiler.spec.ts.snap @@ -4,26 +4,21 @@ exports[`NgJestCompiler with isolatedModule false should downlevel decorators fo "\\"use strict\\"; Object.defineProperty(exports, \\"__esModule\\", { value: true }); exports.MyService = exports.ClassInject = void 0; -var tslib_1 = require(\\"tslib\\"); -var core_1 = require(\\"@angular/core\\"); -var ClassInject = /** @class */ (function () { - function ClassInject() { - } - return ClassInject; -}()); +const tslib_1 = require(\\"tslib\\"); +const core_1 = require(\\"@angular/core\\"); +class ClassInject { +} exports.ClassInject = ClassInject; -var MyService = /** @class */ (function () { +let MyService = class MyService { // eslint-disable-next-line - function MyService(_v) { - } - MyService.ctorParameters = function () { return [ - { type: ClassInject } - ]; }; - MyService = tslib_1.__decorate([ - core_1.Injectable() - ], MyService); - return MyService; -}()); + constructor(_v) { } +}; +MyService.ctorParameters = () => [ + { type: ClassInject } +]; +MyService = tslib_1.__decorate([ + core_1.Injectable() +], MyService); exports.MyService = MyService; //# " `; @@ -32,7 +27,7 @@ exports[`NgJestCompiler with isolatedModule false should hoist correctly 1`] = ` "\\"use strict\\"; Object.defineProperty(exports, \\"__esModule\\", { value: true }); jest.mock('./foo'); -var foo_1 = require(\\"./foo\\"); +const foo_1 = require(\\"./foo\\"); console.log(foo_1.getFoo()); //# " `; @@ -41,21 +36,20 @@ exports[`NgJestCompiler with isolatedModule false should return compiled result "\\"use strict\\"; Object.defineProperty(exports, \\"__esModule\\", { value: true }); exports.AppComponent = void 0; -var tslib_1 = require(\\"tslib\\"); -var core_1 = require(\\"@angular/core\\"); -var AppComponent = /** @class */ (function () { - function AppComponent() { +const tslib_1 = require(\\"tslib\\"); +const core_1 = require(\\"@angular/core\\"); +let AppComponent = class AppComponent { + constructor() { this.title = 'test-app-v10'; } - AppComponent = tslib_1.__decorate([ - core_1.Component({ - selector: 'app-root', - templateUrl: './app.component.html', - styleUrls: ['./app.component.scss'], - }) - ], AppComponent); - return AppComponent; -}()); +}; +AppComponent = tslib_1.__decorate([ + core_1.Component({ + selector: 'app-root', + templateUrl: './app.component.html', + styleUrls: ['./app.component.scss'], + }) +], AppComponent); exports.AppComponent = AppComponent; //# " `; @@ -64,21 +58,20 @@ exports[`NgJestCompiler with isolatedModule false should return compiled result "\\"use strict\\"; Object.defineProperty(exports, \\"__esModule\\", { value: true }); exports.AppComponent = void 0; -var tslib_1 = require(\\"tslib\\"); -var core_1 = require(\\"@angular/core\\"); -var AppComponent = /** @class */ (function () { - function AppComponent() { +const tslib_1 = require(\\"tslib\\"); +const core_1 = require(\\"@angular/core\\"); +let AppComponent = class AppComponent { + constructor() { this.title = 'test-app-v10'; } - AppComponent = tslib_1.__decorate([ - core_1.Component({ - selector: 'app-root', - templateUrl: './app.component.html', - styleUrls: ['./app.component.scss'], - }) - ], AppComponent); - return AppComponent; -}()); +}; +AppComponent = tslib_1.__decorate([ + core_1.Component({ + selector: 'app-root', + templateUrl: './app.component.html', + styleUrls: ['./app.component.scss'], + }) +], AppComponent); exports.AppComponent = AppComponent; //# " `; @@ -91,7 +84,7 @@ exports[`NgJestCompiler with isolatedModules true should hoist correctly 1`] = ` "\\"use strict\\"; Object.defineProperty(exports, \\"__esModule\\", { value: true }); jest.mock('./foo'); -var foo_1 = require(\\"./foo\\"); +const foo_1 = require(\\"./foo\\"); console.log(foo_1.getFoo()); //# " `; @@ -100,23 +93,18 @@ exports[`NgJestCompiler with isolatedModules true should return result 1`] = ` "\\"use strict\\"; Object.defineProperty(exports, \\"__esModule\\", { value: true }); exports.MyService = exports.ClassInject = void 0; -var tslib_1 = require(\\"tslib\\"); -var core_1 = require(\\"@angular/core\\"); -var ClassInject = /** @class */ (function () { - function ClassInject() { - } - return ClassInject; -}()); +const tslib_1 = require(\\"tslib\\"); +const core_1 = require(\\"@angular/core\\"); +class ClassInject { +} exports.ClassInject = ClassInject; -var MyService = /** @class */ (function () { +let MyService = class MyService { // eslint-disable-next-line - function MyService(_v) { - } - MyService = tslib_1.__decorate([ - core_1.Injectable() - ], MyService); - return MyService; -}()); + constructor(_v) { } +}; +MyService = tslib_1.__decorate([ + core_1.Injectable() +], MyService); exports.MyService = MyService; //# " `; diff --git a/src/__tests__/__snapshots__/ng-jest-config.spec.ts.snap b/src/__tests__/__snapshots__/ng-jest-config.spec.ts.snap index 6960b46be2..65b7b42eee 100644 --- a/src/__tests__/__snapshots__/ng-jest-config.spec.ts.snap +++ b/src/__tests__/__snapshots__/ng-jest-config.spec.ts.snap @@ -80,7 +80,7 @@ Object { "sourceRoot": undefined, "strict": true, "suppressOutputPathCheck": true, - "target": 1, + "target": 2, "tsBuildInfoFile": undefined, "types": Array [ "node", @@ -124,7 +124,7 @@ Object { "sourceRoot": undefined, "strict": true, "suppressOutputPathCheck": true, - "target": 1, + "target": 2, "tsBuildInfoFile": undefined, "types": Array [ "node", diff --git a/src/compiler/ngcc-jest-processor.ts b/src/compiler/ngcc-jest-processor.ts index d9a5079580..c05efb50bc 100644 --- a/src/compiler/ngcc-jest-processor.ts +++ b/src/compiler/ngcc-jest-processor.ts @@ -17,13 +17,12 @@ function findNodeModulesDirectory(startPoint: string): string { current = dirname(current); } - throw new Error(`Cannot locate the 'node_modules' directory.`); -} - -if (!existsSync(join(process.cwd(), 'angular.json'))) { - throw new Error('ngcc-jest-processor should be only run from root directory'); + throw new Error( + `Cannot locate the 'node_modules' directory. Please make sure you are running jest from root level of your project`, + ); } +process.stdout.write('ngcc-jest-processor: running ngcc\n'); // We spawn instead of using the API because: // - NGCC Async uses clustering which is problematic when used via the API which means // that we cannot setup multiple cluster masters with different options. diff --git a/src/config/ng-jest-config.ts b/src/config/ng-jest-config.ts index 73061feb7d..98adedbeb8 100644 --- a/src/config/ng-jest-config.ts +++ b/src/config/ng-jest-config.ts @@ -53,8 +53,8 @@ export class NgJestConfig extends ConfigSet { // The transformer is not needed for VE or Ivy in this plugin since Angular decorators are removed. // While the transformer would make no changes, it would still need to walk each source file AST. annotationsAs: 'decorators' as const, - module: this.compilerModule.ModuleKind.CommonJS, - target: this.compilerModule.ScriptTarget.ES5, + module: result.options.module ?? this.compilerModule.ModuleKind.CommonJS, + target: result.options.target ?? this.compilerModule.ScriptTarget.ES2015, }, }; }