build: bundle spec files for saucelabs legacy job (#44281)

Bundle spec files similar to how it is done within the Angular
Components repo. This should simplify the setup and also speed
up the Saucelab job as only a single spec bundle would need to be
downloaded, compared to having to load hundreds of files through the
Saucelabs tunnel.

Also makes a couple of tests more robust with the emulators/and accounts
for ES2015 test runner changes. The tests should be less reluctant to
such build process changes.

Note for reviewers: Some imports have been simplified here. This work
came from Joey's original WIP for this. It's unclear to me whether this
is still needed, but it sounded like this was necessary for the ESBuild
bundling to work. I have robusted the module resolution plugin though,
so I doubt it's still needed. At the same time though: Not worth
reverting/trying as these changes are nice to have anyway!

Co-Authored-By: Joey Perrott <josephperrott@gmail.com>
Co-Authored-By: Paul Gschwendtner <paulgschwendtner@gmail.com>

PR Close #44281
This commit is contained in:
Paul Gschwendtner
2021-11-26 15:24:04 +01:00
committed by Dylan Hunn
parent 6d16255ae0
commit 595d6479eb
24 changed files with 388 additions and 422 deletions
+6 -8
View File
@@ -614,9 +614,9 @@ jobs:
//packages/common/locales
# Needed for the ES5 downlevel reflector test in `packages/core/test/reflection`.
mkdir -p dist/all/@angular/core/test/reflection/
mkdir -p dist/legacy-test-out/core/test/reflection/
cp dist/bin/packages/core/test/reflection/es5_downleveled_inheritance_fixture.js \
dist/all/@angular/core/test/reflection/es5_downleveled_inheritance_fixture.js
dist/legacy-test-out/core/test/reflection/es5_downleveled_inheritance_fixture.js
# Locale files are needed for i18n tests running within Saucelabs. These are added
# directly as sources so that the TypeScript compilation of `/packages/tsconfig.json`
# can succeed. Note that the base locale and currencies files are checked-in, so
@@ -624,11 +624,10 @@ jobs:
mkdir -p packages/common/locales/extra
cp dist/bin/packages/common/locales/*.ts packages/common/locales
cp dist/bin/packages/common/locales/extra/*.ts packages/common/locales/extra
# add module umd tsc compile option so the test can work
# properly in the legacy browsers
- run: yarn tsc -p packages/tsconfig-legacy-saucelabs.json --module UMD
- run: yarn tsc -p modules --module UMD
# Build ZoneJS so that it can be loaded globally in the Karma tests.
- run: yarn bazel build //packages/zone.js:npm_package
# Build the bundle for all tests to run within Saucelabs
- run: node tools/legacy-saucelabs/build-saucelabs-test-bundle.mjs
- run:
# Waiting on ready ensures that we don't run tests too early without Saucelabs not being ready.
name: Waiting for Saucelabs tunnel to connect
@@ -636,8 +635,7 @@ jobs:
- run:
name: Running tests on Saucelabs.
command: |
browsers=$(node -e 'console.log(require("./browser-providers.conf").sauceAliases.CI_REQUIRED.join(","))')
yarn karma start ./karma-js.conf.js --single-run --browsers=${browsers}
KARMA_WEB_TEST_MODE=SL_REQUIRED yarn karma start ./karma-js.conf.js --single-run
- run:
name: Stop Saucelabs tunnel service
command: ./tools/saucelabs/sauce-service.sh stop
+1
View File
@@ -1196,6 +1196,7 @@ groups:
'tools/circular_dependency_test/**',
'tools/contributing-stats/**',
'tools/gulp-tasks/**',
'tools/legacy-saucelabs/**',
'tools/npm/**',
'tools/npm_integration_test/**',
'tools/rxjs/**',
+5 -53
View File
@@ -23,10 +23,6 @@ module.exports = function(config) {
},
files: [
// Sources and specs.
// Loaded through the System loader, in `test-main.js`.
{pattern: 'dist/all/@angular/**/*.js', included: false, watched: true},
// Serve AngularJS for `ngUpgrade` testing.
{pattern: 'node_modules/angular-1.5/angular?(.min).js', included: false, watched: false},
{pattern: 'node_modules/angular-mocks-1.5/angular-mocks.js', included: false, watched: false},
@@ -46,10 +42,9 @@ module.exports = function(config) {
'dist/bin/packages/zone.js/npm_package/bundles/zone-testing.umd.js',
'dist/bin/packages/zone.js/npm_package/bundles/task-tracking.umd.js',
// Including systemjs because it defines `__eval`, which produces correct stack traces.
'test-events.js',
'third_party/shims_for_internal_tests.js',
'node_modules/systemjs/dist/system.src.js',
// Static test assets.
{pattern: 'packages/platform-browser/test/static_assets/**/*', included: false},
{pattern: 'packages/platform-browser/test/browser/static_assets/**/*', included: false},
// Serve polyfills necessary for testing the `elements` package.
{
@@ -58,42 +53,9 @@ module.exports = function(config) {
watched: false
},
{pattern: 'node_modules/rxjs/**', included: false, watched: false, served: true},
'node_modules/reflect-metadata/Reflect.js',
'tools/build/file2modulename.js',
'test-main.js',
{pattern: 'dist/all/@angular/empty.*', included: false, watched: false},
{pattern: 'packages/platform-browser/test/static_assets/**', included: false, watched: false},
{
pattern: 'packages/platform-browser/test/browser/static_assets/**',
included: false,
watched: false,
},
],
exclude: [
'dist/all/@angular/_testing_init/**',
'dist/all/@angular/**/e2e_test/**',
'dist/all/@angular/**/*node_only_spec.js',
'dist/all/@angular/benchpress/**',
'dist/all/@angular/compiler-cli/**',
'dist/all/@angular/compiler-cli/src/ngtsc/**',
'dist/all/@angular/compiler-cli/test/compliance/**',
'dist/all/@angular/compiler-cli/test/ngtsc/**',
'dist/all/@angular/compiler/test/aot/**',
'dist/all/@angular/compiler/test/render3/**',
'dist/all/@angular/core/test/bundling/**',
'dist/all/@angular/core/test/render3/ivy/**',
'dist/all/@angular/core/test/render3/jit/**',
'dist/all/@angular/core/test/render3/perf/**',
'dist/all/@angular/elements/schematics/**',
'dist/all/@angular/examples/**/e2e_test/*',
'dist/all/@angular/language-service/**',
'dist/all/@angular/localize/**/test/**',
'dist/all/@angular/localize/schematics/**',
'dist/all/@angular/router/**/test/**',
'dist/all/@angular/platform-browser/testing/e2e_util.js',
'dist/examples/**/e2e_test/**',
'dist/legacy-test-bundle.spec.js',
],
customLaunchers: browserProvidersConf.customLaunchers,
@@ -149,15 +111,6 @@ module.exports = function(config) {
set: () => {},
});
if (process.env.CIRCLECI) {
conf.frameworks.unshift('parallel');
conf.plugins.unshift(require('karma-parallel'));
conf.parallelOptions = {
executors: 2,
shardStrategy: 'round-robin',
};
}
if (process.env['SAUCE_TUNNEL_IDENTIFIER']) {
console.log(`SAUCE_TUNNEL_IDENTIFIER: ${process.env.SAUCE_TUNNEL_IDENTIFIER}`);
@@ -171,8 +124,7 @@ module.exports = function(config) {
// the test logs from upstream and tries re-uploading them with the Karma enhanced details.
// This slows-down tests/browser restarting and can decrease stability.
// https://github.com/karma-runner/karma-sauce-launcher/blob/59b0c5c877448e064ad56449cd906743721c6b62/src/launcher/launcher.ts#L72-L79.
require('saucelabs').default.prototype.downloadJobAsset =
() => Promise.resolve('<FAKE-LOGS>');
require('saucelabs').default.prototype.downloadJobAsset = () => Promise.resolve('<FAKE-LOGS>');
}
// For SauceLabs jobs, we set up a domain which resolves to the machine which launched
@@ -8,7 +8,7 @@
import {CompilerConfig, DirectiveResolver} from '@angular/compiler';
import {Component, ComponentResolver, Directive, ViewContainerRef,} from '@angular/core';
import {ViewMetadata} from '@angular/core/src/metadata/view';
import {ViewMetadata} from '@angular/core/view';
import {PromiseWrapper} from '@angular/facade/src/async';
import {print, Type} from '@angular/facade/src/lang';
import {bootstrap} from '@angular/platform-browser';
+1 -1
View File
@@ -176,9 +176,9 @@
"gulp-conventional-changelog": "^2.0.35",
"husky": "7.0.4",
"inquirer": "^8.0.0",
"karma-parallel": "^0.3.1",
"karma-sauce-launcher": "^4.3.6",
"madge": "^5.0.0",
"multimatch": "^6.0.0",
"sauce-connect": "https://saucelabs.com/downloads/sc-4.7.1-linux.tar.gz",
"semver": "^7.3.5",
"ts-node": "^10.0.0",
@@ -7,8 +7,7 @@
*/
import {CommonModule} from '@angular/common';
import {ChangeDetectorRef, Component, Directive, TemplateRef, ViewChild, ViewContainerRef} from '@angular/core';
import {Input} from '@angular/core/src/metadata';
import {ChangeDetectorRef, Component, Directive, Input, TemplateRef, ViewChild, ViewContainerRef} from '@angular/core';
import {TestBed} from '@angular/core/testing';
import {By} from '@angular/platform-browser';
import {expect} from '@angular/platform-browser/testing/src/matchers';
@@ -322,7 +321,7 @@ describe('projection', () => {
@Component(
{selector: 'comp', template: `<ng-template><ng-content></ng-content></ng-template>`})
class Comp {
@ViewChild(TemplateRef, {static: true}) template !: TemplateRef<any>;
@ViewChild(TemplateRef, {static: true}) template!: TemplateRef<any>;
}
@Directive({selector: '[trigger]'})
@@ -7,8 +7,7 @@
*/
import {CommonModule} from '@angular/common';
import {Component, Directive, ElementRef, EventEmitter, NgModule, Output, TemplateRef, ViewChild, ViewContainerRef} from '@angular/core';
import {Input} from '@angular/core/src/metadata';
import {Component, Directive, ElementRef, EventEmitter, Input, NgModule, Output, TemplateRef, ViewChild, ViewContainerRef} from '@angular/core';
import {TestBed} from '@angular/core/testing';
import {By} from '@angular/platform-browser';
@@ -6,10 +6,8 @@
* found in the LICENSE file at https://angular.io/license
*/
import {CommonModule} from '@angular/common';
import {Component, Directive, HostBinding, InjectionToken, ViewChild} from '@angular/core';
import {ChangeDetectionStrategy} from '@angular/core/src/change_detection';
import {ChangeDetectionStrategy, Component, Directive, HostBinding, InjectionToken, Input, Output, ViewChild, ViewEncapsulation} from '@angular/core';
import {EventEmitter} from '@angular/core/src/event_emitter';
import {Input, Output, ViewEncapsulation} from '@angular/core/src/metadata';
import {isLView} from '@angular/core/src/render3/interfaces/type_checks';
import {CONTEXT} from '@angular/core/src/render3/interfaces/view';
import {ComponentFixture, TestBed} from '@angular/core/testing';
+2 -1
View File
@@ -127,7 +127,8 @@ describe('text instructions', () => {
fixture.detectChanges();
const div = fixture.nativeElement.querySelector('div');
expect(div.innerHTML).toBe('function foo() { }');
expect(div.innerHTML).toBe(fixture.componentInstance.test.toString());
expect(div.innerHTML).toContain('foo');
});
it('should stringify an object using its toString method', () => {
@@ -8,8 +8,7 @@
import {CommonModule, DOCUMENT} from '@angular/common';
import {computeMsgId} from '@angular/compiler';
import {Compiler, Component, ComponentFactoryResolver, Directive, DoCheck, ElementRef, EmbeddedViewRef, ErrorHandler, InjectionToken, Injector, NgModule, NgModuleRef, NO_ERRORS_SCHEMA, OnDestroy, OnInit, Pipe, PipeTransform, QueryList, RendererFactory2, RendererType2, Sanitizer, TemplateRef, ViewChild, ViewChildren, ViewContainerRef, ɵsetDocument} from '@angular/core';
import {Input} from '@angular/core/src/metadata';
import {Compiler, Component, ComponentFactoryResolver, Directive, DoCheck, ElementRef, EmbeddedViewRef, ErrorHandler, InjectionToken, Injector, Input, NgModule, NgModuleRef, NO_ERRORS_SCHEMA, OnDestroy, OnInit, Pipe, PipeTransform, QueryList, RendererFactory2, RendererType2, Sanitizer, TemplateRef, ViewChild, ViewChildren, ViewContainerRef, ɵsetDocument} from '@angular/core';
import {ngDevModeResetPerfCounters} from '@angular/core/src/util/ng_dev_mode';
import {ComponentFixture, TestBed, TestComponentRenderer} from '@angular/core/testing';
import {clearTranslations, loadTranslations} from '@angular/localize';
@@ -249,7 +249,8 @@ describe('animation integration tests using web animations', function() {
overflow:hidden;
}
.list .inner {
line-height:50px;
box-sizing: border-box;
height: 50px;
}
`],
template: `
+1 -2
View File
@@ -8,8 +8,7 @@
import {CommonModule, NgIfContext, ɵgetDOM as getDOM} from '@angular/common';
import {Component, DebugElement, DebugNode, Directive, ElementRef, EmbeddedViewRef, EventEmitter, HostBinding, Injectable, Input, NO_ERRORS_SCHEMA, OnInit, Output, Renderer2, TemplateRef, ViewChild, ViewContainerRef} from '@angular/core';
import {NgZone} from '@angular/core/src/zone';
import {Component, DebugElement, DebugNode, Directive, ElementRef, EmbeddedViewRef, EventEmitter, HostBinding, Injectable, Input, NgZone, NO_ERRORS_SCHEMA, OnInit, Output, Renderer2, TemplateRef, ViewChild, ViewContainerRef} from '@angular/core';
import {ComponentFixture, TestBed, waitForAsync} from '@angular/core/testing';
import {By} from '@angular/platform-browser/src/dom/debug/by';
import {createMouseEvent, hasClass} from '@angular/platform-browser/testing/src/browser_util';
@@ -6,8 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {AfterContentChecked, AfterContentInit, AfterViewChecked, AfterViewInit, DoCheck, OnChanges, OnInit} from '@angular/core';
import {Component, Directive} from '@angular/core/src/metadata';
import {AfterContentChecked, AfterContentInit, AfterViewChecked, AfterViewInit, Component, Directive, DoCheck, OnChanges, OnInit} from '@angular/core';
import {inject, TestBed} from '@angular/core/testing';
import {Log} from '@angular/core/testing/src/testing_internal';
@@ -7,7 +7,7 @@
*/
import {CommonModule, DOCUMENT, ɵgetDOM as getDOM} from '@angular/common';
import {Compiler, ComponentFactory, ComponentRef, EventEmitter, Host, Inject, Injectable, InjectionToken, Injector, NgModule, NgModuleRef, NO_ERRORS_SCHEMA, OnDestroy, SkipSelf, ViewChild, ViewRef} from '@angular/core';
import {Attribute, Compiler, Component, ComponentFactory, ComponentRef, ContentChildren, Directive, EventEmitter, Host, HostBinding, HostListener, Inject, Injectable, InjectionToken, Injector, Input, NgModule, NgModuleRef, NO_ERRORS_SCHEMA, OnDestroy, Output, Pipe, SkipSelf, ViewChild, ViewRef} from '@angular/core';
import {ChangeDetectionStrategy, ChangeDetectorRef, PipeTransform} from '@angular/core/src/change_detection/change_detection';
import {ComponentFactoryResolver} from '@angular/core/src/linker/component_factory_resolver';
import {ElementRef} from '@angular/core/src/linker/element_ref';
@@ -15,7 +15,6 @@ import {QueryList} from '@angular/core/src/linker/query_list';
import {TemplateRef} from '@angular/core/src/linker/template_ref';
import {ViewContainerRef} from '@angular/core/src/linker/view_container_ref';
import {EmbeddedViewRef} from '@angular/core/src/linker/view_ref';
import {Attribute, Component, ContentChildren, Directive, HostBinding, HostListener, Input, Output, Pipe} from '@angular/core/src/metadata';
import {fakeAsync, getTestBed, TestBed, tick, waitForAsync} from '@angular/core/testing';
import {createMouseEvent, dispatchEvent, el, isCommentNode} from '@angular/platform-browser/testing/src/browser_util';
import {expect} from '@angular/platform-browser/testing/src/matchers';
+10 -2
View File
@@ -29,6 +29,13 @@ describe('i18n debug', () => {
});
it('should print Attribute opCode', () => {
// The `sanitizeFn` is written as actual function, compared to it being an arrow function.
// This is done to make this test less reluctant to build process changes where e.g. an
// arrow function might be transformed to a function declaration in ES5.
const sanitizeFn = function(v: any) {
return v;
};
expect(i18nUpdateOpCodesToString([
0b01, 8,
'pre ', -4,
@@ -39,11 +46,12 @@ describe('i18n debug', () => {
'pre ', -4,
' in ', -3,
' post', 1 << I18nUpdateOpCode.SHIFT_REF | I18nUpdateOpCode.Attr,
'title', (v: any) => v,
'title', sanitizeFn,
] as unknown as I18nUpdateOpCodes))
.toEqual([
'if (mask & 0b1) { (lView[1] as Element).setAttribute(\'title\', `pre ${lView[i-4]} in ${lView[i-3]} post`); }',
'if (mask & 0b10) { (lView[1] as Element).setAttribute(\'title\', (function (v) { return v; })(`pre ${lView[i-4]} in ${lView[i-3]} post`)); }'
`if (mask & 0b10) { (lView[1] as Element).setAttribute('title', (${
sanitizeFn.toString()})(\`pre $\{lView[i-4]} in $\{lView[i-3]} post\`)); }`
]);
});
+1 -5
View File
@@ -7,14 +7,10 @@
*/
import 'reflect-metadata';
import {ElementRef, QueryList} from '@angular/core';
import {Component, ContentChild, ContentChildren, Directive, ElementRef, HostBinding, HostListener, Input, NgModule, Pipe, QueryList, ViewChild, ViewChildren, ɵNgModuleDef as NgModuleDef} from '@angular/core';
import {Injectable} from '@angular/core/src/di/injectable';
import {setCurrentInjector, ɵɵinject} from '@angular/core/src/di/injector_compatibility';
import {ɵɵdefineInjectable, ɵɵInjectorDef} from '@angular/core/src/di/interface/defs';
import {ContentChild, ContentChildren, ViewChild, ViewChildren} from '@angular/core/src/metadata/di';
import {Component, Directive, HostBinding, HostListener, Input, Pipe} from '@angular/core/src/metadata/directives';
import {NgModule} from '@angular/core/src/metadata/ng_module';
import {NgModuleDef} from '@angular/core/src/metadata/ng_module_def';
import {FactoryFn} from '@angular/core/src/render3/definition_factory';
import {ComponentDef, PipeDef} from '@angular/core/src/render3/interfaces/definition';
@@ -7,7 +7,6 @@
*/
import {Compiler, Component, Injector, NgModule, NgModuleFactory, NgModuleRef, Type} from '@angular/core';
import {resolveComponentResources} from '@angular/core/src/metadata/resource_loading';
import {fakeAsync, inject, TestBed, tick} from '@angular/core/testing';
import {PreloadAllModules, PreloadingStrategy, RouterPreloader} from '@angular/router';
import {BehaviorSubject, Observable, of, throwError} from 'rxjs';
+28 -4
View File
@@ -1,13 +1,37 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"target": "ES5",
"module": "commonjs",
"outDir": "../dist/legacy-test-out",
"target": "ES2015",
"module": "ES2020",
"importHelpers": true,
// The project uses Bazel for TypeScript compilation. Unlike with Bazel, we build all
// sources as part of a single TypeScript compilation. This results in `@internal`
// declarations not being omitted between the logical as defined per the Bazel targets.
// This can cause issues where the `override` keyword is needed for the legacy TS
// compilation, but not within Bazel where the overridden member has `@internal`.
"noImplicitOverride": false
}
"noImplicitOverride": false,
// We run the decorator downlevel transform when compiling the sources and tests.
// Given that is the case, we do not need additional `design` metadata being emitted.
// The default TS decorator metadata would also not work with ES2015 JIT.
// https://github.com/angular/angular/issues/30106.
"emitDecoratorMetadata": false
},
"exclude": [
// Exclusions from the parent `tsconfig` need to be merged manually here.
"bazel",
"common/locales",
"compiler-cli/integrationtest",
"compiler-cli/test/compliance",
"core/schematics",
"elements/schematics",
"examples/**",
"http/**",
"platform-server/integrationtest",
"router/test/aot_ngsummary_test",
// Additional exclusion since tests for the language-service never run within the
// Saucelabs job and the package is not compatible with ESM TS compilation anyway.
"language-service/**",
]
}
@@ -573,7 +573,9 @@ withEachNg1Version(() => {
angular.module_('ng1', [lazyModuleName])
.directive(
'ng2', downgradeComponent({component: Ng2AComponent, propagateDigest}))
.run(($rootScope: angular.IRootScopeService) => $rootScope.value = 0);
.run([
'$rootScope', ($rootScope: angular.IRootScopeService) => $rootScope.value = 0
]);
const element = html('<div><ng2 [value]="value" ng-if="loadNg2"></ng2></div>');
const $injector = angular.bootstrap(element, [ng1Module.name]);
@@ -762,10 +764,13 @@ withEachNg1Version(() => {
const ng1Module =
angular.module_('ng1', [lazyModuleName])
.directive('ng2', downgradeComponent({component: Ng2Component, propagateDigest}))
.run(($rootScope: angular.IRootScopeService) => {
$rootScope.attrVal = 'bar';
$rootScope.propVal = 'bar';
});
.run([
'$rootScope',
($rootScope: angular.IRootScopeService) => {
$rootScope.attrVal = 'bar';
$rootScope.propVal = 'bar';
}
]);
const element = html('<ng2 attr-input="{{ attrVal }}" [prop-input]="propVal"></ng2>');
const $injector = angular.bootstrap(element, [ng1Module.name]);
-213
View File
@@ -1,213 +0,0 @@
/**
* @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
*/
// Tun on full stack traces in errors to help debugging
Error.stackTraceLimit = Infinity;
jasmine.DEFAULT_TIMEOUT_INTERVAL = 15000;
// Cancel Karma's synchronous start,
// we will call `__karma__.start()` later, once all the specs are loaded.
__karma__.loaded = function() {};
window.isNode = false;
window.isBrowser = true;
System.config({
baseURL: '/base',
defaultJSExtensions: true,
map: {
'benchpress/*': 'dist/js/dev/es5/benchpress/*.js',
'@angular': 'dist/all/@angular',
'domino': 'dist/all/@angular/empty.js',
'url': 'dist/all/@angular/empty.js',
'xhr2': 'dist/all/@angular/empty.js',
'@angular/platform-server/src/domino_adapter': 'dist/all/@angular/empty.js',
'angular-in-memory-web-api': 'dist/all/@angular/misc/angular-in-memory-web-api',
'rxjs': 'node_modules/rxjs',
},
packages: {
'@angular/core/src/render3': {main: 'index.js', defaultExtension: 'js'},
'@angular/core/testing': {main: 'index.js', defaultExtension: 'js'},
'@angular/core': {main: 'index.js', defaultExtension: 'js'},
'@angular/animations/browser/testing': {main: 'index.js', defaultExtension: 'js'},
'@angular/animations/browser': {main: 'index.js', defaultExtension: 'js'},
'@angular/animations/testing': {main: 'index.js', defaultExtension: 'js'},
'@angular/animations': {main: 'index.js', defaultExtension: 'js'},
'@angular/compiler/testing': {main: 'index.js', defaultExtension: 'js'},
'@angular/compiler': {main: 'index.js', defaultExtension: 'js'},
'@angular/common/testing': {main: 'index.js', defaultExtension: 'js'},
'@angular/common/http/testing': {main: 'index.js', defaultExtension: 'js'},
'@angular/common/http': {main: 'index.js', defaultExtension: 'js'},
'@angular/common': {main: 'index.js', defaultExtension: 'js'},
'@angular/forms': {main: 'index.js', defaultExtension: 'js'},
'@angular/misc/angular-in-memory-web-api': {main: 'index.js', defaultExtension: 'js'},
// remove after all tests imports are fixed
'@angular/facade': {main: 'index.js', defaultExtension: 'js'},
'@angular/router/testing': {main: 'index.js', defaultExtension: 'js'},
'@angular/router': {main: 'index.js', defaultExtension: 'js'},
'@angular/localize/src/utils': {main: 'index.js', defaultExtension: 'js'},
'@angular/localize/src/localize': {main: 'index.js', defaultExtension: 'js'},
'@angular/localize/init': {main: 'index.js', defaultExtension: 'js'},
'@angular/localize': {main: 'index.js', defaultExtension: 'js'},
'@angular/upgrade/static/testing': {main: 'index.js', defaultExtension: 'js'},
'@angular/upgrade/static': {main: 'index.js', defaultExtension: 'js'},
'@angular/upgrade': {main: 'index.js', defaultExtension: 'js'},
'@angular/platform-browser/animations/testing': {main: 'index.js', defaultExtension: 'js'},
'@angular/platform-browser/animations': {main: 'index.js', defaultExtension: 'js'},
'@angular/platform-browser/testing': {main: 'index.js', defaultExtension: 'js'},
'@angular/platform-browser': {main: 'index.js', defaultExtension: 'js'},
'@angular/platform-browser-dynamic/testing': {main: 'index.js', defaultExtension: 'js'},
'@angular/platform-browser-dynamic': {main: 'index.js', defaultExtension: 'js'},
'@angular/platform-server/init': {main: 'index.js', defaultExtension: 'js'},
'@angular/platform-server/testing': {main: 'index.js', defaultExtension: 'js'},
'@angular/platform-server': {main: 'index.js', defaultExtension: 'js'},
'@angular/private/testing': {main: 'index.js', defaultExtension: 'js'},
'@angular/elements': {main: 'index.js', defaultExtension: 'js'},
'rxjs/ajax': {main: 'index.js', defaultExtension: 'js'},
'rxjs/operators': {main: 'index.js', defaultExtension: 'js'},
'rxjs/testing': {main: 'index.js', defaultExtension: 'js'},
'rxjs/websocket': {main: 'index.js', defaultExtension: 'js'},
'rxjs': {main: 'index.js', defaultExtension: 'js'},
}
});
// Load browser-specific CustomElement polyfills, set up the test injector, import all the specs,
// execute their `main()` method and kick off Karma (Jasmine).
Promise
.resolve()
// Load browser-specific polyfills for custom elements.
.then(function() {
return loadCustomElementsPolyfills();
})
// Load necessary testing packages.
.then(function() {
return Promise.all([
System.import('@angular/core/testing'),
System.import('@angular/platform-browser-dynamic/testing'),
System.import('@angular/platform-browser/animations')
]);
})
// Set up the test injector.
.then(function(mods) {
var coreTesting = mods[0];
var pbdTesting = mods[1];
var pbAnimations = mods[2];
coreTesting.TestBed.initTestEnvironment(
[pbdTesting.BrowserDynamicTestingModule, pbAnimations.NoopAnimationsModule],
pbdTesting.platformBrowserDynamicTesting());
})
// Import all the specs and execute their `main()` method.
.then(function() {
return Promise.all(Object
.keys(window.__karma__.files) // All files served by Karma.
.filter(onlySpecFiles)
.map(window.file2moduleName) // Normalize paths to module names.
.map(function(path) {
return System.import(path).then(function(module) {
if (module.hasOwnProperty('main')) {
throw new Error('main() in specs are no longer supported');
}
});
}));
})
// Kick off karma (Jasmine).
.then(
function() {
__karma__.start();
},
function(error) {
console.error(error);
});
function loadCustomElementsPolyfills() {
// The custom elements polyfill will patch properties and methods on `(HTML)Element` and `Node`
// (among others), including `(HTML)Element#innerHTML` and `Node#removeChild()`:
// https://github.com/webcomponents/custom-elements/blob/4f7072c0dbda4beb505d16967acfffd33337b325/src/Patch/Element.js#L28-L73
// https://github.com/webcomponents/custom-elements/blob/4f7072c0dbda4beb505d16967acfffd33337b325/src/Patch/Node.js#L105-L120
// The patched `innerHTML` setter and `removeChild()` method will try to traverse the DOM (via
// `nextSibling` and `parentNode` respectively), which leads to infinite loops when testing
// `HtmlSanitizer` with cloberred elements on browsers that do not support the `<template>`
// element:
// https://github.com/angular/angular/blob/213baa37b0b71e72d00ad7b606ebfc2ade06b934/packages/platform-browser/src/security/html_sanitizer.ts#L29-L38
// To avoid that, we "unpatch" these properties/methods and apply the patch only for the relevant
// `@angular/elements` tests.
var patchConfig = {'innerHTML': ['Element', 'HTMLElement'], 'removeChild': ['Node']};
var patchTargets = {};
var originalDescriptors = {};
if (!window.customElements) {
Object.keys(patchConfig).forEach(function(prop) {
patchConfig[prop]
.map(function(name) {
return window[name].prototype;
})
.some(function(candidatePatchTarget) {
var candidateOriginalDescriptor =
Object.getOwnPropertyDescriptor(candidatePatchTarget, prop);
if (candidateOriginalDescriptor) {
patchTargets[prop] = candidatePatchTarget;
originalDescriptors[prop] = candidateOriginalDescriptor;
return true;
}
});
});
}
var polyfillPath = !window.customElements ?
// Load custom elements polyfill.
'node_modules/@webcomponents/custom-elements/custom-elements.min.js' :
// Allow ES5 functions as custom element constructors.
'node_modules/@webcomponents/custom-elements/src/native-shim.js';
return System.import(polyfillPath).then(function() {
// `packages/compiler/test/schema/schema_extractor.ts` relies on
// `HTMLElement.name`, but custom element polyfills will replace
// `HTMLElement` with an anonymous function.
Object.defineProperty(HTMLElement, 'name', {value: 'HTMLElement'});
// Create helper functions on `window` for patching/restoring
// properties/methods.
Object.keys(patchConfig).forEach(function(prop) {
var patchMethod = '$$patch_' + prop;
var restoreMethod = '$$restore_' + prop;
if (!patchTargets[prop]) {
// No patching detected. Create no-op functions.
window[patchMethod] = window[restoreMethod] = function() {};
} else {
var patchTarget = patchTargets[prop];
var originalDescriptor = originalDescriptors[prop];
var patchedDescriptor = Object.getOwnPropertyDescriptor(patchTarget, prop);
window[patchMethod] = function() {
Object.defineProperty(patchTarget, prop, patchedDescriptor);
};
window[restoreMethod] = function() {
Object.defineProperty(patchTarget, prop, originalDescriptor);
};
// Restore `prop`. The patch will be manually applied only during the
// `@angular/elements` tests that need it.
window[restoreMethod]();
}
});
});
}
function onlySpecFiles(path) {
return /_spec\.js$/.test(path);
}
@@ -0,0 +1,267 @@
#!/usr/bin/env node
import multimatch from 'multimatch';
import esbuild from 'esbuild';
import fs from 'fs';
import glob from 'glob';
import {dirname, join, isAbsolute, relative} from 'path';
import url from 'url';
import ts from 'typescript';
const containingDir = dirname(url.fileURLToPath(import.meta.url));
const projectDir = join(containingDir, '../../');
const distDir = join(projectDir, 'dist/');
const packagesDir = join(projectDir, 'packages/');
const legacyTsconfigPath = join(packagesDir, 'tsconfig-legacy-saucelabs.json');
const legacyOutputDir = join(distDir, 'legacy-test-out');
const outFile = join(distDir, 'legacy-test-bundle.spec.js');
const decoratorDownlevelOutFile = join(distDir, 'legacy-decorator-downlevel-bundle.mjs');
/**
* This script builds the whole library in `angular/angular` together with its
* spec files into a single IIFE bundle.
*
* The bundle can then be used in the legacy Saucelabs or Browserstack tests. Bundling
* helps with avoiding unnecessary complexity with maintaining module resolution at
* runtime through e.g. SystemJS, and it increases test stability by serving significantly
* less files through the remote browser service tunnels.
*/
async function main() {
await transpileDecoratorDownlevelTransform();
await compileProjectWithTsc();
const specEntryPointFile = await createEntryPointSpecFile();
const esbuildResolvePlugin = await createResolveEsbuildPlugin();
const result = await esbuild.build({
bundle: true,
keepNames: true,
treeShaking: false,
sourceRoot: projectDir,
platform: 'browser',
target: 'es2015',
format: 'iife',
outfile: outFile,
sourcemap: true,
plugins: [esbuildResolvePlugin],
stdin: {contents: specEntryPointFile, resolveDir: projectDir},
});
if (result.errors.length) {
throw Error('Could not build legacy test bundle. See errors above.');
}
}
/**
* Finds spec files that should be built, bundled and tested as
* part of the legacy Saucelabs test job.
*/
async function findSpecFiles() {
const baseTestFiles = glob.sync('**/*_spec.js', {absolute: true, cwd: legacyOutputDir});
return multimatch(
baseTestFiles,
[
'**/*',
`!${legacyOutputDir}/_testing_init/**`,
`!${legacyOutputDir}/**/e2e_test/**`,
`!${legacyOutputDir}/**/*node_only_spec.js`,
`!${legacyOutputDir}/benchpress/**`,
`!${legacyOutputDir}/compiler-cli/**`,
`!${legacyOutputDir}/compiler-cli/src/ngtsc/**`,
`!${legacyOutputDir}/compiler-cli/test/compliance/**`,
`!${legacyOutputDir}/compiler-cli/test/ngtsc/**`,
`!${legacyOutputDir}/compiler/test/aot/**`,
`!${legacyOutputDir}/compiler/test/render3/**`,
`!${legacyOutputDir}/core/test/bundling/**`,
`!${legacyOutputDir}/core/schematics/test/**`,
`!${legacyOutputDir}/core/test/render3/ivy/**`,
`!${legacyOutputDir}/core/test/render3/jit/**`,
`!${legacyOutputDir}/core/test/render3/perf/**`,
`!${legacyOutputDir}/elements/schematics/**`,
`!${legacyOutputDir}/examples/**/e2e_test/*`,
`!${legacyOutputDir}/language-service/**`,
`!${legacyOutputDir}/localize/**/test/**`,
`!${legacyOutputDir}/localize/schematics/**`,
`!${legacyOutputDir}/router/**/test/**`,
`!${legacyOutputDir}/zone.js/**/test/**`,
`!${legacyOutputDir}/platform-browser/testing/e2e_util.js`,
]
);
}
/**
* Queries for all spec files in the built output and creates a single
* ESM entry-point file which imports all the spec files.
*
* This spec file can then be used as entry-point for ESBuild in order
* to bundle all specs in an IIFE file.
*/
async function createEntryPointSpecFile() {
const testFiles = await findSpecFiles();
let specEntryPointFile = `import './tools/testing/init_browser_spec.ts';`;
let i = 0;
const testNamespaces = [];
for (const file of testFiles) {
const relativePath = relative(projectDir, file);
const specifier = `./${relativePath.replace(/\\/g, '/')}`;
const testNamespace = `__${i++}`;
testNamespaces.push(testNamespace);
specEntryPointFile += `import * as ${testNamespace} from '${specifier}';\n`;
}
for (const namespaceId of testNamespaces) {
// We generate a side-effect invocation that references the test import. This
// is necessary to trick `ESBuild` in preserving the imports. Unfortunately the
// test files would be dead-code eliminated otherwise because the specs are part
// of folders with `package.json` files setting the `"sideEffects: false"` field.
specEntryPointFile += `new Function('x', 'return x')(${namespaceId});\n`;
}
return specEntryPointFile;
}
/**
* Creates an ESBuild plugin which maps `@angular/<..>` module names to their
* locally-built output (for the packages which are built as part of this repo).
*/
async function createResolveEsbuildPlugin() {
const resolveMappings = new Map([
[/@angular\//, `${legacyOutputDir}/`],
[/^angular-in-memory-web-api$/, join(legacyOutputDir, 'misc/angular-in-memory-web-api')],
]);
return {
name: 'ng-resolve-esbuild', setup: (build) => {
build.onResolve({filter: /(@angular\/|angular-in-memory-web-api)/}, async (args) => {
const matchedPattern = Array.from(resolveMappings.keys()).find(
pattern => args.path.match(pattern));
if (matchedPattern === undefined) {
return undefined;
}
let resolvedPath = args.path.replace(matchedPattern, resolveMappings.get(matchedPattern));
let stats = await statGraceful(resolvedPath);
// If the resolved path points to a directory, resolve the contained `index.js` file
if (stats && stats.isDirectory()) {
resolvedPath = join(resolvedPath, 'index.js');
stats = await statGraceful(resolvedPath);
}
// If the resolved path does not exist, check with an explicit JS extension.
else if (stats === null) {
resolvedPath += '.js';
stats = await statGraceful(resolvedPath);
}
return stats !== null ? {path: resolvedPath} : undefined;
});
}
}
}
/**
* Creates an ESM bundle for the downlevel decorator transform. The decorator
* downlevel transform can then be used later when we compile the sources and tests.
*
* Note: This layer of indirection needs to exist since we cannot load TS directly
* from an ES module. Running ESBuild first allows us to also transpile the TS fast.
*/
async function transpileDecoratorDownlevelTransform() {
const result = await esbuild.build({
bundle: true,
sourceRoot: projectDir,
platform: 'node',
target: 'es2020',
format: 'esm',
outfile: decoratorDownlevelOutFile,
external: ['typescript'],
sourcemap: true,
entryPoints: [join(containingDir, 'downlevel_decorator_transform.ts')],
});
if (result.errors.length) {
throw Error('Could not build decorator downlevel bundle. See errors above.');
}
}
/**
* Compiles the project using the TypeScript compiler in order to produce
* JS output of the packages and tests.
*/
async function compileProjectWithTsc() {
const {legacyCompilationDownlevelDecoratorTransform} = await import(
url.pathToFileURL(decoratorDownlevelOutFile));
const config = parseTsconfigFile(legacyTsconfigPath, dirname(legacyTsconfigPath));
const program = ts.createProgram(config.fileNames, config.options);
const result = program.emit(undefined, undefined, undefined, undefined, {
// We need to downlevel constructor parameters to make ES2015 JIT work. More details
// here: https://github.com/angular/angular/pull/37382.
before: [legacyCompilationDownlevelDecoratorTransform(program)],
});
const diagnostics = [
...result.diagnostics,
...program.getSyntacticDiagnostics(),
...program.getSemanticDiagnostics()
];
if (diagnostics.length) {
console.error(ts.formatDiagnosticsWithColorAndContext(diagnostics, {
getCanonicalFileName: fileName => fileName,
getCurrentDirectory: () => program.getCurrentDirectory(),
getNewLine: () => '\n',
}));
throw new Error('Compilation failed. See errors above.');
}
console.info('Built packages and specs using TypeScript.');
console.info('The constructor parameters have been downleveled.');
}
function parseTsconfigFile(tsconfigPath, basePath) {
const {config} = ts.readConfigFile(tsconfigPath, ts.sys.readFile);
const parseConfigHost = {
useCaseSensitiveFileNames: ts.sys.useCaseSensitiveFileNames,
fileExists: ts.sys.fileExists,
readDirectory: ts.sys.readDirectory,
readFile: ts.sys.readFile,
};
// Throw if incorrect arguments are passed to this function. Passing relative base paths
// results in root directories not being resolved and in later type checking runtime errors.
// More details can be found here: https://github.com/microsoft/TypeScript/issues/37731.
if (!isAbsolute(basePath)) {
throw Error('Unexpected relative base path has been specified.');
}
return ts.parseJsonConfigFileContent(config, parseConfigHost, basePath, {});
}
/**
* Retrieves the `fs.Stats` results for the given path gracefully.
* If the file does not exist, returns `null`.
*/
async function statGraceful(path) {
try {
return await fs.promises.stat(path);
} catch {
return null;
}
}
main().catch(e => {
console.error(e);
process.exitCode = 1;
});
@@ -0,0 +1,27 @@
/**
* @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 ts from 'typescript';
import {TypeScriptReflectionHost} from '../../packages/compiler-cli/src/ngtsc/reflection/src/typescript';
import {getDownlevelDecoratorsTransform} from '../../packages/compiler-cli/src/transformers/downlevel_decorators_transform/index';
/**
* Transform for downleveling Angular decorators and Angular-decorated class
* constructor parameters for dependency injection.
* See https://github.com/angular/angular-cli/pull/14473 for more details.
*/
export function legacyCompilationDownlevelDecoratorTransform(program: ts.Program):
ts.TransformerFactory<ts.SourceFile> {
const typeChecker = program.getTypeChecker();
const reflectionHost = new TypeScriptReflectionHost(typeChecker);
// Note: `isCore` is set to `true` since we also process the core package.
return getDownlevelDecoratorsTransform(
typeChecker, reflectionHost, [], /* isCore */ true,
/* enableClosureCompiler */ false, /* skipClassDecorators */ true);
}
+10
View File
@@ -0,0 +1,10 @@
{
"compilerOptions": {
"target": "ES2020",
"module": "ES2020",
"baseUrl": ".",
"esModuleInterop": true,
"moduleResolution": "Node",
"rootDirs": ["./", "../../"]
}
}
+9 -111
View File
@@ -2603,11 +2603,6 @@ abbrev@1:
resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==
abbrev@1.0.x:
version "1.0.9"
resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135"
integrity sha1-kbR5JYinc4wl813W9jdSovh3YTU=
abort-controller@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392"
@@ -2727,11 +2722,6 @@ ajv@^8.0.0:
require-from-string "^2.0.2"
uri-js "^4.2.2"
amdefine@>=0.0.4:
version "1.0.1"
resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5"
integrity sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=
"angular-1.5@npm:angular@1.5":
version "1.5.11"
resolved "https://registry.yarnpkg.com/angular/-/angular-1.5.11.tgz#8c5ba7386f15965c9acf3429f6881553aada30d6"
@@ -3173,7 +3163,7 @@ async@0.9.x:
resolved "https://registry.yarnpkg.com/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d"
integrity sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=
async@1.x, async@^1.3.0, async@^1.5.2:
async@^1.3.0, async@^1.5.2:
version "1.5.2"
resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a"
integrity sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=
@@ -5893,18 +5883,6 @@ escape-string-regexp@^4.0.0:
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
escodegen@1.8.x:
version "1.8.1"
resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.8.1.tgz#5a5b53af4693110bebb0867aa3430dd3b70a1018"
integrity sha1-WltTr0aTEQvrsIZ6o0MN07cKEBg=
dependencies:
esprima "^2.7.1"
estraverse "^1.9.1"
esutils "^2.0.2"
optionator "^0.8.1"
optionalDependencies:
source-map "~0.2.0"
escodegen@^1.8.1:
version "1.14.3"
resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.14.3.tgz#4e7b81fba61581dc97582ed78cab7f0e8d63f503"
@@ -5942,11 +5920,6 @@ eslint-visitor-keys@^2.0.0:
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303"
integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==
esprima@2.7.x, esprima@^2.7.1:
version "2.7.3"
resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581"
integrity sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=
esprima@4.0.1, esprima@^4.0.0, esprima@^4.0.1, esprima@~4.0.0:
version "4.0.1"
resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
@@ -5959,11 +5932,6 @@ esrecurse@^4.3.0:
dependencies:
estraverse "^5.2.0"
estraverse@^1.9.1:
version "1.9.3"
resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-1.9.3.tgz#af67f2dc922582415950926091a4005d29c9bb44"
integrity sha1-r2fy3JIlgkFZUJJgkaQAXSnJu0Q=
estraverse@^4.1.1, estraverse@^4.2.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d"
@@ -7119,17 +7087,6 @@ glob@7.2.0, glob@^7.0.0, glob@^7.0.3, glob@^7.0.6, glob@^7.1.1, glob@^7.1.2, glo
once "^1.3.0"
path-is-absolute "^1.0.0"
glob@^5.0.15:
version "5.0.15"
resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1"
integrity sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=
dependencies:
inflight "^1.0.4"
inherits "2"
minimatch "2 || 3"
once "^1.3.0"
path-is-absolute "^1.0.0"
global-agent@^2.1.12:
version "2.2.0"
resolved "https://registry.yarnpkg.com/global-agent/-/global-agent-2.2.0.tgz#566331b0646e6bf79429a16877685c4a1fbf76dc"
@@ -7470,7 +7427,7 @@ handle-thing@^2.0.0:
resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-2.0.1.tgz#857f79ce359580c340d43081cc648970d0bb234e"
integrity sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==
handlebars@^4.0.1, handlebars@^4.7.6:
handlebars@^4.7.6:
version "4.7.7"
resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.7.tgz#9ce33416aad02dbd6c8fafa8240d5d98004945a1"
integrity sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==
@@ -7507,11 +7464,6 @@ has-ansi@^2.0.0:
dependencies:
ansi-regex "^2.0.0"
has-flag@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa"
integrity sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=
has-flag@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51"
@@ -8573,26 +8525,6 @@ istanbul-reports@^3.0.2:
html-escaper "^2.0.0"
istanbul-lib-report "^3.0.0"
istanbul@^0.4.5:
version "0.4.5"
resolved "https://registry.yarnpkg.com/istanbul/-/istanbul-0.4.5.tgz#65c7d73d4c4da84d4f3ac310b918fb0b8033733b"
integrity sha1-ZcfXPUxNqE1POsMQuRj7C4Azczs=
dependencies:
abbrev "1.0.x"
async "1.x"
escodegen "1.8.x"
esprima "2.7.x"
glob "^5.0.15"
handlebars "^4.0.1"
js-yaml "3.x"
mkdirp "0.5.x"
nopt "3.x"
once "1.x"
resolve "1.1.x"
supports-color "^3.1.0"
which "^1.1.1"
wordwrap "^1.0.0"
isurl@^1.0.0-alpha5:
version "1.0.0"
resolved "https://registry.yarnpkg.com/isurl/-/isurl-1.0.0.tgz#b27f4f49f3cdaa3ea44a0a5b7f3462e6edc39d67"
@@ -8703,7 +8635,7 @@ js-levenshtein@^1.1.6:
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
js-yaml@3.x, js-yaml@^3.13.1:
js-yaml@^3.13.1:
version "3.14.1"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537"
integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==
@@ -8936,14 +8868,6 @@ karma-jasmine@^4.0.1:
dependencies:
jasmine-core "^3.6.0"
karma-parallel@^0.3.1:
version "0.3.1"
resolved "https://registry.yarnpkg.com/karma-parallel/-/karma-parallel-0.3.1.tgz#781876e5992b2781619e762f3e04dcbf85f47fa1"
integrity sha512-64jxNYamYi/9Y67h4+FfViSYhwDgod3rLuq+ZdZ0c3XeZFp/3q3v3HVkd8b5Czp3hCB+LLF8DIv4zlR4xFqbRw==
dependencies:
istanbul "^0.4.5"
lodash "^4.17.11"
karma-requirejs@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/karma-requirejs/-/karma-requirejs-1.1.0.tgz#fddae2cb87d7ebc16fb0222893564d7fee578798"
@@ -9858,7 +9782,7 @@ minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1:
resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7"
integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==
"minimatch@2 || 3", minimatch@3.0.4, minimatch@^3.0.3, minimatch@^3.0.4:
minimatch@3.0.4, minimatch@^3.0.3, minimatch@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
@@ -9969,7 +9893,7 @@ mkdirp-classic@^0.5.2:
resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113"
integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==
mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.1, mkdirp@^0.5.3, mkdirp@^0.5.5:
"mkdirp@>=0.5 0", mkdirp@^0.5.1, mkdirp@^0.5.3, mkdirp@^0.5.5:
version "0.5.5"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def"
integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==
@@ -10049,7 +9973,7 @@ multicast-dns@^6.0.1:
dns-packet "^1.3.1"
thunky "^1.0.2"
multimatch@*:
multimatch@*, multimatch@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/multimatch/-/multimatch-6.0.0.tgz#c72a9bddbc94baa4727efd613b5d22a1fe4d6ee3"
integrity sha512-I7tSVxHGPlmPN/enE3mS1aOSo6bWBfls+3HmuEeCUBCE7gWnm3cBXCBkpurzFjVRwC6Kld8lLaZ1Iv5vOcjvcQ==
@@ -10254,13 +10178,6 @@ nodejs-websocket@^1.7.2:
resolved "https://registry.yarnpkg.com/nodejs-websocket/-/nodejs-websocket-1.7.2.tgz#94abd1e248f57d4d1c663dec3831015c6dad98a6"
integrity sha512-PFX6ypJcCNDs7obRellR0DGTebfUhw1SXGKe2zpB+Ng1DQJhdzbzx1ob+AvJCLzy2TJF4r8cCDqMQqei1CZdPQ==
nopt@3.x:
version "3.0.6"
resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9"
integrity sha1-xkZdvwirzU2zWTF/eaxopkayj/k=
dependencies:
abbrev "1"
nopt@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/nopt/-/nopt-5.0.0.tgz#530942bb58a512fccafe53fe210f13a25355dc88"
@@ -10549,7 +10466,7 @@ on-headers@^1.0.0, on-headers@~1.0.2:
resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f"
integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==
once@1.x, once@^1.3.0, once@^1.3.1, once@^1.3.2, once@^1.4.0:
once@^1.3.0, once@^1.3.1, once@^1.3.2, once@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
@@ -12362,11 +12279,6 @@ resolve-url@^0.2.1:
resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=
resolve@1.1.x:
version "1.1.7"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b"
integrity sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=
resolve@1.20.0, resolve@^1.1.6, resolve@^1.1.7, resolve@^1.10.0, resolve@^1.14.2, resolve@^1.17.0, resolve@^1.19.0, resolve@^1.3.2, resolve@^1.4.0:
version "1.20.0"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975"
@@ -12644,7 +12556,7 @@ sass@1.43.4:
"sauce-connect@https://saucelabs.com/downloads/sc-4.7.1-linux.tar.gz":
version "0.0.0"
resolved "https://saucelabs.com/downloads/sc-4.7.1-linux.tar.gz#e5d7f82ad98251a653d1b0537f1103e49eda5e11"
resolved "https://saucelabs.com/downloads/sc-4.6.2-linux.tar.gz#7b7f35433af9c3380758e048894d7b9aecf3754e"
saucelabs@4.7.8, saucelabs@^1.5.0, saucelabs@^4.6.3:
version "4.7.8"
@@ -13201,13 +13113,6 @@ source-map@^0.5.0, source-map@^0.5.1, source-map@^0.5.6:
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=
source-map@~0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.2.0.tgz#dab73fbcfc2ba819b4de03bd6f6eaa48164b3f9d"
integrity sha1-2rc/vPwrqBm03gO9b26qSBZLP50=
dependencies:
amdefine ">=0.0.4"
sourcemap-codec@1.4.8, sourcemap-codec@^1.4.4, sourcemap-codec@^1.4.8:
version "1.4.8"
resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4"
@@ -13584,13 +13489,6 @@ supports-color@^2.0.0:
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=
supports-color@^3.1.0:
version "3.2.3"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6"
integrity sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=
dependencies:
has-flag "^1.0.0"
supports-color@^5.0.0, supports-color@^5.3.0:
version "5.5.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
@@ -14900,7 +14798,7 @@ which-module@^2.0.0:
resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a"
integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=
which@^1.1.1, which@^1.2.1, which@^1.2.14, which@^1.2.9:
which@^1.2.1, which@^1.2.14, which@^1.2.9:
version "1.3.1"
resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==