diff --git a/package.json b/package.json
index edd851576b..1a6fe2f501 100644
--- a/package.json
+++ b/package.json
@@ -49,6 +49,7 @@
"@types/diff": "^3.5.1",
"@types/fs-extra": "4.0.2",
"@types/hammerjs": "2.0.35",
+ "@types/inquirer": "^0.0.44",
"@types/jasmine": "^2.8.8",
"@types/jasminewd2": "^2.0.6",
"@types/minimist": "^1.2.0",
diff --git a/packages/core/schematics/migrations/static-queries/BUILD.bazel b/packages/core/schematics/migrations/static-queries/BUILD.bazel
index 00da5b6919..f8fa0a26ba 100644
--- a/packages/core/schematics/migrations/static-queries/BUILD.bazel
+++ b/packages/core/schematics/migrations/static-queries/BUILD.bazel
@@ -15,6 +15,7 @@ ts_library(
"//packages/core/schematics/utils",
"@npm//@angular-devkit/schematics",
"@npm//@types/node",
+ "@npm//rxjs",
"@npm//typescript",
],
)
diff --git a/packages/core/schematics/migrations/static-queries/index.ts b/packages/core/schematics/migrations/static-queries/index.ts
index cabccfa242..12aea9c7e1 100644
--- a/packages/core/schematics/migrations/static-queries/index.ts
+++ b/packages/core/schematics/migrations/static-queries/index.ts
@@ -6,13 +6,14 @@
* found in the LICENSE file at https://angular.io/license
*/
-import {logging} from '@angular-devkit/core';
import {Rule, SchematicContext, SchematicsException, Tree} from '@angular-devkit/schematics';
import {dirname, relative} from 'path';
+import {from} from 'rxjs';
import * as ts from 'typescript';
import {NgComponentTemplateVisitor} from '../../utils/ng_component_template';
import {getProjectTsConfigPaths} from '../../utils/project_tsconfig_paths';
+import {getInquirer, supportsPrompt} from '../../utils/schematics_prompt';
import {parseTsconfigFile} from '../../utils/typescript/parse_tsconfig';
import {TypeScriptVisitor, visitAllNodes} from '../../utils/typescript/visit_nodes';
@@ -22,34 +23,83 @@ import {TimingStrategy} from './strategies/timing-strategy';
import {QueryUsageStrategy} from './strategies/usage_strategy/usage_strategy';
import {getTransformedQueryCallExpr} from './transform';
-type Logger = logging.LoggerApi;
-
/** Entry point for the V8 static-query migration. */
export default function(): Rule {
return (tree: Tree, context: SchematicContext) => {
- const projectTsConfigPaths = getProjectTsConfigPaths(tree);
- const basePath = process.cwd();
-
- if (!projectTsConfigPaths.length) {
- throw new SchematicsException(
- 'Could not find any tsconfig file. Cannot migrate queries ' +
- 'to explicit timing.');
- }
-
- for (const tsconfigPath of projectTsConfigPaths) {
- runStaticQueryMigration(tree, tsconfigPath, basePath, context.logger);
- }
+ // We need to cast the returned "Observable" to "any" as there is a
+ // RxJS version mismatch that breaks the TS compilation.
+ return from(runMigration(tree, context).then(() => tree)) as any;
};
}
+/** Runs the V8 migration static-query migration for all determined TypeScript projects. */
+async function runMigration(tree: Tree, context: SchematicContext) {
+ const projectTsConfigPaths = getProjectTsConfigPaths(tree);
+ const basePath = process.cwd();
+ const logger = context.logger;
+
+ logger.info('------ Static Query migration ------');
+ logger.info('In preparation for Ivy, developers can now explicitly specify the');
+ logger.info('timing of their queries. Read more about this here:');
+ logger.info('https://github.com/angular/angular/pull/28810');
+ logger.info('');
+
+ if (!projectTsConfigPaths.length) {
+ throw new SchematicsException(
+ 'Could not find any tsconfig file. Cannot migrate queries ' +
+ 'to explicit timing.');
+ }
+
+ // In case prompts are supported, determine the desired migration strategy
+ // by creating a choice prompt. By default the template strategy is used.
+ let isUsageStrategy = false;
+ if (supportsPrompt()) {
+ logger.info('There are two available migration strategies that can be selected:');
+ logger.info(' • Template strategy - migration tool (short-term gains, rare corrections)');
+ logger.info(' • Usage strategy - best practices (long-term gains, manual corrections)');
+ logger.info('For an easy migration, the template strategy is recommended. The usage');
+ logger.info('strategy can be used for best practices and a code base that will be more');
+ logger.info('flexible to changes going forward.');
+ const {strategyName} = await getInquirer().prompt<{strategyName: string}>({
+ type: 'list',
+ name: 'strategyName',
+ message: 'What migration strategy do you want to use?',
+ choices: [
+ {name: 'Template strategy', value: 'template'}, {name: 'Usage strategy', value: 'usage'}
+ ],
+ default: 'template',
+ });
+ logger.info('');
+ isUsageStrategy = strategyName === 'usage';
+ } else {
+ // In case prompts are not supported, we still want to allow developers to opt
+ // into the usage strategy by specifying an environment variable. The tests also
+ // use the environment variable as there is no headless way to select via prompt.
+ isUsageStrategy = !!process.env['NG_STATIC_QUERY_USAGE_STRATEGY'];
+ }
+
+ const failures = [];
+ for (const tsconfigPath of projectTsConfigPaths) {
+ failures.push(...await runStaticQueryMigration(tree, tsconfigPath, basePath, isUsageStrategy));
+ }
+
+ if (failures.length) {
+ logger.info('Some queries cannot be migrated automatically. Please go through');
+ logger.info('those manually and apply the appropriate timing:');
+ failures.forEach(failure => logger.warn(`⮑ ${failure}`));
+ }
+
+ logger.info('------------------------------------------------');
+}
+
/**
* Runs the static query migration for the given TypeScript project. The schematic
* analyzes all queries within the project and sets up the query timing based on
* the current usage of the query property. e.g. a view query that is not used in any
* lifecycle hook does not need to be static and can be set up with "static: false".
*/
-function runStaticQueryMigration(
- tree: Tree, tsconfigPath: string, basePath: string, logger: Logger) {
+async function runStaticQueryMigration(
+ tree: Tree, tsconfigPath: string, basePath: string, isUsageStrategy: boolean) {
const parsed = parseTsconfigFile(tsconfigPath, dirname(tsconfigPath));
const host = ts.createCompilerHost(parsed.options, true);
@@ -62,7 +112,6 @@ function runStaticQueryMigration(
return buffer ? buffer.toString() : undefined;
};
- const isUsageStrategy = !!process.env['NG_STATIC_QUERY_USAGE_STRATEGY'];
const program = ts.createProgram(parsed.fileNames, parsed.options, host);
const typeChecker = program.getTypeChecker();
const queryVisitor = new NgQueryResolveVisitor(typeChecker);
@@ -100,13 +149,13 @@ function runStaticQueryMigration(
const strategy: TimingStrategy = isUsageStrategy ?
new QueryUsageStrategy(classMetadata, typeChecker) :
new QueryTemplateStrategy(tsconfigPath, classMetadata, host);
- const detectionMessages: string[] = [];
+ const failureMessages: string[] = [];
// In case the strategy could not be set up properly, we just exit the
// migration. We don't want to throw an exception as this could mean
// that other migrations are interrupted.
if (!strategy.setup()) {
- return;
+ return [];
}
// Walk through all source files that contain resolved queries and update
@@ -135,23 +184,15 @@ function runStaticQueryMigration(
update.remove(queryExpr.getStart(), queryExpr.getWidth());
update.insertRight(queryExpr.getStart(), newText);
- const {line, character} =
- ts.getLineAndCharacterOfPosition(sourceFile, q.decorator.node.getStart());
- detectionMessages.push(`${relativePath}@${line + 1}:${character + 1}: ${message}`);
+ if (message) {
+ const {line, character} =
+ ts.getLineAndCharacterOfPosition(sourceFile, q.decorator.node.getStart());
+ failureMessages.push(`${relativePath}@${line + 1}:${character + 1}: ${message}`);
+ }
});
tree.commitUpdate(update);
});
- if (detectionMessages.length) {
- logger.info('------ Static Query migration ------');
- logger.info('In preparation for Ivy, developers can now explicitly specify the');
- logger.info('timing of their queries. Read more about this here:');
- logger.info('https://github.com/angular/angular/pull/28810');
- logger.info('');
- logger.info('Some queries cannot be migrated automatically. Please go through');
- logger.info('those manually and apply the appropriate timing:');
- detectionMessages.forEach(failure => logger.warn(`⮑ ${failure}`));
- logger.info('------------------------------------------------');
- }
+ return failureMessages;
}
diff --git a/packages/core/schematics/test/static_queries_migration_template_spec.ts b/packages/core/schematics/test/static_queries_migration_template_spec.ts
index 5345f3c1f7..b2ce90c8cb 100644
--- a/packages/core/schematics/test/static_queries_migration_template_spec.ts
+++ b/packages/core/schematics/test/static_queries_migration_template_spec.ts
@@ -93,11 +93,13 @@ describe('static-queries migration with template strategy', () => {
host.sync.write(normalize(filePath), virtualFs.stringToFileBuffer(contents));
}
- function runMigration() { runner.runSchematic('migration-v8-static-queries', {}, tree); }
+ async function runMigration() {
+ await runner.runSchematicAsync('migration-v8-static-queries', {}, tree).toPromise();
+ }
describe('ViewChild', () => {
- it('should detect queries selecting elements through template reference', () => {
+ it('should detect queries selecting elements through template reference', async() => {
writeFile('/index.ts', `
import {Component, NgModule, ViewChild} from '@angular/core';
@@ -118,7 +120,7 @@ describe('static-queries migration with template strategy', () => {
export class MyModule {}
`);
- runMigration();
+ await runMigration();
expect(tree.readContent('/index.ts'))
.toContain(`@ViewChild('myButton', { static: false }) query: any;`);
@@ -126,7 +128,7 @@ describe('static-queries migration with template strategy', () => {
.toContain(`@ViewChild('myStaticButton', { static: true }) query2: any;`);
});
- it('should detect queries selecting ng-template as static', () => {
+ it('should detect queries selecting ng-template as static', async() => {
writeFile('/index.ts', `
import {Component, NgModule, ViewChild} from '@angular/core';
@@ -143,13 +145,13 @@ describe('static-queries migration with template strategy', () => {
export class MyModule {}
`);
- runMigration();
+ await runMigration();
expect(tree.readContent('/index.ts'))
.toContain(`@ViewChild('myTmpl', { static: true }) query: any;`);
});
- it('should detect queries selecting component view providers through string token', () => {
+ it('should detect queries selecting component view providers through string token', async() => {
writeFile('/index.ts', `
import {Component, Directive, NgModule, ViewChild} from '@angular/core';
@@ -186,7 +188,7 @@ describe('static-queries migration with template strategy', () => {
`);
- runMigration();
+ await runMigration();
expect(tree.readContent('/index.ts'))
.toContain(`@ViewChild('my-token', { static: true }) query: any;`);
@@ -194,7 +196,7 @@ describe('static-queries migration with template strategy', () => {
.toContain(`@ViewChild('my-token-2', { static: false }) query2: any;`);
});
- it('should detect queries selecting component view providers using class token', () => {
+ it('should detect queries selecting component view providers using class token', async() => {
writeFile('/index.ts', `
import {Component, Directive, NgModule, ViewChild} from '@angular/core';
@@ -230,7 +232,7 @@ describe('static-queries migration with template strategy', () => {
`);
- runMigration();
+ await runMigration();
expect(tree.readContent('/index.ts'))
.toContain(`@ViewChild(MyService, { static: true }) query: any;`);
@@ -238,7 +240,7 @@ describe('static-queries migration with template strategy', () => {
.toContain(`@ViewChild(MyService2, { static: false }) query2: any;`);
});
- it('should detect queries selecting component', () => {
+ it('should detect queries selecting component', async() => {
writeFile('/index.ts', `
import {Component, NgModule, ViewChild} from '@angular/core';
import {HomeComponent, HomeComponent2} from './home-comp';
@@ -276,7 +278,7 @@ describe('static-queries migration with template strategy', () => {
export class HomeComponent2 {}
`);
- runMigration();
+ await runMigration();
expect(tree.readContent('/index.ts'))
.toContain(`@ViewChild(HomeComponent, { static: true }) query: any;`);
@@ -284,7 +286,7 @@ describe('static-queries migration with template strategy', () => {
.toContain(`@ViewChild(HomeComponent2, { static: false }) query2: any;`);
});
- it('should detect queries selecting third-party component', () => {
+ it('should detect queries selecting third-party component', async() => {
writeFakeLibrary();
writeFile('/index.ts', `
import {Component, NgModule, ViewChild} from '@angular/core';
@@ -303,13 +305,13 @@ describe('static-queries migration with template strategy', () => {
My projected content
`);
- runMigration();
+ await runMigration();
expect(tree.readContent('/index.ts'))
.toContain(`@ViewChild(MyLibComponent, { static: true }) query: any;`);
});
- it('should detect queries selecting third-party component with multiple selectors', () => {
+ it('should detect queries selecting third-party component with multiple selectors', async() => {
writeFakeLibrary('a-selector, test-selector');
writeFile('/index.ts', `
import {Component, NgModule, ViewChild} from '@angular/core';
@@ -331,13 +333,13 @@ describe('static-queries migration with template strategy', () => {
`);
- runMigration();
+ await runMigration();
expect(tree.readContent('/index.ts'))
.toContain(`@ViewChild(MyLibComponent, { static: false }) query: any;`);
});
- it('should detect queries within structural directive', () => {
+ it('should detect queries within structural directive', async() => {
writeFile('/index.ts', `
import {Component, Directive, NgModule, ViewChild} from '@angular/core';
@@ -359,7 +361,7 @@ describe('static-queries migration with template strategy', () => {
With asterisk
`);
- runMigration();
+ await runMigration();
expect(tree.readContent('/index.ts'))
.toContain(`@ViewChild('myRef', { static: true }) query: any;`);
@@ -367,7 +369,7 @@ describe('static-queries migration with template strategy', () => {
.toContain(`@ViewChild('myRef2', { static: false }) query2: any;`);
});
- it('should detect inherited queries', () => {
+ it('should detect inherited queries', async() => {
writeFile('/index.ts', `
import {Component, NgModule, ViewChild} from '@angular/core';
@@ -386,13 +388,13 @@ describe('static-queries migration with template strategy', () => {
My Ref
`);
- runMigration();
+ await runMigration();
expect(tree.readContent('/index.ts'))
.toContain(`@ViewChild('myRef', { static: true }) query: any;`);
});
- it('should add a todo if a query is not declared in any component', () => {
+ it('should add a todo if a query is not declared in any component', async() => {
writeFile('/index.ts', `
import {Component, NgModule, ViewChild, SomeToken} from '@angular/core';
@@ -401,7 +403,7 @@ describe('static-queries migration with template strategy', () => {
}
`);
- runMigration();
+ await runMigration();
expect(tree.readContent('/index.ts'))
.toContain(
@@ -412,7 +414,7 @@ describe('static-queries migration with template strategy', () => {
/^⮑ {3}index.ts@5:11:.+could not be determined.+not declared in any component/);
});
- it('should add a todo if a query is used multiple times with different timing', () => {
+ it('should add a todo if a query is used multiple times with different timing', async() => {
writeFile('/index.ts', `
import {Component, NgModule, ViewChild} from '@angular/core';
@@ -430,7 +432,7 @@ describe('static-queries migration with template strategy', () => {
export class MyModule {}
`);
- runMigration();
+ await runMigration();
expect(tree.readContent('/index.ts'))
.toContain(`@ViewChild('myRef', /* TODO: add static flag */ {}) query: any;`);
@@ -440,7 +442,7 @@ describe('static-queries migration with template strategy', () => {
/^⮑ {3}index.ts@5:11: Multiple components use the query with different timings./);
});
- it('should gracefully exit migration if queries could not be analyzed', () => {
+ it('should gracefully exit migration if queries could not be analyzed', async() => {
writeFile('/index.ts', `
import {Component, ViewChild} from '@angular/core';
@@ -456,7 +458,7 @@ describe('static-queries migration with template strategy', () => {
// We don't expect an error to be thrown as this could interrupt other
// migrations which are scheduled with "ng update" in the CLI.
- expect(() => runMigration()).not.toThrow();
+ await runMigration();
expect(console.error)
.toHaveBeenCalledWith('Could not create Angular AOT compiler to determine query timing.');
@@ -465,7 +467,7 @@ describe('static-queries migration with template strategy', () => {
jasmine.stringMatching(/Cannot determine the module for class MyComp/));
});
- it('should add a todo for content queries which are not detectable', () => {
+ it('should add a todo for content queries which are not detectable', async() => {
writeFile('/index.ts', `
import {Component, NgModule, ContentChild} from '@angular/core';
@@ -478,7 +480,7 @@ describe('static-queries migration with template strategy', () => {
export class MyModule {}
`);
- runMigration();
+ await runMigration();
expect(tree.readContent('/index.ts'))
.toContain(`@ContentChild('myRef', /* TODO: add static flag */ {}) query: any;`);
diff --git a/packages/core/schematics/test/static_queries_migration_usage_spec.ts b/packages/core/schematics/test/static_queries_migration_usage_spec.ts
index 025618e949..7b33fc99f8 100644
--- a/packages/core/schematics/test/static_queries_migration_usage_spec.ts
+++ b/packages/core/schematics/test/static_queries_migration_usage_spec.ts
@@ -52,7 +52,7 @@ describe('static-queries migration with usage strategy', () => {
describe('ViewChild', () => {
createQueryTests('ViewChild');
- it('should mark view queries used in "ngAfterContentInit" as static', () => {
+ it('should mark view queries used in "ngAfterContentInit" as static', async() => {
writeFile('/index.ts', `
import {Component, ViewChild} from '@angular/core';
@@ -66,13 +66,13 @@ describe('static-queries migration with usage strategy', () => {
}
`);
- runMigration();
+ await runMigration();
expect(tree.readContent('/index.ts'))
.toContain(`@ViewChild('test', { static: true }) query: any;`);
});
- it('should mark view queries used in "ngAfterContentChecked" as static', () => {
+ it('should mark view queries used in "ngAfterContentChecked" as static', async() => {
writeFile('/index.ts', `
import {Component, ViewChild} from '@angular/core';
@@ -86,7 +86,7 @@ describe('static-queries migration with usage strategy', () => {
}
`);
- runMigration();
+ await runMigration();
expect(tree.readContent('/index.ts'))
.toContain(`@ViewChild('test', { static: true }) query: any;`);
@@ -96,7 +96,7 @@ describe('static-queries migration with usage strategy', () => {
describe('ContentChild', () => {
createQueryTests('ContentChild');
- it('should not mark content queries used in "ngAfterContentInit" as static', () => {
+ it('should not mark content queries used in "ngAfterContentInit" as static', async() => {
writeFile('/index.ts', `
import {Component, ContentChild} from '@angular/core';
@@ -110,13 +110,13 @@ describe('static-queries migration with usage strategy', () => {
}
`);
- runMigration();
+ await runMigration();
expect(tree.readContent('/index.ts'))
.toContain(`@ContentChild('test', { static: false }) query: any;`);
});
- it('should not mark content queries used in "ngAfterContentChecked" as static', () => {
+ it('should not mark content queries used in "ngAfterContentChecked" as static', async() => {
writeFile('/index.ts', `
import {Component, ContentChild} from '@angular/core';
@@ -130,7 +130,7 @@ describe('static-queries migration with usage strategy', () => {
}
`);
- runMigration();
+ await runMigration();
expect(tree.readContent('/index.ts'))
.toContain(`@ContentChild('test', { static: false }) query: any;`);
@@ -141,10 +141,12 @@ describe('static-queries migration with usage strategy', () => {
host.sync.write(normalize(filePath), virtualFs.stringToFileBuffer(contents));
}
- function runMigration() { runner.runSchematic('migration-v8-static-queries', {}, tree); }
+ async function runMigration() {
+ await runner.runSchematicAsync('migration-v8-static-queries', {}, tree).toPromise();
+ }
function createQueryTests(queryType: 'ViewChild' | 'ContentChild') {
- it('should mark queries as dynamic', () => {
+ it('should mark queries as dynamic', async() => {
writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core';
@@ -159,7 +161,7 @@ describe('static-queries migration with usage strategy', () => {
}
`);
- runMigration();
+ await runMigration();
expect(tree.readContent('/index.ts'))
.toContain(`@${queryType}('test', { static: false }) unused: any;`);
@@ -167,7 +169,7 @@ describe('static-queries migration with usage strategy', () => {
.toContain(`@${queryType}('dynamic', { static: false }) dynamic: any`);
});
- it('should mark queries used in "ngOnChanges" as static', () => {
+ it('should mark queries used in "ngOnChanges" as static', async() => {
writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core';
@@ -181,13 +183,13 @@ describe('static-queries migration with usage strategy', () => {
}
`);
- runMigration();
+ await runMigration();
expect(tree.readContent('/index.ts'))
.toContain(`@${queryType}('test', { static: true }) query: any;`);
});
- it('should mark queries used in "ngOnInit" as static', () => {
+ it('should mark queries used in "ngOnInit" as static', async() => {
writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core';
@@ -201,13 +203,13 @@ describe('static-queries migration with usage strategy', () => {
}
`);
- runMigration();
+ await runMigration();
expect(tree.readContent('/index.ts'))
.toContain(`@${queryType}('test', { static: true }) query: any;`);
});
- it('should mark queries used in "ngDoCheck" as static', () => {
+ it('should mark queries used in "ngDoCheck" as static', async() => {
writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core';
@@ -221,13 +223,13 @@ describe('static-queries migration with usage strategy', () => {
}
`);
- runMigration();
+ await runMigration();
expect(tree.readContent('/index.ts'))
.toContain(`@${queryType}('test', { static: true }) query: any;`);
});
- it('should keep existing query options when updating timing', () => {
+ it('should keep existing query options when updating timing', async() => {
writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core';
@@ -241,13 +243,13 @@ describe('static-queries migration with usage strategy', () => {
}
`);
- runMigration();
+ await runMigration();
expect(tree.readContent('/index.ts'))
.toContain(`@${queryType}('test', { /* test */ read: null, static: true }) query: any;`);
});
- it('should not overwrite existing explicit query timing', () => {
+ it('should not overwrite existing explicit query timing', async() => {
writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core';
@@ -257,13 +259,13 @@ describe('static-queries migration with usage strategy', () => {
}
`);
- runMigration();
+ await runMigration();
expect(tree.readContent('/index.ts'))
.toContain(`@${queryType}('test', {static: /* untouched */ someVal}) query: any;`);
});
- it('should detect queries used in deep method chain', () => {
+ it('should detect queries used in deep method chain', async() => {
writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core';
@@ -292,13 +294,13 @@ describe('static-queries migration with usage strategy', () => {
}
`);
- runMigration();
+ await runMigration();
expect(tree.readContent('/index.ts'))
.toContain(`@${queryType}('test', { static: true }) query: any;`);
});
- it('should properly exit if recursive function is analyzed', () => {
+ it('should properly exit if recursive function is analyzed', async() => {
writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core';
@@ -316,13 +318,13 @@ describe('static-queries migration with usage strategy', () => {
}
`);
- runMigration();
+ await runMigration();
expect(tree.readContent('/index.ts'))
.toContain(`@${queryType}('test', { static: false }) query: any;`);
});
- it('should detect queries used in newly instantiated classes', () => {
+ it('should detect queries used in newly instantiated classes', async() => {
writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core';
@@ -353,7 +355,7 @@ describe('static-queries migration with usage strategy', () => {
}
`);
- runMigration();
+ await runMigration();
expect(tree.readContent('/index.ts'))
.toContain(`@${queryType}('test', { static: true }) query: any;`);
@@ -361,7 +363,7 @@ describe('static-queries migration with usage strategy', () => {
.toContain(`@${queryType}('test', { static: true }) query2: any;`);
});
- it('should detect queries used in parenthesized new expressions', () => {
+ it('should detect queries used in parenthesized new expressions', async() => {
writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core';
@@ -381,13 +383,13 @@ describe('static-queries migration with usage strategy', () => {
}
`);
- runMigration();
+ await runMigration();
expect(tree.readContent('/index.ts'))
.toContain(`@${queryType}('test', { static: true }) query: any;`);
});
- it('should detect queries in lifecycle hook with string literal name', () => {
+ it('should detect queries in lifecycle hook with string literal name', async() => {
writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core';
@@ -401,13 +403,13 @@ describe('static-queries migration with usage strategy', () => {
}
`);
- runMigration();
+ await runMigration();
expect(tree.readContent('/index.ts'))
.toContain(`@${queryType}('test', { static: true }) query: any;`);
});
- it('should detect static queries within nested inheritance', () => {
+ it('should detect static queries within nested inheritance', async() => {
writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core';
@@ -426,13 +428,13 @@ describe('static-queries migration with usage strategy', () => {
}
`);
- runMigration();
+ await runMigration();
expect(tree.readContent('/index.ts'))
.toContain(`@${queryType}('test', { static: true }) query: any;`);
});
- it('should detect static queries used within input setters', () => {
+ it('should detect static queries used within input setters', async() => {
writeFile('/index.ts', `
import {Component, Input, ${queryType}} from '@angular/core';
@@ -448,13 +450,13 @@ describe('static-queries migration with usage strategy', () => {
}
`);
- runMigration();
+ await runMigration();
expect(tree.readContent('/index.ts'))
.toContain(`@${queryType}('test', { static: true }) query: any;`);
});
- it('should detect inputs defined in metadata', () => {
+ it('should detect inputs defined in metadata', async() => {
writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core';
@@ -474,13 +476,13 @@ describe('static-queries migration with usage strategy', () => {
}
`);
- runMigration();
+ await runMigration();
expect(tree.readContent('/index.ts'))
.toContain(`@${queryType}('test', { static: true }) query: any;`);
});
- it('should detect aliased inputs declared in metadata', () => {
+ it('should detect aliased inputs declared in metadata', async() => {
writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core';
@@ -497,13 +499,13 @@ describe('static-queries migration with usage strategy', () => {
}
`);
- runMigration();
+ await runMigration();
expect(tree.readContent('/index.ts'))
.toContain(`@${queryType}('test', { static: true }) query: any;`);
});
- it('should not mark query as static if query is used in non-input setter', () => {
+ it('should not mark query as static if query is used in non-input setter', async() => {
writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core';
@@ -517,13 +519,13 @@ describe('static-queries migration with usage strategy', () => {
}
`);
- runMigration();
+ await runMigration();
expect(tree.readContent('/index.ts'))
.toContain(`@${queryType}('test', { static: false }) query: any;`);
});
- it('should detect input decorator on setter', () => {
+ it('should detect input decorator on setter', async() => {
writeFile('/index.ts', `
import {Input, Component, ${queryType}} from '@angular/core';
@@ -542,13 +544,13 @@ describe('static-queries migration with usage strategy', () => {
}
`);
- runMigration();
+ await runMigration();
expect(tree.readContent('/index.ts'))
.toContain(`@${queryType}('test', { static: true }) query: any;`);
});
- it('should detect setter inputs in derived classes', () => {
+ it('should detect setter inputs in derived classes', async() => {
writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core';
@@ -567,13 +569,13 @@ describe('static-queries migration with usage strategy', () => {
}
`);
- runMigration();
+ await runMigration();
expect(tree.readContent('/index.ts'))
.toContain(`@${queryType}('test', { static: true }) query: any;`);
});
- it('should properly detect static query in external derived class', () => {
+ it('should properly detect static query in external derived class', async() => {
writeFile('/src/index.ts', `
import {Component, ${queryType}} from '@angular/core';
@@ -597,13 +599,13 @@ describe('static-queries migration with usage strategy', () => {
// recorded for TypeScript projects not at the schematic tree root.
host.sync.rename(normalize('/tsconfig.json'), normalize('/src/tsconfig.json'));
- runMigration();
+ await runMigration();
expect(tree.readContent('/src/index.ts'))
.toContain(`@${queryType}('test', { static: true }) query: any;`);
});
- it('should not mark queries used in promises as static', () => {
+ it('should not mark queries used in promises as static', async() => {
writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core';
@@ -637,7 +639,7 @@ describe('static-queries migration with usage strategy', () => {
}
`);
- runMigration();
+ await runMigration();
expect(tree.readContent('/index.ts'))
.toContain(`@${queryType}('test', { static: false }) query: any;`);
@@ -645,7 +647,7 @@ describe('static-queries migration with usage strategy', () => {
.toContain(`@${queryType}('test', { static: true }) query2: any;`);
});
- it('should handle function callbacks which statically access queries', () => {
+ it('should handle function callbacks which statically access queries', async() => {
writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core';
@@ -667,14 +669,15 @@ describe('static-queries migration with usage strategy', () => {
}
`);
- runMigration();
+ await runMigration();
expect(tree.readContent('/index.ts'))
.toContain(`@${queryType}('test', { static: true }) query: any;`);
});
- it('should handle class instantiations with specified callbacks that access queries', () => {
- writeFile('/index.ts', `
+ it('should handle class instantiations with specified callbacks that access queries',
+ async() => {
+ writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core';
import {External} from './external';
@@ -688,7 +691,7 @@ describe('static-queries migration with usage strategy', () => {
}
`);
- writeFile('/external.ts', `
+ writeFile('/external.ts', `
export class External {
constructor(cb: () => void) {
// Add extra parentheses to ensure that expression is unwrapped.
@@ -697,13 +700,13 @@ describe('static-queries migration with usage strategy', () => {
}
`);
- runMigration();
+ await runMigration();
- expect(tree.readContent('/index.ts'))
- .toContain(`@${queryType}('test', { static: true }) query: any;`);
- });
+ expect(tree.readContent('/index.ts'))
+ .toContain(`@${queryType}('test', { static: true }) query: any;`);
+ });
- it('should handle nested functions with arguments from parent closure', () => {
+ it('should handle nested functions with arguments from parent closure', async() => {
writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core';
@@ -726,13 +729,13 @@ describe('static-queries migration with usage strategy', () => {
}
`);
- runMigration();
+ await runMigration();
expect(tree.readContent('/index.ts'))
.toContain(`@${queryType}('test', { static: true }) query: any;`);
});
- it('should not mark queries used in setTimeout as static', () => {
+ it('should not mark queries used in setTimeout as static', async() => {
writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core';
@@ -757,7 +760,7 @@ describe('static-queries migration with usage strategy', () => {
}
`);
- runMigration();
+ await runMigration();
expect(tree.readContent('/index.ts'))
.toContain(`@${queryType}('test', { static: false }) query: any;`);
@@ -767,7 +770,7 @@ describe('static-queries migration with usage strategy', () => {
.toContain(`@${queryType}('test', { static: false }) query3: any;`);
});
- it('should not mark queries used in "addEventListener" as static', () => {
+ it('should not mark queries used in "addEventListener" as static', async() => {
writeFile('/index.ts', `
import {Component, ElementRef, ${queryType}} from '@angular/core';
@@ -785,13 +788,13 @@ describe('static-queries migration with usage strategy', () => {
}
`);
- runMigration();
+ await runMigration();
expect(tree.readContent('/index.ts'))
.toContain(`@${queryType}('test', { static: false }) query: any;`);
});
- it('should not mark queries used in "requestAnimationFrame" as static', () => {
+ it('should not mark queries used in "requestAnimationFrame" as static', async() => {
writeFile('/index.ts', `
import {Component, ElementRef, ${queryType}} from '@angular/core';
@@ -809,13 +812,13 @@ describe('static-queries migration with usage strategy', () => {
}
`);
- runMigration();
+ await runMigration();
expect(tree.readContent('/index.ts'))
.toContain(`@${queryType}('test', { static: false }) query: any;`);
});
- it('should mark queries used in immediately-invoked function expression as static', () => {
+ it('should mark queries used in immediately-invoked function expression as static', async() => {
writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core';
@@ -836,7 +839,7 @@ describe('static-queries migration with usage strategy', () => {
}
`);
- runMigration();
+ await runMigration();
expect(tree.readContent('/index.ts'))
.toContain(`@${queryType}('test', { static: true }) query: any;`);
@@ -844,7 +847,7 @@ describe('static-queries migration with usage strategy', () => {
.toContain(`@${queryType}('test', { static: true }) query2: any;`);
});
- it('should detect static queries used in external function-like declaration', () => {
+ it('should detect static queries used in external function-like declaration', async() => {
writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core';
import {externalFn} from './external';
@@ -867,13 +870,13 @@ describe('static-queries migration with usage strategy', () => {
}
`);
- runMigration();
+ await runMigration();
expect(tree.readContent('/index.ts'))
.toContain(`@${queryType}('test', { static: true }) query: any;`);
});
- it('should detect static queries used through getter property access', () => {
+ it('should detect static queries used through getter property access', async() => {
writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core';
@@ -891,13 +894,13 @@ describe('static-queries migration with usage strategy', () => {
}
`);
- runMigration();
+ await runMigration();
expect(tree.readContent('/index.ts'))
.toContain(`@${queryType}('test', { static: true }) query: any;`);
});
- it('should detect static queries used through external getter access', () => {
+ it('should detect static queries used through external getter access', async() => {
writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core';
import {External} from './external';
@@ -929,13 +932,13 @@ describe('static-queries migration with usage strategy', () => {
}
`);
- runMigration();
+ await runMigration();
expect(tree.readContent('/index.ts'))
.toContain(`@${queryType}('test', { static: true }) query: any;`);
});
- it('should not mark queries as static if a value is assigned to accessor property', () => {
+ it('should not mark queries as static if a value is assigned to accessor property', async() => {
writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core';
@@ -954,13 +957,13 @@ describe('static-queries migration with usage strategy', () => {
}
`);
- runMigration();
+ await runMigration();
expect(tree.readContent('/index.ts'))
.toContain(`@${queryType}('test', { static: false }) query: any;`);
});
- it('should mark queries as static if non-input setter uses query', () => {
+ it('should mark queries as static if non-input setter uses query', async() => {
writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core';
@@ -979,13 +982,13 @@ describe('static-queries migration with usage strategy', () => {
}
`);
- runMigration();
+ await runMigration();
expect(tree.readContent('/index.ts'))
.toContain(`@${queryType}('test', { static: true }) query: any;`);
});
- it('should check setter and getter when using compound assignment', () => {
+ it('should check setter and getter when using compound assignment', async() => {
writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core';
@@ -1005,7 +1008,7 @@ describe('static-queries migration with usage strategy', () => {
}
`);
- runMigration();
+ await runMigration();
expect(tree.readContent('/index.ts'))
.toContain(`@${queryType}('test', { static: true }) query: any;`);
@@ -1013,7 +1016,7 @@ describe('static-queries migration with usage strategy', () => {
.toContain(`@${queryType}('test', { static: true }) query2: any;`);
});
- it('should check getters when using comparison operator in binary expression', () => {
+ it('should check getters when using comparison operator in binary expression', async() => {
writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core';
@@ -1032,13 +1035,13 @@ describe('static-queries migration with usage strategy', () => {
}
`);
- runMigration();
+ await runMigration();
expect(tree.readContent('/index.ts'))
.toContain(`@${queryType}('test', { static: true }) query: any;`);
});
- it('should check derived abstract class methods', () => {
+ it('should check derived abstract class methods', async() => {
writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core';
@@ -1068,13 +1071,13 @@ describe('static-queries migration with usage strategy', () => {
}
`);
- runMigration();
+ await runMigration();
expect(tree.readContent('/index.ts'))
.toContain(`@${queryType}('test', { static: true }) query: any;`);
});
- it('should detect queries accessed through deep abstract class method', () => {
+ it('should detect queries accessed through deep abstract class method', async() => {
writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core';
@@ -1100,13 +1103,13 @@ describe('static-queries migration with usage strategy', () => {
}
`);
- runMigration();
+ await runMigration();
expect(tree.readContent('/index.ts'))
.toContain(`@${queryType}('test', { static: true }) query: any;`);
});
- it('should detect queries accessed through abstract property getter', () => {
+ it('should detect queries accessed through abstract property getter', async() => {
writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core';
@@ -1126,13 +1129,13 @@ describe('static-queries migration with usage strategy', () => {
}
`);
- runMigration();
+ await runMigration();
expect(tree.readContent('/index.ts'))
.toContain(`@${queryType}('test', { static: true }) query: any;`);
});
- it('should detect queries accessed through abstract property setter', () => {
+ it('should detect queries accessed through abstract property setter', async() => {
writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core';
@@ -1153,13 +1156,13 @@ describe('static-queries migration with usage strategy', () => {
}
`);
- runMigration();
+ await runMigration();
expect(tree.readContent('/index.ts'))
.toContain(`@${queryType}('test', { static: true }) query: any;`);
});
- it('should detect query usage in abstract class methods accessing inherited query', () => {
+ it('should detect query usage in abstract class methods accessing inherited query', async() => {
writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core';
@@ -1189,13 +1192,13 @@ describe('static-queries migration with usage strategy', () => {
}
`);
- runMigration();
+ await runMigration();
expect(tree.readContent('/index.ts'))
.toContain(`@${queryType}('test', { static: true }) query: any;`);
});
- it('should detect query usage within component template', () => {
+ it('should detect query usage within component template', async() => {
writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core';
@@ -1210,13 +1213,13 @@ describe('static-queries migration with usage strategy', () => {
`);
- runMigration();
+ await runMigration();
expect(tree.readContent('/index.ts'))
.toContain(`@${queryType}('test', { static: true }) query: any;`);
});
- it('should detect query usage with nested property read within component template', () => {
+ it('should detect query usage with nested property read within component template', async() => {
writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core';
@@ -1231,14 +1234,15 @@ describe('static-queries migration with usage strategy', () => {
`);
- runMigration();
+ await runMigration();
expect(tree.readContent('/index.ts'))
.toContain(`@${queryType}('test', { static: true }) query: any;`);
});
- it('should not mark query as static if template has template reference with same name', () => {
- writeFile('/index.ts', `
+ it('should not mark query as static if template has template reference with same name',
+ async() => {
+ writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core';
@Component({templateUrl: 'my-template.html'})
@@ -1247,21 +1251,21 @@ describe('static-queries migration with usage strategy', () => {
}
`);
- writeFile(`/my-template.html`, `
+ writeFile(`/my-template.html`, `
`);
- runMigration();
+ await runMigration();
- expect(tree.readContent('/index.ts'))
- .toContain(`@${queryType}('test', { static: false }) query: any;`);
- });
+ expect(tree.readContent('/index.ts'))
+ .toContain(`@${queryType}('test', { static: false }) query: any;`);
+ });
it('should not mark query as static if template has property read with query name but different receiver',
- () => {
+ async() => {
writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core';
@@ -1280,13 +1284,13 @@ describe('static-queries migration with usage strategy', () => {
`);
- runMigration();
+ await runMigration();
expect(tree.readContent('/index.ts'))
.toContain(`@${queryType}('test', { static: false }) someProp: any;`);
});
- it('should ignore queries accessed within element', () => {
+ it('should ignore queries accessed within element', async() => {
writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core';
@@ -1304,13 +1308,13 @@ describe('static-queries migration with usage strategy', () => {
`);
- runMigration();
+ await runMigration();
expect(tree.readContent('/index.ts'))
.toContain(`@${queryType}('test', { static: false }) query: any;`);
});
- it('should detect inherited queries used in templates', () => {
+ it('should detect inherited queries used in templates', async() => {
writeFile('/index.ts', `
import {Component, ${queryType}} from '@angular/core';
@@ -1327,13 +1331,13 @@ describe('static-queries migration with usage strategy', () => {
`);
- runMigration();
+ await runMigration();
expect(tree.readContent('/index.ts'))
.toContain(`@${queryType}('test', { static: true }) query: any;`);
});
- it('should properly handle multiple tsconfig files', () => {
+ it('should properly handle multiple tsconfig files', async() => {
writeFile('/src/index.ts', `
import {Component, ${queryType}} from '@angular/core';
@@ -1352,7 +1356,7 @@ describe('static-queries migration with usage strategy', () => {
// The migration runs for "/tsconfig.json" and "/src/tsconfig.json" which both
// contain the "src/index.ts" file. This test ensures that we don't incorrectly
// apply the code transformation multiple times with outdated offsets.
- runMigration();
+ await runMigration();
expect(tree.readContent('/src/index.ts'))
.toContain(`@${queryType}('test', { static: false }) query: any;`);
diff --git a/packages/core/schematics/utils/schematics_prompt.ts b/packages/core/schematics/utils/schematics_prompt.ts
new file mode 100644
index 0000000000..9fcfc92f48
--- /dev/null
+++ b/packages/core/schematics/utils/schematics_prompt.ts
@@ -0,0 +1,34 @@
+/**
+ * @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
+ */
+
+type Inquirer = typeof import('inquirer');
+
+let resolvedInquirerModule: Inquirer|null;
+
+try {
+ // "inquirer" is the prompt module also used by the devkit schematics CLI
+ // in order to show prompts for schematics. We transitively depend on this
+ // module, but don't want to throw an exception if the module is not
+ // installed for some reason. In that case prompts are just not supported.
+ resolvedInquirerModule = require('inquirer');
+} catch (e) {
+ resolvedInquirerModule = null;
+}
+
+/** Whether prompts are currently supported. */
+export function supportsPrompt(): boolean {
+ return !!resolvedInquirerModule && !!process.stdin.isTTY;
+}
+
+/**
+ * Gets the resolved instance of "inquirer" which can be used to programmatically
+ * create prompts.
+ */
+export function getInquirer(): Inquirer {
+ return resolvedInquirerModule !;
+}
diff --git a/yarn.lock b/yarn.lock
index f036c51758..dddf995843 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -455,6 +455,14 @@
resolved "https://registry.yarnpkg.com/@types/hammerjs/-/hammerjs-2.0.35.tgz#7b7c950c7d54593e23bffc8d2b4feba9866a7277"
integrity sha512-4mUIMSZ2U4UOWq1b+iV7XUTE4w+Kr3x+Zb/Qz5ROO6BTZLw2c8/ftjq0aRgluguLs4KRuBnrOy/s389HVn1/zA==
+"@types/inquirer@^0.0.44":
+ version "0.0.44"
+ resolved "https://registry.yarnpkg.com/@types/inquirer/-/inquirer-0.0.44.tgz#60ce954581cfdf44ad3899ec4cdc5fbe3fef1694"
+ integrity sha512-ugbhy1yBtCz5iTWYF+AGRS/UcMcWicdyHhxl9VaeFYc3ueg0CCssthQLB3rIcIOeGtfG6WPEvHdLu/IjKYfefg==
+ dependencies:
+ "@types/rx" "*"
+ "@types/through" "*"
+
"@types/jasmine@*":
version "3.3.5"
resolved "https://registry.yarnpkg.com/@types/jasmine/-/jasmine-3.3.5.tgz#3738ffbf34dffae9ecaac4503d7d969744f0e1d7"
@@ -524,6 +532,107 @@
resolved "https://registry.yarnpkg.com/@types/q/-/q-0.0.32.tgz#bd284e57c84f1325da702babfc82a5328190c0c5"
integrity sha1-vShOV8hPEyXacCur/IKlMoGQwMU=
+"@types/rx-core-binding@*":
+ version "4.0.4"
+ resolved "https://registry.yarnpkg.com/@types/rx-core-binding/-/rx-core-binding-4.0.4.tgz#d969d32f15a62b89e2862c17b3ee78fe329818d3"
+ integrity sha512-5pkfxnC4w810LqBPUwP5bg7SFR/USwhMSaAeZQQbEHeBp57pjKXRlXmqpMrLJB4y1oglR/c2502853uN0I+DAQ==
+ dependencies:
+ "@types/rx-core" "*"
+
+"@types/rx-core@*":
+ version "4.0.3"
+ resolved "https://registry.yarnpkg.com/@types/rx-core/-/rx-core-4.0.3.tgz#0b3354b1238cedbe2b74f6326f139dbc7a591d60"
+ integrity sha1-CzNUsSOM7b4rdPYybxOdvHpZHWA=
+
+"@types/rx-lite-aggregates@*":
+ version "4.0.3"
+ resolved "https://registry.yarnpkg.com/@types/rx-lite-aggregates/-/rx-lite-aggregates-4.0.3.tgz#6efb2b7f3d5f07183a1cb2bd4b1371d7073384c2"
+ integrity sha512-MAGDAHy8cRatm94FDduhJF+iNS5//jrZ/PIfm+QYw9OCeDgbymFHChM8YVIvN2zArwsRftKgE33QfRWvQk4DPg==
+ dependencies:
+ "@types/rx-lite" "*"
+
+"@types/rx-lite-async@*":
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/@types/rx-lite-async/-/rx-lite-async-4.0.2.tgz#27fbf0caeff029f41e2d2aae638b05e91ceb600c"
+ integrity sha512-vTEv5o8l6702ZwfAM5aOeVDfUwBSDOs+ARoGmWAKQ6LOInQ8J4/zjM7ov12fuTpktUKdMQjkeCp07Vd73mPkxw==
+ dependencies:
+ "@types/rx-lite" "*"
+
+"@types/rx-lite-backpressure@*":
+ version "4.0.3"
+ resolved "https://registry.yarnpkg.com/@types/rx-lite-backpressure/-/rx-lite-backpressure-4.0.3.tgz#05abb19bdf87cc740196c355e5d0b37bb50b5d56"
+ integrity sha512-Y6aIeQCtNban5XSAF4B8dffhIKu6aAy/TXFlScHzSxh6ivfQBQw6UjxyEJxIOt3IT49YkS+siuayM2H/Q0cmgA==
+ dependencies:
+ "@types/rx-lite" "*"
+
+"@types/rx-lite-coincidence@*":
+ version "4.0.3"
+ resolved "https://registry.yarnpkg.com/@types/rx-lite-coincidence/-/rx-lite-coincidence-4.0.3.tgz#80bd69acc4054a15cdc1638e2dc8843498cd85c0"
+ integrity sha512-1VNJqzE9gALUyMGypDXZZXzR0Tt7LC9DdAZQ3Ou/Q0MubNU35agVUNXKGHKpNTba+fr8GdIdkC26bRDqtCQBeQ==
+ dependencies:
+ "@types/rx-lite" "*"
+
+"@types/rx-lite-experimental@*":
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/@types/rx-lite-experimental/-/rx-lite-experimental-4.0.1.tgz#c532f5cbdf3f2c15da16ded8930d1b2984023cbd"
+ integrity sha1-xTL1y98/LBXaFt7Ykw0bKYQCPL0=
+ dependencies:
+ "@types/rx-lite" "*"
+
+"@types/rx-lite-joinpatterns@*":
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/@types/rx-lite-joinpatterns/-/rx-lite-joinpatterns-4.0.1.tgz#f70fe370518a8432f29158cc92ffb56b4e4afc3e"
+ integrity sha1-9w/jcFGKhDLykVjMkv+1a05K/D4=
+ dependencies:
+ "@types/rx-lite" "*"
+
+"@types/rx-lite-testing@*":
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/@types/rx-lite-testing/-/rx-lite-testing-4.0.1.tgz#21b19d11f4dfd6ffef5a9d1648e9c8879bfe21e9"
+ integrity sha1-IbGdEfTf1v/vWp0WSOnIh5v+Iek=
+ dependencies:
+ "@types/rx-lite-virtualtime" "*"
+
+"@types/rx-lite-time@*":
+ version "4.0.3"
+ resolved "https://registry.yarnpkg.com/@types/rx-lite-time/-/rx-lite-time-4.0.3.tgz#0eda65474570237598f3448b845d2696f2dbb1c4"
+ integrity sha512-ukO5sPKDRwCGWRZRqPlaAU0SKVxmWwSjiOrLhoQDoWxZWg6vyB9XLEZViKOzIO6LnTIQBlk4UylYV0rnhJLxQw==
+ dependencies:
+ "@types/rx-lite" "*"
+
+"@types/rx-lite-virtualtime@*":
+ version "4.0.3"
+ resolved "https://registry.yarnpkg.com/@types/rx-lite-virtualtime/-/rx-lite-virtualtime-4.0.3.tgz#4b30cacd0fe2e53af29f04f7438584c7d3959537"
+ integrity sha512-3uC6sGmjpOKatZSVHI2xB1+dedgml669ZRvqxy+WqmGJDVusOdyxcKfyzjW0P3/GrCiN4nmRkLVMhPwHCc5QLg==
+ dependencies:
+ "@types/rx-lite" "*"
+
+"@types/rx-lite@*":
+ version "4.0.6"
+ resolved "https://registry.yarnpkg.com/@types/rx-lite/-/rx-lite-4.0.6.tgz#3c02921c4244074234f26b772241bcc20c18c253"
+ integrity sha512-oYiDrFIcor9zDm0VDUca1UbROiMYBxMLMaM6qzz4ADAfOmA9r1dYEcAFH+2fsPI5BCCjPvV9pWC3X3flbrvs7w==
+ dependencies:
+ "@types/rx-core" "*"
+ "@types/rx-core-binding" "*"
+
+"@types/rx@*":
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/@types/rx/-/rx-4.1.1.tgz#598fc94a56baed975f194574e0f572fd8e627a48"
+ integrity sha1-WY/JSla67ZdfGUV04PVy/Y5iekg=
+ dependencies:
+ "@types/rx-core" "*"
+ "@types/rx-core-binding" "*"
+ "@types/rx-lite" "*"
+ "@types/rx-lite-aggregates" "*"
+ "@types/rx-lite-async" "*"
+ "@types/rx-lite-backpressure" "*"
+ "@types/rx-lite-coincidence" "*"
+ "@types/rx-lite-experimental" "*"
+ "@types/rx-lite-joinpatterns" "*"
+ "@types/rx-lite-testing" "*"
+ "@types/rx-lite-time" "*"
+ "@types/rx-lite-virtualtime" "*"
+
"@types/selenium-webdriver@3.0.7":
version "3.0.7"
resolved "https://registry.yarnpkg.com/@types/selenium-webdriver/-/selenium-webdriver-3.0.7.tgz#5d3613d1ab3ca08b74d19683a3a7c573129ab18f"
@@ -554,6 +663,13 @@
resolved "https://registry.yarnpkg.com/@types/systemjs/-/systemjs-0.19.32.tgz#e9204c4cdbc8e275d645c00e6150e68fc5615a24"
integrity sha1-6SBMTNvI4nXWRcAOYVDmj8VhWiQ=
+"@types/through@*":
+ version "0.0.29"
+ resolved "https://registry.yarnpkg.com/@types/through/-/through-0.0.29.tgz#72943aac922e179339c651fa34a4428a4d722f93"
+ integrity sha512-9a7C5VHh+1BKblaYiq+7Tfc+EOmjMdZaD1MYtkQjSoxgB69tBjW98ry6SKsi4zEIWztLOMRuL87A3bdT/Fc/4w==
+ dependencies:
+ "@types/node" "*"
+
"@types/yargs@^11.1.1":
version "11.1.1"
resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-11.1.1.tgz#2e724257167fd6b615dbe4e54301e65fe597433f"