Update to latest version of angular (#17303)

* Update to the latest version of angular

Signed-off-by: Matt Busche <mrbusche@gmail.com>
This commit is contained in:
Matt Busche 2022-08-16 22:30:48 -05:00 committed by GitHub
parent a272158023
commit 548b27a0c6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 6557 additions and 4776 deletions

View File

@ -5,18 +5,18 @@
"description": "Harbor UI with Clarity", "description": "Harbor UI with Clarity",
"angular-cli": {}, "angular-cli": {},
"scripts": { "scripts": {
// triggered after running "npm install" // triggered after running "npm install"
"postinstall": "node scripts/convert-yaml-to-json.js && ng-swagger-gen -i ng-swagger-gen/swagger.json -o ng-swagger-gen && node scripts/delete-swagger-json.js", "postinstall": "node scripts/convert-yaml-to-json.js && ng-swagger-gen -i ng-swagger-gen/swagger.json -o ng-swagger-gen && node scripts/delete-swagger-json.js",
// For developing // For developing
"start": "node --max_old_space_size=2048 ./node_modules/@angular/cli/bin/ng serve --ssl true --host 0.0.0.0 --proxy-config proxy.config.json", "start": "node --max_old_space_size=2048 ./node_modules/@angular/cli/bin/ng serve --ssl true --host 0.0.0.0 --proxy-config proxy.config.json",
"start:prod": "node --max_old_space_size=2048 ./node_modules/@angular/cli/bin/ng serve --ssl true --host 0.0.0.0 --proxy-config proxy.config.json --configuration production", "start:prod": "node --max_old_space_size=2048 ./node_modules/@angular/cli/bin/ng serve --ssl true --host 0.0.0.0 --proxy-config proxy.config.json --configuration production",
// For code grammar checking // For code grammar checking
"lint": "tslint \"src/**/*.ts\"", "lint": "tslint \"src/**/*.ts\"",
"lint_fix": "tslint --fix \"src/**/*.ts\"", "lint_fix": "tslint --fix \"src/**/*.ts\"",
// For unit test // For unit test
"test": "node --max_old_space_size=2048 ./node_modules/@angular/cli/bin/ng test --code-coverage", "test": "node --max_old_space_size=2048 ./node_modules/@angular/cli/bin/ng test --code-coverage",
"test:watch": "ng test --code-coverage --watch", "test:watch": "ng test --code-coverage --watch",
@ -24,80 +24,80 @@
"test:chrome": "ng test --code-coverage --browsers Chrome", "test:chrome": "ng test --code-coverage --browsers Chrome",
"test:headless": "ng test --watch=false --no-progress --code-coverage --browsers=ChromeNoSandboxHeadless", "test:headless": "ng test --watch=false --no-progress --code-coverage --browsers=ChromeNoSandboxHeadless",
"test:chrome-debug": "ng test --code-coverage --browsers Chrome --watch", "test:chrome-debug": "ng test --code-coverage --browsers Chrome --watch",
// E2e related. Currently not used // E2e related. Currently not used
"pree2e": "webdriver-manager update", "pree2e": "webdriver-manager update",
"e2e": "protractor", "e2e": "protractor",
"build": "ng build --aot", "build": "ng build --aot",
"release": "ng build --configuration production", "release": "ng build --configuration production",
"build-mock-api-server": "tsc -p server", "build-mock-api-server": "tsc -p server",
// to run a mocked node express api server // to run a mocked node express api server
"mock-api-server": "npm run build-mock-api-server && node server/dist/server/src/mock-api.js", "mock-api-server": "npm run build-mock-api-server && node server/dist/server/src/mock-api.js",
// Run this command before the production building. It will set the current timestamp to "buildTimestamp" property in "environment.prod.ts" file // Run this command before the production building. It will set the current timestamp to "buildTimestamp" property in "environment.prod.ts" file
// And "buildTimestamp" will be used as a query parameter to avoid browser cache after upgrading Harbor UI // And "buildTimestamp" will be used as a query parameter to avoid browser cache after upgrading Harbor UI
"generate-build-timestamp": "node scripts/generate-build-timestamp.js" "generate-build-timestamp": "node scripts/generate-build-timestamp.js"
}, },
"private": true, "private": true,
"dependencies": { "dependencies": {
// Angular framework. Required // Angular framework. Required
"@angular/animations": "~13.3.0", "@angular/animations": "~14.1.0",
"@angular/common": "~13.3.0", "@angular/common": "~14.1.0",
"@angular/compiler": "~13.3.0", "@angular/compiler": "~14.1.0",
"@angular/core": "~13.3.0", "@angular/core": "~14.1.0",
"@angular/forms": "~13.3.0", "@angular/forms": "~14.1.0",
"@angular/localize": "~13.3.0", "@angular/localize": "~14.1.0",
"@angular/platform-browser": "~13.3.0", "@angular/platform-browser": "~14.1.0",
"@angular/platform-browser-dynamic": "~13.3.0", "@angular/platform-browser-dynamic": "~14.1.0",
"@angular/router": "~13.2.2", "@angular/router": "~13.2.2",
"rxjs": "^7.4.0", "rxjs": "^7.4.0",
"tslib": "^2.2.0", "tslib": "^2.2.0",
"zone.js": "~0.11.4", "zone.js": "~0.11.4",
// Clarity UI. Required // Clarity UI. Required
"@clr/angular": "13.0.2", "@clr/angular": "13.0.2",
"@cds/core": "5.6.4", "@cds/core": "5.6.4",
"@clr/icons": "13.0.2", "@clr/icons": "13.0.2",
"@clr/ui": "13.0.2", "@clr/ui": "13.0.2",
// For Harbor i18n functionality. Required // For Harbor i18n functionality. Required
"@ngx-translate/core": "^13.0.0", "@ngx-translate/core": "^13.0.0",
"@ngx-translate/http-loader": "^6.0.0", "@ngx-translate/http-loader": "^6.0.0",
// For cron string checking. Required // For cron string checking. Required
"cron-validator": "^1.2.1", "cron-validator": "^1.2.1",
// Used by CopyInputComponent to copy pull command to clipboard. Required // Used by CopyInputComponent to copy pull command to clipboard. Required
"ngx-clipboard": "^12.3.1", "ngx-clipboard": "^12.3.1",
// For Harbor cookie service. Required // For Harbor cookie service. Required
"ngx-cookie": "^5.0.2", "ngx-cookie": "^5.0.2",
// To render markdown data. Required // To render markdown data. Required
"ngx-markdown": "~13.0.0", "ngx-markdown": "~13.0.0",
// For swagger API center. Required // For swagger API center. Required
"swagger-ui": "~4.9.0", "swagger-ui": "~4.9.0",
"buffer": "^6.0.3", "buffer": "^6.0.3",
"stream-browserify": "^3.0.0", "stream-browserify": "^3.0.0",
// To convert yaml to json. Required // To convert yaml to json. Required
"js-yaml": "^4.1.0" "js-yaml": "^4.1.0"
}, },
"devDependencies": { "devDependencies": {
// Angular framework. Required // Angular framework. Required
"@angular-devkit/build-angular": "~13.3.0", "@angular-devkit/build-angular": "~14.1.0",
"@angular/cli": "~13.3.0", "@angular/cli": "~14.1.0",
"@angular/compiler-cli": "~13.3.0", "@angular/compiler-cli": "~14.1.0",
"@types/jasmine": "~3.10.1", "@types/jasmine": "~3.10.1",
"@types/node": "^16.11.6", "@types/node": "^16.11.6",
"typescript": "~4.5.4", "typescript": "~4.5.4",
// For unit test. Required // For unit test. Required
"jasmine-core": "^4.0.0", "jasmine-core": "^4.0.0",
"jasmine-spec-reporter": "~7.0.0", "jasmine-spec-reporter": "~7.0.0",
@ -106,27 +106,27 @@
"karma-coverage": "^2.2.0", "karma-coverage": "^2.2.0",
"karma-jasmine": "~4.0.1", "karma-jasmine": "~4.0.1",
"karma-jasmine-html-reporter": "^1.7.0", "karma-jasmine-html-reporter": "^1.7.0",
// To run a local mocked API server. Required // To run a local mocked API server. Required
"@types/express": "^4.17.12", "@types/express": "^4.17.12",
"express": "^4.17.1", "express": "^4.17.1",
// To generate models and Angular services based on swagger.yaml. Required // To generate models and Angular services based on swagger.yaml. Required
// do not upgrade it // do not upgrade it
"ng-swagger-gen": "^1.8.1", "ng-swagger-gen": "^1.8.1",
// For e2e test. Required // For e2e test. Required
"protractor": "^7.0.0", "protractor": "^7.0.0",
// For code grammar checking. Optional // For code grammar checking. Optional
"eslint": "^8.12.0", "eslint": "^8.12.0",
"@angular-eslint/eslint-plugin": "13.2.1", "@angular-eslint/eslint-plugin": "14.0.2",
"@angular-eslint/eslint-plugin-template": "13.2.1", "@angular-eslint/eslint-plugin-template": "14.0.2",
"@angular-eslint/schematics": "13.2.1", "@angular-eslint/schematics": "14.0.2",
"@angular-eslint/template-parser": "13.2.1", "@angular-eslint/template-parser": "14.0.2",
"@typescript-eslint/eslint-plugin": "5.17.0", "@typescript-eslint/eslint-plugin": "5.29.0",
"@typescript-eslint/parser": "5.17.0", "@typescript-eslint/parser": "5.29.0",
// For code format // For code format
"prettier": "^2.6.2", "prettier": "^2.6.2",
"prettier-eslint": "^14.0.2", "prettier-eslint": "^14.0.2",

View File

@ -168,7 +168,6 @@
} }
} }
}, },
"defaultProject": "harbor-portal",
"schematics": { "schematics": {
"@schematics/angular:component": { "@schematics/angular:component": {
"prefix": "app" "prefix": "app"

File diff suppressed because it is too large Load Diff

View File

@ -27,19 +27,19 @@
}, },
"private": true, "private": true,
"dependencies": { "dependencies": {
"@angular/animations": "~13.3.4", "@angular/animations": "^14.1.0",
"@angular/common": "~13.3.4", "@angular/common": "^14.1.0",
"@angular/compiler": "~13.3.4", "@angular/compiler": "^14.1.0",
"@angular/core": "~13.3.4", "@angular/core": "^14.1.0",
"@angular/forms": "~13.3.4", "@angular/forms": "^14.1.0",
"@angular/localize": "~13.3.4", "@angular/localize": "^14.1.0",
"@angular/platform-browser": "~13.3.4", "@angular/platform-browser": "^14.1.0",
"@angular/platform-browser-dynamic": "~13.3.4", "@angular/platform-browser-dynamic": "^14.1.0",
"@angular/router": "~13.3.4", "@angular/router": "^14.1.0",
"@cds/core": "6.0.0", "@cds/core": "6.0.0",
"@clr/angular": "13.3.0", "@clr/angular": "13.7.0",
"@clr/icons": "13.0.2", "@clr/icons": "13.0.2",
"@clr/ui": "13.3.0", "@clr/ui": "13.7.0",
"@ngx-translate/core": "^13.0.0", "@ngx-translate/core": "^13.0.0",
"@ngx-translate/http-loader": "^6.0.0", "@ngx-translate/http-loader": "^6.0.0",
"buffer": "^6.0.3", "buffer": "^6.0.3",
@ -47,7 +47,7 @@
"js-yaml": "^4.1.0", "js-yaml": "^4.1.0",
"ngx-clipboard": "^12.3.1", "ngx-clipboard": "^12.3.1",
"ngx-cookie": "^5.0.2", "ngx-cookie": "^5.0.2",
"ngx-markdown": "13.1.0", "ngx-markdown": "14.0.1",
"rxjs": "^7.4.0", "rxjs": "^7.4.0",
"stream-browserify": "^3.0.0", "stream-browserify": "^3.0.0",
"swagger-ui": "~4.10.3", "swagger-ui": "~4.10.3",
@ -55,20 +55,20 @@
"zone.js": "~0.11.4" "zone.js": "~0.11.4"
}, },
"devDependencies": { "devDependencies": {
"@angular-devkit/build-angular": "~13.3.9", "@angular-devkit/build-angular": "^14.1.0",
"@angular-eslint/builder": "13.2.1", "@angular-eslint/builder": "14.0.2",
"@angular-eslint/eslint-plugin": "13.2.1", "@angular-eslint/eslint-plugin": "14.0.2",
"@angular-eslint/eslint-plugin-template": "13.2.1", "@angular-eslint/eslint-plugin-template": "14.0.2",
"@angular-eslint/schematics": "13.2.1", "@angular-eslint/schematics": "14.0.2",
"@angular-eslint/template-parser": "13.2.1", "@angular-eslint/template-parser": "14.0.2",
"@angular/cli": "~13.3.4", "@angular/cli": "^14.1.0",
"@angular/compiler-cli": "~13.3.4", "@angular/compiler-cli": "^14.1.0",
"@types/express": "^4.17.12", "@types/express": "^4.17.12",
"@types/jasmine": "~3.10.1", "@types/jasmine": "~3.10.1",
"@types/node": "^16.11.6", "@types/node": "^16.11.6",
"@typescript-eslint/eslint-plugin": "5.17.0", "@typescript-eslint/eslint-plugin": "^5.29.0",
"@typescript-eslint/parser": "5.17.0", "@typescript-eslint/parser": "^5.29.0",
"eslint": "^8.12.0", "eslint": "^8.18.0",
"eslint-config-prettier": "^8.5.0", "eslint-config-prettier": "^8.5.0",
"eslint-plugin-prettier": "^4.0.0", "eslint-plugin-prettier": "^4.0.0",
"express": "^4.17.1", "express": "^4.17.1",
@ -88,6 +88,6 @@
"stylelint-config-prettier-scss": "^0.0.1", "stylelint-config-prettier-scss": "^0.0.1",
"stylelint-config-standard": "^25.0.0", "stylelint-config-standard": "^25.0.0",
"stylelint-config-standard-scss": "^4.0.0", "stylelint-config-standard-scss": "^4.0.0",
"typescript": "~4.5.4" "typescript": "~4.7.4"
} }
} }

View File

@ -6,7 +6,7 @@ import {
tick, tick,
} from '@angular/core/testing'; } from '@angular/core/testing';
import { NewScannerFormComponent } from './new-scanner-form.component'; import { NewScannerFormComponent } from './new-scanner-form.component';
import { FormBuilder } from '@angular/forms'; import { UntypedFormBuilder } from '@angular/forms';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { ClarityModule } from '@clr/angular'; import { ClarityModule } from '@clr/angular';
import { SharedTestingModule } from '../../../../../shared/shared.module'; import { SharedTestingModule } from '../../../../../shared/shared.module';
@ -41,7 +41,7 @@ describe('NewScannerFormComponent', () => {
], ],
declarations: [NewScannerFormComponent], declarations: [NewScannerFormComponent],
providers: [ providers: [
FormBuilder, UntypedFormBuilder,
TranslateService, TranslateService,
{ {
provide: ScannerService, provide: ScannerService,

View File

@ -5,7 +5,11 @@ import {
OnDestroy, OnDestroy,
ViewChild, ViewChild,
} from '@angular/core'; } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import {
UntypedFormBuilder,
UntypedFormGroup,
Validators,
} from '@angular/forms';
import { fromEvent } from 'rxjs'; import { fromEvent } from 'rxjs';
import { import {
debounceTime, debounceTime,
@ -24,7 +28,7 @@ import { ScannerService } from '../../../../../../../ng-swagger-gen/services/sca
}) })
export class NewScannerFormComponent implements AfterViewInit, OnDestroy { export class NewScannerFormComponent implements AfterViewInit, OnDestroy {
checkOnGoing: boolean = false; checkOnGoing: boolean = false;
newScannerForm: FormGroup = this.fb.group({ newScannerForm: UntypedFormGroup = this.fb.group({
name: this.fb.control('', [Validators.required]), name: this.fb.control('', [Validators.required]),
description: this.fb.control(''), description: this.fb.control(''),
url: this.fb.control('', [ url: this.fb.control('', [
@ -54,7 +58,7 @@ export class NewScannerFormComponent implements AfterViewInit, OnDestroy {
@ViewChild('name') scannerName: ElementRef; @ViewChild('name') scannerName: ElementRef;
@ViewChild('endpointUrl') scannerEndpointUrl: ElementRef; @ViewChild('endpointUrl') scannerEndpointUrl: ElementRef;
constructor( constructor(
private fb: FormBuilder, private fb: UntypedFormBuilder,
private scannerService: ScannerService private scannerService: ScannerService
) {} ) {}
ngAfterViewInit(): void { ngAfterViewInit(): void {

View File

@ -9,7 +9,7 @@ import { ClrLoadingState } from '@clr/angular';
import { NewScannerModalComponent } from './new-scanner-modal.component'; import { NewScannerModalComponent } from './new-scanner-modal.component';
import { MessageHandlerService } from '../../../../../shared/services/message-handler.service'; import { MessageHandlerService } from '../../../../../shared/services/message-handler.service';
import { NewScannerFormComponent } from '../new-scanner-form/new-scanner-form.component'; import { NewScannerFormComponent } from '../new-scanner-form/new-scanner-form.component';
import { FormBuilder } from '@angular/forms'; import { UntypedFormBuilder } from '@angular/forms';
import { of, Subscription } from 'rxjs'; import { of, Subscription } from 'rxjs';
import { delay } from 'rxjs/operators'; import { delay } from 'rxjs/operators';
import { SharedTestingModule } from '../../../../../shared/shared.module'; import { SharedTestingModule } from '../../../../../shared/shared.module';
@ -50,7 +50,7 @@ describe('NewScannerModalComponent', () => {
provide: ScannerService, provide: ScannerService,
useValue: fakedConfigScannerService, useValue: fakedConfigScannerService,
}, },
FormBuilder, UntypedFormBuilder,
// open auto detect // open auto detect
{ provide: ComponentFixtureAutoDetect, useValue: true }, { provide: ComponentFixtureAutoDetect, useValue: true },
], ],

View File

@ -24,11 +24,11 @@ import { Filter } from '../../../../../shared/services';
import { forkJoin, Observable, Subject, Subscription } from 'rxjs'; import { forkJoin, Observable, Subject, Subscription } from 'rxjs';
import { debounceTime, distinctUntilChanged, finalize } from 'rxjs/operators'; import { debounceTime, distinctUntilChanged, finalize } from 'rxjs/operators';
import { import {
FormArray, UntypedFormArray,
FormBuilder, UntypedFormBuilder,
FormGroup, UntypedFormGroup,
Validators, Validators,
FormControl, UntypedFormControl,
} from '@angular/forms'; } from '@angular/forms';
import { import {
clone, clone,
@ -86,7 +86,7 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
nameChecker: Subject<string> = new Subject<string>(); nameChecker: Subject<string> = new Subject<string>();
policyId: number; policyId: number;
confirmSub: Subscription; confirmSub: Subscription;
ruleForm: FormGroup; ruleForm: UntypedFormGroup;
copyUpdateForm: ReplicationPolicy; copyUpdateForm: ReplicationPolicy;
cronString: string; cronString: string;
supportedTriggers: string[]; supportedTriggers: string[];
@ -117,7 +117,7 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
selectedUnit: string = BandwidthUnit.KB; selectedUnit: string = BandwidthUnit.KB;
copySpeedUnit: string = BandwidthUnit.KB; copySpeedUnit: string = BandwidthUnit.KB;
constructor( constructor(
private fb: FormBuilder, private fb: UntypedFormBuilder,
private repService: ReplicationService, private repService: ReplicationService,
private endpointService: RegistryService, private endpointService: RegistryService,
private errorHandler: ErrorHandler, private errorHandler: ErrorHandler,
@ -301,8 +301,8 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
this.ruleForm = this.fb.group({ this.ruleForm = this.fb.group({
name: ['', Validators.required], name: ['', Validators.required],
description: '', description: '',
src_registry: new FormControl(), src_registry: new UntypedFormControl(),
dest_registry: new FormControl(), dest_registry: new UntypedFormControl(),
dest_namespace: '', dest_namespace: '',
dest_namespace_replace_count: -1, dest_namespace_replace_count: -1,
trigger: this.fb.group({ trigger: this.fb.group({
@ -391,8 +391,8 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
// end of reset the filter list. // end of reset the filter list.
} }
get filters(): FormArray { get filters(): UntypedFormArray {
return this.ruleForm.get('filters') as FormArray; return this.ruleForm.get('filters') as UntypedFormArray;
} }
setFilter(filters: Filter[]) { setFilter(filters: Filter[]) {
const filterFGs = filters.map(filter => { const filterFGs = filters.map(filter => {
@ -733,8 +733,8 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
} }
stickLabel(value, index) { stickLabel(value, index) {
value.select = !value.select; value.select = !value.select;
let filters = this.ruleForm.get('filters') as FormArray; let filters = this.ruleForm.get('filters') as UntypedFormArray;
let fromIndex = filters.controls[index] as FormGroup; let fromIndex = filters.controls[index] as UntypedFormGroup;
let labelValue = this.supportedFilterLabels.reduce( let labelValue = this.supportedFilterLabels.reduce(
(cumulatedSelectedArrs, currentValue) => { (cumulatedSelectedArrs, currentValue) => {
if (currentValue.select) { if (currentValue.select) {

View File

@ -1,7 +1,7 @@
import { Router, ActivatedRoute } from '@angular/router'; import { Router, ActivatedRoute } from '@angular/router';
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { OidcOnboardService } from './oidc-onboard.service'; import { OidcOnboardService } from './oidc-onboard.service';
import { FormControl } from '@angular/forms'; import { UntypedFormControl } from '@angular/forms';
import { CommonRoutes } from '../shared/entities/shared.const'; import { CommonRoutes } from '../shared/entities/shared.const';
import { errorHandler } from '../shared/units/shared.utils'; import { errorHandler } from '../shared/units/shared.utils';
@ -13,7 +13,7 @@ import { errorHandler } from '../shared/units/shared.utils';
export class OidcOnboardComponent implements OnInit { export class OidcOnboardComponent implements OnInit {
url: string; url: string;
errorMessage: string = ''; errorMessage: string = '';
oidcUsername = new FormControl(''); oidcUsername = new UntypedFormControl('');
errorOpen: boolean = false; errorOpen: boolean = false;
constructor( constructor(
private oidcOnboardService: OidcOnboardService, private oidcOnboardService: OidcOnboardService,

View File

@ -3,8 +3,8 @@ import { Subject } from 'rxjs';
import { debounceTime, finalize, switchMap } from 'rxjs/operators'; import { debounceTime, finalize, switchMap } from 'rxjs/operators';
import { import {
AbstractControl, AbstractControl,
FormBuilder, UntypedFormBuilder,
FormGroup, UntypedFormGroup,
Validators, Validators,
} from '@angular/forms'; } from '@angular/forms';
import { ErrorHandler } from '../../units/error-handler'; import { ErrorHandler } from '../../units/error-handler';
@ -19,7 +19,7 @@ import { Project } from 'ng-swagger-gen/models/project';
export class ImageNameInputComponent implements OnInit, OnDestroy { export class ImageNameInputComponent implements OnInit, OnDestroy {
selectedProjectList: Project[] = []; selectedProjectList: Project[] = [];
proNameChecker: Subject<string> = new Subject<string>(); proNameChecker: Subject<string> = new Subject<string>();
imageNameForm: FormGroup; imageNameForm: UntypedFormGroup;
notExist: boolean = false; notExist: boolean = false;
checkingName: boolean = false; checkingName: boolean = false;
public project: string; public project: string;
@ -27,7 +27,7 @@ export class ImageNameInputComponent implements OnInit, OnDestroy {
public tag: string; public tag: string;
constructor( constructor(
private fb: FormBuilder, private fb: UntypedFormBuilder,
private errorHandler: ErrorHandler, private errorHandler: ErrorHandler,
private proService: ProjectService private proService: ProjectService
) { ) {

View File

@ -13,7 +13,7 @@
"experimentalDecorators": true, "experimentalDecorators": true,
"moduleResolution": "node", "moduleResolution": "node",
"importHelpers": true, "importHelpers": true,
"target": "es2015", "target": "es2020",
"module": "es2020", "module": "es2020",
"lib": [ "lib": [
"es2018", "es2018",