diff --git a/BUILD.bazel b/BUILD.bazel index c4583ffd86..a6187e772e 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -29,6 +29,8 @@ node_modules_filegroup( "tsutils", "typescript", "zone.js", + "@angular-devkit/core", + "@angular-devkit/schematics", "@types", "@webcomponents/custom-elements", ], diff --git a/karma-js.conf.js b/karma-js.conf.js index 5a7bdae4cb..aab3ad13ca 100644 --- a/karma-js.conf.js +++ b/karma-js.conf.js @@ -68,6 +68,7 @@ module.exports = function(config) { 'dist/all/@angular/compiler/test/aot/**', 'dist/all/@angular/compiler/test/render3/**', 'dist/all/@angular/core/test/bundling/**', + 'dist/all/@angular/elements/schematics/**', 'dist/all/@angular/examples/**/e2e_test/*', 'dist/all/@angular/language-service/**', 'dist/all/@angular/router/test/**', diff --git a/package.json b/package.json index 250e70bb99..6782934973 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,8 @@ "commitmsg": "node ./scripts/git/commit-msg.js" }, "dependencies": { + "@angular-devkit/schematics": "^0.5.5", + "@schematics/angular": "^0.5.4", "core-js": "^2.4.1", "reflect-metadata": "^0.1.3", "rxjs": "^6.0.0-terrific-rc.3", diff --git a/packages/elements/package.json b/packages/elements/package.json index 6c3a5e19e2..08d9e2a7c6 100644 --- a/packages/elements/package.json +++ b/packages/elements/package.json @@ -27,5 +27,6 @@ "ng-update": { "packageGroup": "NG_UPDATE_PACKAGE_GROUP" }, - "sideEffects": false + "sideEffects": false, + "schematics": "./schematics/collection.json" } diff --git a/packages/elements/schematics/BUILD.bazel b/packages/elements/schematics/BUILD.bazel new file mode 100644 index 0000000000..d37f40b269 --- /dev/null +++ b/packages/elements/schematics/BUILD.bazel @@ -0,0 +1,58 @@ +package(default_visibility = ["//visibility:public"]) + +load("//tools:defaults.bzl", "ts_library") +load("@build_bazel_rules_nodejs//:defs.bzl", "jasmine_node_test") + +exports_files([ + "package.json", + "collection.json", +]) + +ts_library( + name = "schematics", + srcs = glob( + [ + "ng-add/index.ts", + "ng-add/schema.d.ts", + ], + ), + module_name = "@angular/elements/schematics", + deps = [ + "//packages/common", + "//packages/core", + "@rxjs", + ], +) + +ts_library( + name = "test_lib", + testonly = 1, + srcs = glob( + [ + "ng-add/index_spec.ts", + ], + ), + deps = [ + ":schematics", + "//packages/common", + "//packages/core", + "@rxjs", + "@rxjs//operators", + ], +) + +jasmine_node_test( + name = "test", + data = [":collection"], + deps = [ + ":test_lib", + ], +) + +genrule( + name = "collection", + srcs = ["collection.json"], + outs = ["test-collection.json"], + cmd = "cp $< $@", + output_to_bindir = 1, +) diff --git a/packages/elements/schematics/collection.json b/packages/elements/schematics/collection.json new file mode 100644 index 0000000000..a5d825684d --- /dev/null +++ b/packages/elements/schematics/collection.json @@ -0,0 +1,9 @@ +{ + "$schema": "../node_modules/@angular-devkit/schematics/collection-schema.json", + "schematics": { + "ng-add": { + "description": "Adds the document-register-element polyfill.", + "factory": "./ng-add" + } + } +} diff --git a/packages/elements/schematics/ng-add/index.ts b/packages/elements/schematics/ng-add/index.ts new file mode 100644 index 0000000000..6928e36383 --- /dev/null +++ b/packages/elements/schematics/ng-add/index.ts @@ -0,0 +1,76 @@ +/** + * @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 + */ +import {Rule, SchematicContext, Tree, chain, noop} from '@angular-devkit/schematics'; +import {NodePackageInstallTask} from '@angular-devkit/schematics/tasks'; +import {Schema} from './schema'; + +export default function(options: Schema): Rule { + return chain([ + options && options.skipPackageJson ? noop() : addPackageJsonDependency(), addScript(options) + ]); +} + +/** Adds a package.json dependency for document-register-element */ +function addPackageJsonDependency() { + return (host: Tree, context: SchematicContext) => { + + if (host.exists('package.json')) { + const jsonStr = host.read('package.json') !.toString('utf-8'); + const json = JSON.parse(jsonStr); + + // If there are no dependencies, create an entry for dependencies. + const type = 'dependencies'; + if (!json[type]) { + json[type] = {}; + } + + // If not already present, add the dependency. + const pkg = 'document-register-element'; + const version = '^1.7.2'; + if (!json[type][pkg]) { + json[type][pkg] = version; + } + + // Write the JSON back to package.json + host.overwrite('package.json', JSON.stringify(json, null, 2)); + context.logger.log('info', 'Added `document-register-element` as a dependency.'); + + // Install the dependency + context.addTask(new NodePackageInstallTask()); + } + + return host; + }; +} + +/** Adds the document-register-element.js script to the angular CLI json. */ +function addScript(options: Schema) { + return (host: Tree, context: SchematicContext) => { + const script = 'node_modules/document-register-element/build/document-register-element.js'; + + + try { + // Handle the new json - angular.json + const angularJsonFile = host.read('angular.json'); + if (angularJsonFile) { + const json = JSON.parse(angularJsonFile.toString('utf-8')); + const project = Object.keys(json['projects'])[0] || options.project; + const scripts = json['projects'][project]['architect']['build']['options']['scripts']; + scripts.push({input: script}); + host.overwrite('angular.json', JSON.stringify(json, null, 2)); + } + } catch (e) { + context.logger.log( + 'warn', 'Failed to add the polyfill document-register-element.js to scripts'); + } + + context.logger.log('info', 'Added document-register-element.js polyfill to scripts'); + + return host; + }; +} diff --git a/packages/elements/schematics/ng-add/index_spec.ts b/packages/elements/schematics/ng-add/index_spec.ts new file mode 100644 index 0000000000..1a4cf30a40 --- /dev/null +++ b/packages/elements/schematics/ng-add/index_spec.ts @@ -0,0 +1,58 @@ +/** + * @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 + */ +import {SchematicTestRunner, UnitTestTree} from '@angular-devkit/schematics/testing'; +import * as path from 'path'; +import {Observable} from 'rxjs'; +import {concatMap} from 'rxjs/operators'; + +import {Schema as ElementsOptions} from './schema'; + + +const polyfillPath = 'node_modules/document-register-element/build/document-register-element.js'; + +// tslint:disable:max-line-length +describe('Elements Schematics', () => { + const schematicRunner = new SchematicTestRunner( + '@angular/elements', path.join(__dirname, '../test-collection.json'), ); + const defaultOptions: ElementsOptions = {project: 'bar', skipPackageJson: false}; + + let appTree: UnitTestTree; + + // tslint:disable-next-line:no-any + const workspaceOptions: any = { + name: 'workspace', + newProjectRoot: 'projects', + version: '6.0.0', + }; + + // tslint:disable-next-line:no-any + const appOptions: any = { + name: 'elements', + inlineStyle: false, + inlineTemplate: false, + routing: false, + style: 'css', + skipTests: false, + }; + + beforeEach((done) => { + schematicRunner.runExternalSchematicAsync('@schematics/angular', 'workspace', workspaceOptions) + .pipe(concatMap( + (tree) => schematicRunner.runExternalSchematicAsync( + '@schematics/angular', 'application', appOptions, tree))) + .subscribe((tree: UnitTestTree) => appTree = tree, done.fail, done); + }); + + it('should run the ng-add schematic', () => { + const tree = schematicRunner.runSchematic('ng-add', defaultOptions, appTree); + const configText = tree.readContent('/angular.json'); + const config = JSON.parse(configText); + const scripts = config.projects.elements.architect.build.options.scripts; + expect(scripts[0].input).toEqual(polyfillPath); + }); +}); diff --git a/packages/elements/schematics/ng-add/schema.d.ts b/packages/elements/schematics/ng-add/schema.d.ts new file mode 100644 index 0000000000..224492cbb4 --- /dev/null +++ b/packages/elements/schematics/ng-add/schema.d.ts @@ -0,0 +1,11 @@ +export interface Schema { + /** + * Skip package.json install. + */ + skipPackageJson: boolean; + + /** + * The project that needs the polyfill scripts + */ + project: name; +} diff --git a/packages/tsconfig.json b/packages/tsconfig.json index a387a0595a..162991e17b 100644 --- a/packages/tsconfig.json +++ b/packages/tsconfig.json @@ -31,7 +31,8 @@ "bazel", "compiler-cli/integrationtest", "platform-server/integrationtest", - "common/locales" + "common/locales", + "elements/schematics" ] } diff --git a/tools/tslint/rollupConfigRule.ts b/tools/tslint/rollupConfigRule.ts index 19157b2a1f..44b508d24d 100644 --- a/tools/tslint/rollupConfigRule.ts +++ b/tools/tslint/rollupConfigRule.ts @@ -29,6 +29,7 @@ const sourceFilePathBlacklist = [ /[/\\]packages[/\\]bazel[/\\]/, /[/\\]packages[/\\]benchpress[/\\]/, /[/\\]packages[/\\]examples[/\\]/, + /[/\\]packages[/\\]elements[/\\]schematics[/\\]/, // language-service bundles everything in its UMD, so we don't need a globals. There are // exceptions but we simply ignore those files from this rule. diff --git a/yarn.lock b/yarn.lock index 9dc839fa6c..0f8efd552c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,10 +2,56 @@ # yarn lockfile v1 +"@angular-devkit/core@0.5.4": + version "0.5.4" + resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-0.5.4.tgz#94b7462f5039cf811c7e06db0c87bb2299d61c71" + dependencies: + ajv "~5.5.1" + chokidar "^1.7.0" + rxjs "^6.0.0-beta.3" + source-map "^0.5.6" + +"@angular-devkit/core@0.5.5": + version "0.5.5" + resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-0.5.5.tgz#659c9ef3f22c3e99c459e325441b1009412a4af6" + dependencies: + ajv "~5.5.1" + chokidar "^1.7.0" + rxjs "^6.0.0-beta.3" + source-map "^0.5.6" + +"@angular-devkit/schematics@0.5.4": + version "0.5.4" + resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-0.5.4.tgz#6a4b0abb30091fa1a5d0751737f9ed036ac8704f" + dependencies: + "@angular-devkit/core" "0.5.4" + "@ngtools/json-schema" "^1.1.0" + rxjs "^6.0.0-beta.3" + +"@angular-devkit/schematics@^0.5.5": + version "0.5.5" + resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-0.5.5.tgz#c0b20980993237f2eeb4182e253c7c9efa299f3b" + dependencies: + "@angular-devkit/core" "0.5.5" + "@ngtools/json-schema" "^1.1.0" + rxjs "^6.0.0-beta.3" + "@bazel/ibazel@^0.1.1": version "0.1.1" resolved "https://registry.yarnpkg.com/@bazel/ibazel/-/ibazel-0.1.1.tgz#f970c08b4e4efb0ab17e04ade3cc610554f33bed" +"@ngtools/json-schema@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@ngtools/json-schema/-/json-schema-1.1.0.tgz#c3a0c544d62392acc2813a42c8a0dc6f58f86922" + +"@schematics/angular@^0.5.4": + version "0.5.4" + resolved "https://registry.yarnpkg.com/@schematics/angular/-/angular-0.5.4.tgz#1c87706703a985fd291d283a4db1a9fc0aa6238f" + dependencies: + "@angular-devkit/core" "0.5.4" + "@angular-devkit/schematics" "0.5.4" + typescript "~2.6.2" + "@types/angularjs@1.5.14-alpha": version "1.5.14-alpha" resolved "https://registry.yarnpkg.com/@types/angularjs/-/angularjs-1.5.14-alpha.tgz#2add80c88e1d84ade07e042918843093b6ac9808" @@ -177,6 +223,15 @@ ajv@^5.1.0: json-schema-traverse "^0.3.0" json-stable-stringify "^1.0.1" +ajv@~5.5.1: + version "5.5.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965" + dependencies: + co "^4.6.0" + fast-deep-equal "^1.0.0" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.3.0" + align-text@^0.1.1, align-text@^0.1.3: version "0.1.4" resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117" @@ -840,7 +895,7 @@ chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3: strip-ansi "^3.0.0" supports-color "^2.0.0" -chokidar@1.7.0, chokidar@^1.0.0, chokidar@^1.4.1: +chokidar@1.7.0, chokidar@^1.0.0, chokidar@^1.4.1, chokidar@^1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468" dependencies: @@ -2030,6 +2085,10 @@ fast-deep-equal@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz#96256a3bc975595eb36d82e9929d060d893439ff" +fast-json-stable-stringify@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" + faye-websocket@~0.10.0: version "0.10.0" resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.10.0.tgz#4e492f8d04dfb6f89003507f6edbf2d501e7c6f4" @@ -5083,6 +5142,12 @@ rollup@0.47.4: version "0.47.4" resolved "https://registry.yarnpkg.com/rollup/-/rollup-0.47.4.tgz#e3a55de83a78221d232ce29619a8d68189ae845e" +rxjs@^6.0.0-beta.3: + version "6.0.0-tactical-rc.1" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.0.0-tactical-rc.1.tgz#1fe1f1204132d1c71c72f249a487f8e76a5ec1d5" + dependencies: + tslib "^1.9.0" + rxjs@^6.0.0-terrific-rc.3: version "6.0.0-terrific-rc.3" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.0.0-terrific-rc.3.tgz#3acee937c1789ee4addf3cc3f7cc843d7cc2887c" @@ -5928,6 +5993,10 @@ typescript@2.7.x: version "2.7.2" resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.7.2.tgz#2d615a1ef4aee4f574425cdff7026edf81919836" +typescript@~2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.6.2.tgz#3c5b6fd7f6de0914269027f03c0946758f7673a4" + uglify-es@^3.3.9: version "3.3.9" resolved "https://registry.yarnpkg.com/uglify-es/-/uglify-es-3.3.9.tgz#0c1c4f0700bed8dbc124cdb304d2592ca203e677"