Skip to content

Commit

Permalink
feat(@angular-devkit/schematics): add support for analytics
Browse files Browse the repository at this point in the history
Schematics context now have an (optional) analytics field that, if set,
should be used to report usage. This can be set even in some cases where
analytics is disabled (to a noop analytics).
  • Loading branch information
hansl authored and alexeagle committed Mar 20, 2019
1 parent 2e9dc3d commit 15032aa
Show file tree
Hide file tree
Showing 7 changed files with 62 additions and 16 deletions.
5 changes: 4 additions & 1 deletion etc/api/angular_devkit/schematics/src/_golden-api.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,16 @@ export declare type AsyncFileOperator = (tree: FileEntry) => Observable<FileEntr
export declare abstract class BaseWorkflow implements Workflow {
protected _context: WorkflowExecutionContext[];
protected _dryRun: boolean;
protected _engine: SchematicEngine<{}, {}>;
protected _engine: Engine<{}, {}>;
protected _engineHost: EngineHost<{}, {}>;
protected _force: boolean;
protected _host: virtualFs.Host;
protected _lifeCycle: Subject<LifeCycleEvent>;
protected _registry: schema.CoreSchemaRegistry;
protected _reporter: Subject<DryRunEvent>;
readonly context: Readonly<WorkflowExecutionContext>;
readonly engine: Engine<{}, {}>;
readonly engineHost: EngineHost<{}, {}>;
readonly lifeCycle: Observable<LifeCycleEvent>;
readonly registry: schema.SchemaRegistry;
readonly reporter: Observable<DryRunEvent>;
Expand Down Expand Up @@ -556,6 +558,7 @@ export interface TreeConstructor {
export declare const TreeSymbol: symbol;

export interface TypedSchematicContext<CollectionMetadataT extends object, SchematicMetadataT extends object> {
readonly analytics?: analytics.Analytics;
readonly debug: boolean;
readonly engine: Engine<CollectionMetadataT, SchematicMetadataT>;
readonly interactive: boolean;
Expand Down
11 changes: 9 additions & 2 deletions etc/api/angular_devkit/schematics/tools/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ export declare class CollectionMissingSchematicsMapException extends BaseExcepti
constructor(name: string);
}

export declare type ContextTransform = (context: FileSystemSchematicContext) => FileSystemSchematicContext;

export declare class ExportStringRef<T> {
readonly module: string;
readonly path: string;
Expand All @@ -33,6 +35,8 @@ export interface FileSystemCollectionDescription {
readonly version?: string;
}

export declare type FileSystemEngine = Engine<FileSystemCollectionDescription, FileSystemSchematicDescription>;

export declare class FileSystemEngineHost extends FileSystemEngineHostBase {
protected _root: string;
constructor(_root: string);
Expand All @@ -47,7 +51,7 @@ export declare class FileSystemEngineHost extends FileSystemEngineHostBase {
hasTaskExecutor(name: string): boolean;
}

export declare abstract class FileSystemEngineHostBase implements EngineHost<FileSystemCollectionDescription, FileSystemSchematicDescription> {
export declare abstract class FileSystemEngineHostBase implements FileSystemEngineHost {
protected abstract _resolveCollectionPath(name: string): string;
protected abstract _resolveReferenceString(name: string, parentPath: string): {
ref: RuleFactory<{}>;
Expand All @@ -63,6 +67,7 @@ export declare abstract class FileSystemEngineHostBase implements EngineHost<Fil
hasTaskExecutor(name: string): boolean;
listSchematicNames(collection: FileSystemCollectionDesc): string[];
listSchematics(collection: FileSystemCollection): string[];
registerContextTransform(t: ContextTransform): void;
registerOptionsTransform<T extends object, R extends object>(t: OptionTransform<T, R>): void;
registerTaskExecutor<T>(factory: TaskExecutorFactory<T>, options?: T): void;
transformContext(context: FileSystemSchematicContext): FileSystemSchematicContext;
Expand Down Expand Up @@ -123,6 +128,8 @@ export declare class NodePackageDoesNotSupportSchematics extends BaseException {
}

export declare class NodeWorkflow extends workflow.BaseWorkflow {
readonly engine: FileSystemEngine;
readonly engineHost: NodeModulesEngineHost;
constructor(host: virtualFs.Host, options: {
force?: boolean;
dryRun?: boolean;
Expand All @@ -131,7 +138,7 @@ export declare class NodeWorkflow extends workflow.BaseWorkflow {
});
}

export declare type OptionTransform<T extends object, R extends object> = (schematic: FileSystemSchematicDescription, options: T, context?: FileSystemSchematicContext) => Observable<R>;
export declare type OptionTransform<T extends object, R extends object> = (schematic: FileSystemSchematicDescription, options: T, context?: FileSystemSchematicContext) => Observable<R> | PromiseLike<R> | R;

export declare class SchematicMissingDescriptionException extends BaseException {
constructor(name: string);
Expand Down
5 changes: 4 additions & 1 deletion packages/angular_devkit/schematics/src/engine/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* 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 { logging } from '@angular-devkit/core';
import { analytics, logging } from '@angular-devkit/core';
import { Observable } from 'rxjs';
import { Url } from 'url';
import { FileEntry, MergeStrategy, Tree } from '../tree/interface';
Expand Down Expand Up @@ -192,6 +192,9 @@ export interface TypedSchematicContext<CollectionMetadataT extends object,
readonly strategy: MergeStrategy;
readonly interactive: boolean;
addTask<T>(task: TaskConfigurationGenerator<T>, dependencies?: Array<TaskId>): TaskId;

// This might be undefined if the feature is unsupported.
readonly analytics?: analytics.Analytics;
}


Expand Down
10 changes: 8 additions & 2 deletions packages/angular_devkit/schematics/src/workflow/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import { logging, schema, virtualFs } from '@angular-devkit/core';
import { EMPTY, Observable, Subject, concat, from, of, throwError } from 'rxjs';
import { concatMap, defaultIfEmpty, ignoreElements, last, map, tap } from 'rxjs/operators';
import { EngineHost, SchematicEngine } from '../engine';
import { Engine, EngineHost, SchematicEngine } from '../engine';
import { UnsuccessfulWorkflowExecution } from '../exception/exception';
import { standardFormats } from '../formats';
import { DryRunEvent, DryRunSink } from '../sink/dryrun';
Expand Down Expand Up @@ -46,7 +46,7 @@ export interface BaseWorkflowOptions {
* @public
*/
export abstract class BaseWorkflow implements Workflow {
protected _engine: SchematicEngine<{}, {}>;
protected _engine: Engine<{}, {}>;
protected _engineHost: EngineHost<{}, {}>;
protected _registry: schema.CoreSchemaRegistry;

Expand Down Expand Up @@ -87,6 +87,12 @@ export abstract class BaseWorkflow implements Workflow {

return maybeContext;
}
get engine(): Engine<{}, {}> {
return this._engine;
}
get engineHost(): EngineHost<{}, {}> {
return this._engineHost;
}
get registry(): schema.SchemaRegistry {
return this._registry;
}
Expand Down
6 changes: 6 additions & 0 deletions packages/angular_devkit/schematics/tools/description.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import { JsonObject } from '@angular-devkit/core';
import {
Collection,
CollectionDescription,
Engine,
EngineHost,
RuleFactory,
Schematic,
SchematicDescription,
Expand Down Expand Up @@ -44,6 +46,10 @@ export interface FileSystemSchematicDescription extends FileSystemSchematicJsonD
/**
* Used to simplify typings.
*/
export declare type FileSystemEngine
= Engine<FileSystemCollectionDescription, FileSystemSchematicDescription>;
export declare type FileSystemEngineHost
= EngineHost<FileSystemCollectionDescription, FileSystemSchematicDescription>;
export declare type FileSystemCollection
= Collection<FileSystemCollectionDescription, FileSystemSchematicDescription>;
export declare type FileSystemSchematic
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,22 @@ import {
JsonObject,
UnexpectedEndOfInputException,
isObservable,
isPromise,
normalize,
virtualFs,
} from '@angular-devkit/core';
import { NodeJsSyncHost } from '@angular-devkit/core/node';
import { existsSync, statSync } from 'fs';
import { dirname, isAbsolute, join, resolve } from 'path';
import { Observable, from as observableFrom, of as observableOf, throwError } from 'rxjs';
import {
Observable,
from as observableFrom,
of as observableOf,
throwError,
} from 'rxjs';
import { mergeMap } from 'rxjs/operators';
import { Url } from 'url';
import {
EngineHost,
HostCreateTree,
RuleFactory,
Source,
Expand All @@ -32,7 +37,7 @@ import {
import {
FileSystemCollection,
FileSystemCollectionDesc,
FileSystemCollectionDescription,
FileSystemEngineHost,
FileSystemSchematicContext,
FileSystemSchematicDesc,
FileSystemSchematicDescription,
Expand All @@ -45,7 +50,9 @@ export declare type OptionTransform<T extends object, R extends object>
schematic: FileSystemSchematicDescription,
options: T,
context?: FileSystemSchematicContext,
) => Observable<R>;
) => Observable<R> | PromiseLike<R> | R;
export declare type ContextTransform
= (context: FileSystemSchematicContext) => FileSystemSchematicContext;


export class CollectionCannotBeResolvedException extends BaseException {
Expand Down Expand Up @@ -102,8 +109,7 @@ export class SchematicNameCollisionException extends BaseException {
* A EngineHost base class that uses the file system to resolve collections. This is the base of
* all other EngineHost provided by the tooling part of the Schematics library.
*/
export abstract class FileSystemEngineHostBase implements
EngineHost<FileSystemCollectionDescription, FileSystemSchematicDescription> {
export abstract class FileSystemEngineHostBase implements FileSystemEngineHost {
protected abstract _resolveCollectionPath(name: string): string;
protected abstract _resolveReferenceString(
name: string, parentPath: string): { ref: RuleFactory<{}>, path: string } | null;
Expand All @@ -115,6 +121,7 @@ export abstract class FileSystemEngineHostBase implements
desc: Partial<FileSystemSchematicDesc>): FileSystemSchematicDesc;

private _transforms: OptionTransform<{}, {}>[] = [];
private _contextTransforms: ContextTransform[] = [];
private _taskFactories = new Map<string, () => Observable<TaskExecutor>>();

/**
Expand Down Expand Up @@ -148,6 +155,10 @@ export abstract class FileSystemEngineHostBase implements
this._transforms.push(t);
}

registerContextTransform(t: ContextTransform) {
this._contextTransforms.push(t);
}

/**
*
* @param name
Expand Down Expand Up @@ -294,6 +305,8 @@ export abstract class FileSystemEngineHostBase implements
const newOptions = tFn(schematic, opt, context);
if (isObservable(newOptions)) {
return newOptions;
} else if (isPromise(newOptions)) {
return observableFrom(newOptions);
} else {
return observableOf(newOptions);
}
Expand All @@ -302,7 +315,8 @@ export abstract class FileSystemEngineHostBase implements
}

transformContext(context: FileSystemSchematicContext): FileSystemSchematicContext {
return context;
// tslint:disable-next-line:no-any https://github.com/ReactiveX/rxjs/issues/3989
return this._contextTransforms.reduce((acc, curr) => curr(acc), context);
}

getSchematicRuleFactory<OptionT extends object>(
Expand Down
13 changes: 10 additions & 3 deletions packages/angular_devkit/schematics/tools/workflow/node-workflow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
workflow,
} from '@angular-devkit/schematics'; // tslint:disable-line:no-implicit-dependencies
import { BuiltinTaskExecutor } from '../../tasks/node';
import { FileSystemEngine } from '../description';
import { NodeModulesEngineHost } from '../node-module-engine-host';
import { validateOptionsWithSchema } from '../schema-option-transform';

Expand All @@ -28,15 +29,14 @@ export class NodeWorkflow extends workflow.BaseWorkflow {
) {
const engineHost = new NodeModulesEngineHost();
super({
host: host,
engineHost: engineHost,
host,
engineHost,

force: options.force,
dryRun: options.dryRun,
});

engineHost.registerOptionsTransform(validateOptionsWithSchema(this._registry));

engineHost.registerTaskExecutor(
BuiltinTaskExecutor.NodePackage,
{
Expand All @@ -56,4 +56,11 @@ export class NodeWorkflow extends workflow.BaseWorkflow {

this._context = [];
}

get engine(): FileSystemEngine {
return this._engine as {} as FileSystemEngine;
}
get engineHost(): NodeModulesEngineHost {
return this._engineHost as NodeModulesEngineHost;
}
}

0 comments on commit 15032aa

Please sign in to comment.