diff --git a/package.json b/package.json index a859c6cc22..6427fd2344 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,6 @@ "// 1": "dependencies are used locally and by bazel", "dependencies": { "@angular/cli": "12.0.0-next.7", - "@angular-devkit/architect": "0.1200.0-next.7", "@angular-devkit/build-angular": "github:angular/angular-devkit-build-angular-builds#e0c1374b12cfc892844030431bc19f631c0086a5", "@angular-devkit/build-optimizer": "0.1200.0-next.7", "@angular-devkit/core": "12.0.0-next.7", diff --git a/packages/bazel/BUILD.bazel b/packages/bazel/BUILD.bazel index f5b10a87c9..89ee85b4a4 100644 --- a/packages/bazel/BUILD.bazel +++ b/packages/bazel/BUILD.bazel @@ -13,9 +13,6 @@ pkg_npm( "//packages/bazel/src/ngc-wrapped:package_assets", "//packages/bazel/third_party/github.com/bazelbuild/bazel/src/main/protobuf:package_assets", ], - nested_packages = [ - "//packages/bazel/docs", - ], substitutions = { "(#|//)\\s+BEGIN-DEV-ONLY[\\w\\W]+?(#|//)\\s+END-DEV-ONLY": "", "//packages/bazel/": "//@angular/bazel/", diff --git a/packages/bazel/src/schematics/README.md b/packages/bazel/docs/BAZEL_SCHEMATICS.md similarity index 96% rename from packages/bazel/src/schematics/README.md rename to packages/bazel/docs/BAZEL_SCHEMATICS.md index 657d3d2f46..37e76ef8c3 100644 --- a/packages/bazel/src/schematics/README.md +++ b/packages/bazel/docs/BAZEL_SCHEMATICS.md @@ -45,7 +45,7 @@ This new rule leverages ngtsc plugin supported by `ts_library`, and it is much f For the latest recommendations, please refer to the canonical Angular Bazel [repo](https://github.com/bazelbuild/rules_nodejs/tree/master/examples/angular). -For questions, please ask in the `#angular` channel in https://slack.bazel.build/. +For questions, please ask in the `#angular` channel in http://slack.bazel.build/. ## Angular CLI diff --git a/packages/bazel/docs/BUILD.bazel b/packages/bazel/docs/BUILD.bazel deleted file mode 100644 index 55b84494d8..0000000000 --- a/packages/bazel/docs/BUILD.bazel +++ /dev/null @@ -1,13 +0,0 @@ -load("@io_bazel_skydoc//skylark:skylark.bzl", "skylark_doc") - -skylark_doc( - name = "docs", - srcs = [ - "//packages/bazel/src:ng_module.bzl", - "//packages/bazel/src/ng_package:ng_package.bzl", - ], - format = "html", - site_root = "/bazel-builds", - strip_prefix = "packages/bazel/", - visibility = ["//packages/bazel:__subpackages__"], -) diff --git a/packages/bazel/src/builders/bazel.ts b/packages/bazel/src/builders/bazel.ts deleted file mode 100644 index c309914196..0000000000 --- a/packages/bazel/src/builders/bazel.ts +++ /dev/null @@ -1,200 +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 - */ - -/// - -import {spawn} from 'child_process'; -import {copyFileSync, existsSync, readdirSync, readFileSync, statSync, unlinkSync, writeFileSync} from 'fs'; -import {platform} from 'os'; -import {dirname, join, normalize} from 'path'; - -export type Executable = 'bazel'|'ibazel'; -export type Command = 'build'|'test'|'run'|'coverage'|'query'; - -/** - * Spawn the Bazel process. Trap SINGINT to make sure Bazel process is killed. - */ -export function runBazel( - projectDir: string, binary: string, command: Command, workspaceTarget: string, - flags: string[]) { - projectDir = normalize(projectDir); - binary = normalize(binary); - return new Promise((resolve, reject) => { - const buildProcess = spawn(binary, [command, workspaceTarget, ...flags], { - cwd: projectDir, - stdio: 'inherit', - }); - - process.on('SIGINT', (signal) => { - if (!buildProcess.killed) { - buildProcess.kill(); - reject(new Error(`Bazel process received ${signal}.`)); - } - }); - - buildProcess.once('close', (code: number) => { - if (code === 0) { - resolve(); - } else { - reject(new Error(`${binary} failed with code ${code}.`)); - } - }); - }); -} - -/** - * Resolves the path to `@bazel/bazel` or `@bazel/ibazel`. - */ -export function checkInstallation(name: Executable, projectDir: string): string { - projectDir = normalize(projectDir); - const packageName = `@bazel/${name}`; - try { - const bazelPath = require.resolve(packageName, { - paths: [projectDir], - }); - return require(bazelPath).getNativeBinary(); - } catch (error) { - if (error.code === 'MODULE_NOT_FOUND') { - throw new Error( - `Could not run ${name}. Please make sure that the ` + - `"${name}" command is installed by running ` + - `"npm install ${packageName}" or "yarn install ${packageName}".`); - } - throw error; - } -} - -/** - * Returns the absolute path to the template directory in `@angular/bazel`. - */ -export function getTemplateDir(root: string): string { - root = normalize(root); - const packageJson = require.resolve('@angular/bazel/package.json', { - paths: [root], - }); - const packageDir = dirname(packageJson); - const templateDir = join(packageDir, 'src', 'builders', 'files'); - if (!statSync(templateDir).isDirectory()) { - throw new Error('Could not find Bazel template directory in "@angular/bazel".'); - } - return templateDir; -} - -/** - * Recursively list the specified 'dir' using depth-first approach. Paths - * returned are relative to 'dir'. - */ -function listR(dir: string): string[] { - function list(dir: string, root: string, results: string[]) { - const paths = readdirSync(dir); - for (const path of paths) { - const absPath = join(dir, path); - const relPath = join(root, path); - if (statSync(absPath).isFile()) { - results.push(relPath); - } else { - list(absPath, relPath, results); - } - } - return results; - } - - return list(dir, '', []); -} - -/** - * Return the name of the lock file that is present in the specified 'root' - * directory. If none exists, default to creating an empty yarn.lock file. - */ -function getOrCreateLockFile(root: string): 'yarn.lock'|'package-lock.json' { - const yarnLock = join(root, 'yarn.lock'); - if (existsSync(yarnLock)) { - return 'yarn.lock'; - } - const npmLock = join(root, 'package-lock.json'); - if (existsSync(npmLock)) { - return 'package-lock.json'; - } - // Prefer yarn if no lock file exists - writeFileSync(yarnLock, ''); - return 'yarn.lock'; -} - -// Replace yarn_install rule with npm_install and copy from 'source' to 'dest'. -function replaceYarnWithNpm(source: string, dest: string) { - const srcContent = readFileSync(source, 'utf-8'); - const destContent = srcContent.replace(/yarn_install/g, 'npm_install') - .replace('yarn_lock', 'package_lock_json') - .replace('yarn.lock', 'package-lock.json'); - writeFileSync(dest, destContent); -} - -/** - * Disable sandbox on Mac OS by setting spawn_strategy in .bazelrc. - * For a hello world (ng new) application, removing the sandbox improves build - * time by almost 40%. - * ng build with sandbox: 22.0 seconds - * ng build without sandbox: 13.3 seconds - */ -function disableSandbox(source: string, dest: string) { - const srcContent = readFileSync(source, 'utf-8'); - const destContent = `${srcContent} -# Disable sandbox on Mac OS for performance reason. -build --spawn_strategy=local -run --spawn_strategy=local -test --spawn_strategy=local -`; - writeFileSync(dest, destContent); -} - -/** - * Copy Bazel files (WORKSPACE, BUILD.bazel, etc) from the template directory to - * the project `root` directory, and return the absolute paths of the files - * copied, so that they can be deleted later. - * Existing files in `root` will not be replaced. - */ -export function copyBazelFiles(root: string, templateDir: string) { - root = normalize(root); - templateDir = normalize(templateDir); - const bazelFiles: string[] = []; - const templates = listR(templateDir); - const useYarn = getOrCreateLockFile(root) === 'yarn.lock'; - - for (const template of templates) { - const name = template.replace('__dot__', '.').replace('.template', ''); - const source = join(templateDir, template); - const dest = join(root, name); - try { - if (!existsSync(dest)) { - if (!useYarn && name === 'WORKSPACE') { - replaceYarnWithNpm(source, dest); - } else if (platform() === 'darwin' && name === '.bazelrc') { - disableSandbox(source, dest); - } else { - copyFileSync(source, dest); - } - bazelFiles.push(dest); - } - } catch { - } - } - - return bazelFiles; -} - -/** - * Delete the specified 'files'. This function never throws. - */ -export function deleteBazelFiles(files: string[]) { - for (const file of files) { - try { - unlinkSync(file); - } catch { - } - } -} diff --git a/packages/bazel/src/builders/index.ts b/packages/bazel/src/builders/index.ts deleted file mode 100644 index f0218c1cd4..0000000000 --- a/packages/bazel/src/builders/index.ts +++ /dev/null @@ -1,41 +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 - * - * @fileoverview Bazel builder - */ - -import {BuilderContext, BuilderOutput, createBuilder,} from '@angular-devkit/architect'; -import {JsonObject} from '@angular-devkit/core'; -import {checkInstallation, copyBazelFiles, deleteBazelFiles, getTemplateDir, runBazel} from './bazel'; -import {Schema} from './schema'; - -async function _bazelBuilder( - options: JsonObject&Schema, - context: BuilderContext, - ): Promise { - const {logger, workspaceRoot} = context; - const {bazelCommand, leaveBazelFilesOnDisk, targetLabel, watch} = options; - const executable = watch ? 'ibazel' : 'bazel'; - const binary = checkInstallation(executable, workspaceRoot); - const templateDir = getTemplateDir(workspaceRoot); - const bazelFiles = copyBazelFiles(workspaceRoot, templateDir); - - try { - const flags: string[] = []; - await runBazel(workspaceRoot, binary, bazelCommand, targetLabel, flags); - return {success: true}; - } catch (err) { - logger.error(err.message); - return {success: false}; - } finally { - if (!leaveBazelFilesOnDisk) { - deleteBazelFiles(bazelFiles); // this will never throw - } - } -} - -export default createBuilder(_bazelBuilder); diff --git a/packages/bazel/src/builders/schema.d.ts b/packages/bazel/src/builders/schema.d.ts deleted file mode 100644 index 7dc3de1311..0000000000 --- a/packages/bazel/src/builders/schema.d.ts +++ /dev/null @@ -1,38 +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 - */ - -/** - * Options for Bazel Builder - */ -export interface Schema { - /** - * Common commands supported by Bazel. - */ - bazelCommand: BazelCommand; - /** - * If true, leave Bazel files on disk after running command. - */ - leaveBazelFilesOnDisk?: boolean; - /** - * Target to be executed under Bazel. - */ - targetLabel: string; - /** - * If true, watch the filesystem using ibazel. - */ - watch?: boolean; -} - -/** - * Common commands supported by Bazel. - */ -export enum BazelCommand { - Build = 'build', - Run = 'run', - Test = 'test', -} diff --git a/packages/bazel/src/schematics/ng-add/index.ts b/packages/bazel/src/schematics/ng-add/index.ts deleted file mode 100644 index f381a606e1..0000000000 --- a/packages/bazel/src/schematics/ng-add/index.ts +++ /dev/null @@ -1,357 +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 - * - * @fileoverview Schematics for ng-new project that builds with Bazel. - */ - -import {JsonAstObject, parseJsonAst} from '@angular-devkit/core'; -import {apply, applyTemplates, chain, mergeWith, Rule, SchematicContext, SchematicsException, Tree, url} from '@angular-devkit/schematics'; -import {NodePackageInstallTask} from '@angular-devkit/schematics/tasks'; -import {getWorkspace, getWorkspacePath} from '@schematics/angular/utility/config'; -import {addPackageJsonDependency, getPackageJsonDependency, NodeDependencyType, removePackageJsonDependency} from '@schematics/angular/utility/dependencies'; -import {findPropertyInAstObject, insertPropertyInAstObjectInOrder} from '@schematics/angular/utility/json-utils'; -import {validateProjectName} from '@schematics/angular/utility/validation'; - -import {isJsonAstObject, replacePropertyInAstObject} from '../utility/json-utils'; -import {findE2eArchitect} from '../utility/workspace-utils'; - -import {Schema} from './schema'; - - - -/** - * Packages that build under Bazel require additional dev dependencies. This - * function adds those dependencies to "devDependencies" section in - * package.json. - */ -function addDevDependenciesToPackageJson(options: Schema) { - return (host: Tree) => { - const angularCore = getPackageJsonDependency(host, '@angular/core'); - if (!angularCore) { - throw new Error('@angular/core dependency not found in package.json'); - } - - // TODO: use a Record when the tsc lib setting allows us - const devDependencies: [string, string][] = [ - ['@angular/bazel', angularCore.version], - ['@bazel/bazel', '2.1.0'], - ['@bazel/ibazel', '0.12.3'], - ['@bazel/karma', '1.6.0'], - ['@bazel/protractor', '1.6.0'], - ['@bazel/rollup', '1.6.0'], - ['@bazel/terser', '1.6.0'], - ['@bazel/typescript', '1.6.0'], - ['history-server', '1.3.1'], - ['html-insert-assets', '0.5.0'], - ['karma', '4.4.1'], - ['karma-chrome-launcher', '3.1.0'], - ['karma-firefox-launcher', '1.2.0'], - ['karma-jasmine', '2.0.1'], - ['karma-requirejs', '1.1.0'], - ['karma-sourcemap-loader', '0.3.7'], - ['protractor', '5.4.2'], - ['requirejs', '2.3.6'], - ['rollup', '1.27.5'], - ['rollup-plugin-commonjs', '10.1.0'], - ['rollup-plugin-node-resolve', '5.2.0'], - ['terser', '4.4.0'], - ]; - - for (const [name, version] of devDependencies) { - const dep = getPackageJsonDependency(host, name); - if (dep && dep.type !== NodeDependencyType.Dev) { - removePackageJsonDependency(host, name); - } - - addPackageJsonDependency(host, { - name, - version, - type: NodeDependencyType.Dev, - overwrite: true, - }); - } - }; -} - -/** - * Remove packages that are not needed under Bazel. - * @param options - */ -function removeObsoleteDependenciesFromPackageJson(options: Schema) { - return (host: Tree) => { - const depsToRemove = [ - '@angular-devkit/build-angular', - ]; - - for (const packageName of depsToRemove) { - removePackageJsonDependency(host, packageName); - } - }; -} - -/** - * Append additional Javascript / Typescript files needed to compile an Angular - * project under Bazel. - */ -function addFilesRequiredByBazel(options: Schema) { - return (host: Tree) => { - return mergeWith(apply(url('./files'), [ - applyTemplates({}), - ])); - }; -} - -/** - * Append '/bazel-out' to the gitignore file. - */ -function updateGitignore() { - return (host: Tree) => { - const gitignore = '/.gitignore'; - if (!host.exists(gitignore)) { - return host; - } - const gitIgnoreContentRaw = host.read(gitignore); - if (!gitIgnoreContentRaw) { - return host; - } - const gitIgnoreContent = gitIgnoreContentRaw.toString(); - if (gitIgnoreContent.includes('\n/bazel-out\n')) { - return host; - } - const compiledOutput = '# compiled output\n'; - const index = gitIgnoreContent.indexOf(compiledOutput); - const insertionIndex = index >= 0 ? index + compiledOutput.length : gitIgnoreContent.length; - const recorder = host.beginUpdate(gitignore); - recorder.insertRight(insertionIndex, '/bazel-out\n'); - host.commitUpdate(recorder); - return host; - }; -} - -/** - * Change the architect in angular.json to use Bazel builder. - */ -function updateAngularJsonToUseBazelBuilder(options: Schema): Rule { - return (host: Tree) => { - const name = options.name!; - const workspacePath = getWorkspacePath(host); - if (!workspacePath) { - throw new Error('Could not find angular.json'); - } - const workspaceContent = host.read(workspacePath); - if (!workspaceContent) { - throw new Error('Failed to read angular.json content'); - } - const workspaceJsonAst = parseJsonAst(workspaceContent.toString()) as JsonAstObject; - const projects = findPropertyInAstObject(workspaceJsonAst, 'projects'); - if (!projects) { - throw new SchematicsException('Expect projects in angular.json to be an Object'); - } - const project = findPropertyInAstObject(projects as JsonAstObject, name); - if (!project) { - throw new SchematicsException(`Expected projects to contain ${name}`); - } - const recorder = host.beginUpdate(workspacePath); - const indent = 8; - const architect = - findPropertyInAstObject(project as JsonAstObject, 'architect') as JsonAstObject; - replacePropertyInAstObject( - recorder, architect, 'build', { - builder: '@angular/bazel:build', - options: { - targetLabel: '//src:prodapp', - bazelCommand: 'build', - }, - configurations: { - production: { - targetLabel: '//src:prodapp', - }, - }, - }, - indent); - replacePropertyInAstObject( - recorder, architect, 'serve', { - builder: '@angular/bazel:build', - options: { - targetLabel: '//src:devserver', - bazelCommand: 'run', - watch: true, - }, - configurations: { - production: { - targetLabel: '//src:prodserver', - }, - }, - }, - indent); - - if (findPropertyInAstObject(architect, 'test')) { - replacePropertyInAstObject( - recorder, architect, 'test', { - builder: '@angular/bazel:build', - options: { - bazelCommand: 'test', - targetLabel: '//src:test', - }, - }, - indent); - } - - const e2eArchitect = findE2eArchitect(workspaceJsonAst, name); - if (e2eArchitect && findPropertyInAstObject(e2eArchitect, 'e2e')) { - replacePropertyInAstObject( - recorder, e2eArchitect, 'e2e', { - builder: '@angular/bazel:build', - options: { - bazelCommand: 'test', - targetLabel: '//e2e:devserver_test', - }, - configurations: { - production: { - targetLabel: '//e2e:prodserver_test', - }, - } - }, - indent); - } - - host.commitUpdate(recorder); - return host; - }; -} - -/** - * Create a backup for the original angular.json file in case user wants to - * eject Bazel and revert to the original workflow. - */ -function backupAngularJson(): Rule { - return (host: Tree, context: SchematicContext) => { - const workspacePath = getWorkspacePath(host); - if (!workspacePath) { - return; - } - host.create( - `${workspacePath}.bak`, - '// This is a backup file of the original angular.json. ' + - 'This file is needed in case you want to revert to the workflow without Bazel.\n\n' + - host.read(workspacePath)); - }; -} - -/** - * @angular/bazel requires minimum version of rxjs to be 6.4.0. This function - * upgrades the version of rxjs in package.json if necessary. - */ -function upgradeRxjs() { - return (host: Tree, context: SchematicContext) => { - const rxjsNode = getPackageJsonDependency(host, 'rxjs'); - if (!rxjsNode) { - throw new Error(`Failed to find rxjs dependency.`); - } - - const match = rxjsNode.version.match(/(\d)+\.(\d)+.(\d)+$/); - if (match) { - const [_, major, minor] = match; - if (major < '6' || (major === '6' && minor < '5')) { - addPackageJsonDependency(host, { - ...rxjsNode, - version: '~6.5.3', - overwrite: true, - }); - } - } else { - context.logger.info( - 'Could not determine version of rxjs. \n' + - 'Please make sure that version is at least 6.5.3.'); - } - return host; - }; -} - -/** - * When using Ivy, ngcc must be run as a postinstall step. - * This function adds this postinstall step. - */ -function addPostinstallToRunNgcc() { - return (host: Tree, context: SchematicContext) => { - const packageJson = 'package.json'; - if (!host.exists(packageJson)) { - throw new Error(`Could not find ${packageJson}`); - } - const content = host.read(packageJson); - if (!content) { - throw new Error('Failed to read package.json content'); - } - const jsonAst = parseJsonAst(content.toString()); - if (!isJsonAstObject(jsonAst)) { - throw new Error(`Failed to parse JSON for ${packageJson}`); - } - const scripts = findPropertyInAstObject(jsonAst, 'scripts') as JsonAstObject; - const recorder = host.beginUpdate(packageJson); - // For bazel we need to compile the all files in place so we - // don't use `--first-only` or `--create-ivy-entry-points` - const ngccCommand = 'ngcc --properties es2015 browser module main'; - if (scripts) { - const postInstall = findPropertyInAstObject(scripts, 'postinstall'); - if (postInstall && postInstall.value) { - let value = postInstall.value as string; - if (/\bngcc\b/.test(value)) { - // `ngcc` is already in the postinstall script - value = - value.replace(/\s*--first-only\b/, '').replace(/\s*--create-ivy-entry-points\b/, ''); - replacePropertyInAstObject(recorder, scripts, 'postinstall', value); - } else { - const command = `${postInstall.value}; ${ngccCommand}`; - replacePropertyInAstObject(recorder, scripts, 'postinstall', command); - } - } else { - insertPropertyInAstObjectInOrder(recorder, scripts, 'postinstall', ngccCommand, 4); - } - } else { - insertPropertyInAstObjectInOrder( - recorder, jsonAst, 'scripts', { - postinstall: ngccCommand, - }, - 2); - } - host.commitUpdate(recorder); - return host; - }; -} - -/** - * Schedule a task to perform npm / yarn install. - */ -function installNodeModules(options: Schema): Rule { - return (host: Tree, context: SchematicContext) => { - if (!options.skipInstall) { - context.addTask(new NodePackageInstallTask()); - } - }; -} - -export default function(options: Schema): Rule { - return (host: Tree) => { - options.name = options.name || getWorkspace(host).defaultProject; - if (!options.name) { - throw new Error('Please specify a project using "--name project-name"'); - } - validateProjectName(options.name); - - return chain([ - addFilesRequiredByBazel(options), - addDevDependenciesToPackageJson(options), - removeObsoleteDependenciesFromPackageJson(options), - addPostinstallToRunNgcc(), - backupAngularJson(), - updateAngularJsonToUseBazelBuilder(options), - updateGitignore(), - upgradeRxjs(), - installNodeModules(options), - ]); - }; -} diff --git a/packages/bazel/src/schematics/ng-add/index_spec.ts b/packages/bazel/src/schematics/ng-add/index_spec.ts deleted file mode 100644 index d751890774..0000000000 --- a/packages/bazel/src/schematics/ng-add/index_spec.ts +++ /dev/null @@ -1,340 +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 - */ - -import {HostTree} from '@angular-devkit/schematics'; -import {SchematicTestRunner, UnitTestTree} from '@angular-devkit/schematics/testing'; - -describe('ng-add schematic', () => { - const defaultOptions = {name: 'demo'}; - let host: UnitTestTree; - let schematicRunner: SchematicTestRunner; - - beforeEach(() => { - host = new UnitTestTree(new HostTree()); - host.create('package.json', JSON.stringify({ - name: 'demo', - dependencies: { - '@angular/core': '1.2.3', - 'rxjs': '~6.3.3', - }, - devDependencies: { - 'typescript': '3.2.2', - }, - })); - host.create('tsconfig.json', JSON.stringify({ - compileOnSave: false, - compilerOptions: { - baseUrl: './', - outDir: './dist/out-tsc', - } - })); - host.create('angular.json', JSON.stringify({ - projects: { - 'demo': { - architect: { - build: {}, - serve: {}, - test: {}, - 'extract-i18n': { - builder: '@angular-devkit/build-angular:extract-i18n', - }, - }, - }, - 'demo-e2e': { - architect: { - e2e: {}, - lint: { - builder: '@angular-devkit/build-angular:tslint', - }, - }, - }, - }, - defaultProject: 'demo', - })); - schematicRunner = - new SchematicTestRunner('@angular/bazel', require.resolve('../collection.json')); - }); - - it('throws if package.json is not found', async () => { - expect(host.files).toContain('/package.json'); - host.delete('/package.json'); - - let message = 'No error'; - - try { - await schematicRunner.runSchematicAsync('ng-add', defaultOptions).toPromise(); - } catch (e) { - message = e.message; - } - - expect(message).toBe('Could not read package.json.'); - }); - - it('throws if angular.json is not found', async () => { - expect(host.files).toContain('/angular.json'); - host.delete('/angular.json'); - - let message = 'No error'; - - try { - await schematicRunner.runSchematicAsync('ng-add', defaultOptions, host).toPromise(); - } catch (e) { - message = e.message; - } - - expect(message).toBe('Could not find angular.json'); - }); - - it('should add @angular/bazel to package.json dependencies', async () => { - host = await schematicRunner.runSchematicAsync('ng-add', defaultOptions, host).toPromise(); - const {files} = host; - expect(files).toContain('/package.json'); - const content = host.readContent('/package.json'); - expect(() => JSON.parse(content)).not.toThrow(); - const json = JSON.parse(content); - const core = '@angular/core'; - const bazel = '@angular/bazel'; - expect(Object.keys(json)).toContain('dependencies'); - expect(Object.keys(json)).toContain('devDependencies'); - expect(Object.keys(json.dependencies)).toContain(core); - expect(Object.keys(json.devDependencies)).toContain(bazel); - }); - - it('should add @bazel/* dev dependencies', async () => { - host = await schematicRunner.runSchematicAsync('ng-add', defaultOptions, host).toPromise(); - const content = host.readContent('/package.json'); - const json = JSON.parse(content); - const devDeps = Object.keys(json.devDependencies); - expect(devDeps).toContain('@bazel/bazel'); - expect(devDeps).toContain('@bazel/ibazel'); - expect(devDeps).toContain('@bazel/karma'); - expect(devDeps).toContain('@bazel/protractor'); - expect(devDeps).toContain('@bazel/typescript'); - }); - - it('should replace an existing dev dependency', async () => { - expect(host.files).toContain('/package.json'); - const packageJson = JSON.parse(host.readContent('/package.json')); - packageJson.devDependencies['@angular/bazel'] = '4.2.42'; - host.overwrite('/package.json', JSON.stringify(packageJson)); - host = await schematicRunner.runSchematicAsync('ng-add', defaultOptions, host).toPromise(); - const content = host.readContent('/package.json'); - // It is possible that a dep gets added twice if the package already exists. - expect(content.match(/@angular\/bazel/g)!.length).toEqual(1); - const json = JSON.parse(content); - expect(json.devDependencies['@angular/bazel']).toBe('1.2.3'); - }); - - it('should remove an existing dependency', async () => { - expect(host.files).toContain('/package.json'); - const packageJson = JSON.parse(host.readContent('/package.json')); - packageJson.dependencies['@angular/bazel'] = '4.2.42'; - expect(Object.keys(packageJson.dependencies)).toContain('@angular/bazel'); - host.overwrite('/package.json', JSON.stringify(packageJson)); - host = await schematicRunner.runSchematicAsync('ng-add', defaultOptions, host).toPromise(); - const content = host.readContent('/package.json'); - const json = JSON.parse(content); - expect(Object.keys(json.dependencies)).not.toContain('@angular/bazel'); - expect(json.devDependencies['@angular/bazel']).toBe('1.2.3'); - }); - - it('should remove unneeded dependencies', async () => { - const packageJson = JSON.parse(host.readContent('/package.json')); - packageJson.devDependencies['@angular-devkit/build-angular'] = '1.2.3'; - host.overwrite('/package.json', JSON.stringify(packageJson)); - host = await schematicRunner.runSchematicAsync('ng-add', defaultOptions, host).toPromise(); - const content = host.readContent('/package.json'); - const json = JSON.parse(content); - expect(json.devDependencies['angular-devkit/build-angular']).toBeUndefined(); - }); - - it('should append to scripts.postinstall if it already exists', async () => { - const packageJson = JSON.parse(host.readContent('/package.json')); - packageJson['scripts'] = { - postinstall: 'angular rocks', - }; - host.overwrite('/package.json', JSON.stringify(packageJson)); - host = await schematicRunner.runSchematicAsync('ng-add', defaultOptions, host).toPromise(); - const content = host.readContent('/package.json'); - const json = JSON.parse(content); - expect(json.scripts['postinstall']) - .toBe('angular rocks; ngcc --properties es2015 browser module main'); - }); - - it('should update ngcc in scripts.postinstall if it already exists', async () => { - const packageJson = JSON.parse(host.readContent('/package.json')); - packageJson['scripts'] = { - postinstall: - 'ngcc --properties es2015 browser module main --first-only --create-ivy-entry-points', - }; - host.overwrite('/package.json', JSON.stringify(packageJson)); - host = await schematicRunner.runSchematicAsync('ng-add', defaultOptions, host).toPromise(); - const content = host.readContent('/package.json'); - const json = JSON.parse(content); - expect(json.scripts['postinstall']).toBe('ngcc --properties es2015 browser module main'); - }); - - it('should not create Bazel workspace file', async () => { - host = await schematicRunner.runSchematicAsync('ng-add', defaultOptions, host).toPromise(); - const {files} = host; - expect(files).not.toContain('/WORKSPACE'); - expect(files).not.toContain('/BUILD.bazel'); - }); - - it('should produce main.dev.ts and main.prod.ts for AOT', async () => { - host.create('/src/main.ts', 'generated by CLI'); - host = await schematicRunner.runSchematicAsync('ng-add', defaultOptions, host).toPromise(); - const {files} = host; - // main.dev.ts and main.prod.ts are used by Bazel for AOT - expect(files).toContain('/src/main.dev.ts'); - expect(files).toContain('/src/main.prod.ts'); - // main.ts is produced by original ng-add schematics - // This file should be present for backwards compatibility. - expect(files).toContain('/src/main.ts'); - }); - - it('should not overwrite index.html with script tags', async () => { - host.create('/src/index.html', 'Hello World'); - host = await schematicRunner.runSchematicAsync('ng-add', defaultOptions, host).toPromise(); - const {files} = host; - expect(files).toContain('/src/index.html'); - const content = host.readContent('/src/index.html'); - expect(content).not.toMatch(''); - expect(content).not.toMatch(''); - }); - - it('should generate main.dev.ts and main.prod.ts', async () => { - host = await schematicRunner.runSchematicAsync('ng-add', defaultOptions, host).toPromise(); - const {files} = host; - expect(files).toContain('/src/main.dev.ts'); - expect(files).toContain('/src/main.prod.ts'); - }); - - it('should overwrite .gitignore for bazel-out directory', async () => { - host.create('.gitignore', '\n# compiled output\n'); - host = await schematicRunner.runSchematicAsync('ng-add', defaultOptions, host).toPromise(); - const {files} = host; - expect(files).toContain('/.gitignore'); - const content = host.readContent('/.gitignore'); - expect(content).toMatch('\n# compiled output\n/bazel-out\n'); - }); - - it('should create a backup for original angular.json', async () => { - expect(host.files).toContain('/angular.json'); - const original = host.readContent('/angular.json'); - host = await schematicRunner.runSchematicAsync('ng-add', defaultOptions, host).toPromise(); - expect(host.files).toContain('/angular.json.bak'); - const content = host.readContent('/angular.json.bak'); - expect(content.startsWith('// This is a backup file')).toBe(true); - expect(content).toMatch(original); - }); - - it('should update angular.json to use Bazel builder', async () => { - host = await schematicRunner.runSchematicAsync('ng-add', defaultOptions, host).toPromise(); - const {files} = host; - expect(files).toContain('/angular.json'); - const content = host.readContent('/angular.json'); - expect(() => JSON.parse(content)).not.toThrow(); - const json = JSON.parse(content); - const demo = json.projects.demo; - const demo_e2e = json.projects['demo-e2e']; - const {build, serve, test} = demo.architect; - expect(build.builder).toBe('@angular/bazel:build'); - expect(serve.builder).toBe('@angular/bazel:build'); - expect(test.builder).toBe('@angular/bazel:build'); - const {e2e, lint} = demo_e2e.architect; - expect(e2e.builder).toBe('@angular/bazel:build'); - // it should leave non-Bazel commands unmodified - expect(demo.architect['extract-i18n'].builder) - .toBe('@angular-devkit/build-angular:extract-i18n'); - expect(lint.builder).toBe('@angular-devkit/build-angular:tslint'); - }); - - it('should get defaultProject if name is not provided', async () => { - const options = {}; - host = await schematicRunner.runSchematicAsync('ng-add', options, host).toPromise(); - const content = host.readContent('/angular.json'); - const json = JSON.parse(content); - const builder = json.projects.demo.architect.build.builder; - expect(builder).toBe('@angular/bazel:build'); - }); - - describe('rxjs', () => { - const cases = [ - // version|upgrade - ['6.3.3', true], - ['~6.3.3', true], - ['^6.3.3', true], - ['~6.3.11', true], - ['6.4.0', true], - ['~6.4.0', true], - ['~6.4.1', true], - ['6.5.0', false], - ['~6.5.0', false], - ['^6.5.0', false], - ['~7.0.1', false], - ]; - for (const [version, upgrade] of cases) { - it(`should ${upgrade ? '' : 'not '}upgrade v${version}')`, async () => { - host.overwrite('package.json', JSON.stringify({ - name: 'demo', - dependencies: { - '@angular/core': '1.2.3', - 'rxjs': version, - }, - devDependencies: { - 'typescript': '3.2.2', - }, - })); - host = await schematicRunner.runSchematicAsync('ng-add', defaultOptions, host).toPromise(); - expect(host.files).toContain('/package.json'); - const content = host.readContent('/package.json'); - const json = JSON.parse(content); - if (upgrade) { - expect(json.dependencies.rxjs).toBe('~6.5.3'); - } else { - expect(json.dependencies.rxjs).toBe(version); - } - }); - } - }); - - it('should add a postinstall step to package.json', async () => { - host = await schematicRunner.runSchematicAsync('ng-add', defaultOptions, host).toPromise(); - expect(host.files).toContain('/package.json'); - const content = host.readContent('/package.json'); - const json = JSON.parse(content); - expect(json.scripts.postinstall).toBe('ngcc --properties es2015 browser module main'); - }); - - it('should work when run on a minimal project (without test and e2e targets)', async () => { - host.overwrite('angular.json', JSON.stringify({ - projects: { - 'demo': { - architect: { - build: {}, - serve: {}, - 'extract-i18n': { - builder: '@angular-devkit/build-angular:extract-i18n', - }, - }, - }, - }, - })); - - let error: Error|null = null; - - try { - await schematicRunner.runSchematicAsync('ng-add', defaultOptions, host).toPromise(); - } catch (e) { - error = e; - } - - expect(error).toBeNull(); - }); -}); diff --git a/packages/bazel/src/schematics/ng-add/schema.d.ts b/packages/bazel/src/schematics/ng-add/schema.d.ts deleted file mode 100644 index 9fa5a4be2b..0000000000 --- a/packages/bazel/src/schematics/ng-add/schema.d.ts +++ /dev/null @@ -1,18 +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 - */ - -export interface Schema { - /** - * The name of the project. - */ - name?: string; - /** - * When true, does not install dependency packages. - */ - skipInstall?: boolean; -} diff --git a/packages/bazel/src/schematics/ng-new/index.ts b/packages/bazel/src/schematics/ng-new/index.ts deleted file mode 100644 index 05ffc596da..0000000000 --- a/packages/bazel/src/schematics/ng-new/index.ts +++ /dev/null @@ -1,33 +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 - * - * @fileoverview Schematics for ng-new project that builds with Bazel. - */ - -import {chain, externalSchematic, Rule, schematic, Tree} from '@angular-devkit/schematics'; -import {validateProjectName} from '@schematics/angular/utility/validation'; - -import {Schema} from './schema'; - -export default function(options: Schema): Rule { - return (host: Tree) => { - validateProjectName(options.name); - - return chain([ - externalSchematic('@schematics/angular', 'ng-new', options), - schematic( - 'ng-add', { - name: options.name, - // skip install since `ng-new` above will schedule the task - skipInstall: true, - }, - { - scope: options.name, - }), - ]); - }; -} diff --git a/packages/bazel/src/schematics/ng-new/index_spec.ts b/packages/bazel/src/schematics/ng-new/index_spec.ts deleted file mode 100644 index 99322d7bac..0000000000 --- a/packages/bazel/src/schematics/ng-new/index_spec.ts +++ /dev/null @@ -1,37 +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 - */ - -import {SchematicTestRunner} from '@angular-devkit/schematics/testing'; - -describe('ng-new schematic', () => { - const schematicRunner = new SchematicTestRunner( - '@angular/bazel', - require.resolve('../collection.json'), - ); - const defaultOptions = { - name: 'demo', - version: '7.0.0', - }; - - it('should call external @schematics/angular', async () => { - const options = {...defaultOptions}; - const host = await schematicRunner.runSchematicAsync('ng-new', options).toPromise(); - const {files} = host; - // External schematic should produce workspace file angular.json - expect(files).toContain('/demo/angular.json'); - expect(files).toContain('/demo/package.json'); - }); - - it('should call ng-add to generate additional files needed by Bazel', async () => { - const options = {...defaultOptions}; - const host = await schematicRunner.runSchematicAsync('ng-new', options).toPromise(); - const {files} = host; - expect(files).toContain('/demo/src/main.dev.ts'); - expect(files).toContain('/demo/src/main.prod.ts'); - }); -}); diff --git a/packages/bazel/src/schematics/ng-new/schema.d.ts b/packages/bazel/src/schematics/ng-new/schema.d.ts deleted file mode 100644 index a734a45e27..0000000000 --- a/packages/bazel/src/schematics/ng-new/schema.d.ts +++ /dev/null @@ -1,112 +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 - */ - -export interface Schema { - /** - * Initial git repository commit information. - */ - commit?: CommitUnion; - /** - * When true (the default), creates a new initial app project in the src folder of the new - * workspace. When false, creates an empty workspace with no initial app. You can then use - * the generate application command so that all apps are created in the projects folder. - */ - createApplication?: boolean; - /** - * The directory name to create the workspace in. - */ - directory?: string; - /** - * When true, creates a new app that uses the Ivy rendering engine. - */ - enableIvy?: boolean; - /** - * When true, includes styles inline in the component TS file. By default, an external - * styles file is created and referenced in the component TS file. - */ - inlineStyle?: boolean; - /** - * When true, includes template inline in the component TS file. By default, an external - * template file is created and referenced in the component TS file. - */ - inlineTemplate?: boolean; - /** - * When true, links the CLI to the global version (internal development only). - */ - linkCli?: boolean; - /** - * When true, creates a project without any testing frameworks. (Use for learning purposes - * only.) - */ - minimal?: boolean; - /** - * The name of the new workspace and initial project. - */ - name: string; - /** - * The path where new projects will be created, relative to the new workspace root. - */ - newProjectRoot?: string; - /** - * The prefix to apply to generated selectors for the initial project. - */ - prefix?: string; - /** - * When true, generates a routing module for the initial project. - */ - routing?: boolean; - /** - * When true, does not initialize a git repository. - */ - skipGit?: boolean; - /** - * When true, does not install dependency packages. - */ - skipInstall?: boolean; - /** - * When true, does not generate "spec.ts" test files for the new project. - */ - skipTests?: boolean; - /** - * The file extension or preprocessor to use for style files. - */ - style?: Style; - /** - * The version of the Angular CLI to use. - */ - version: string; - /** - * The view encapsulation strategy to use in the initial project. - */ - viewEncapsulation?: ViewEncapsulation; -} -/** - * Initial git repository commit information. - */ -export declare type CommitUnion = boolean | CommitObject; -export interface CommitObject { - email: string; - message?: string; - name: string; -} -/** - * The file extension or preprocessor to use for style files. - */ -export declare enum Style { - Css = 'css', - Sass = 'sass', - Scss = 'scss', -} -/** - * The view encapsulation strategy to use in the initial project. - */ -export declare enum ViewEncapsulation { - Emulated = 'Emulated', - None = 'None', - ShadowDom = 'ShadowDom' -} diff --git a/packages/bazel/src/schematics/utility/json-utils.ts b/packages/bazel/src/schematics/utility/json-utils.ts deleted file mode 100644 index 4feb7f5f8f..0000000000 --- a/packages/bazel/src/schematics/utility/json-utils.ts +++ /dev/null @@ -1,65 +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 - */ - -import {JsonAstNode, JsonAstObject, JsonValue} from '@angular-devkit/core'; -import {UpdateRecorder} from '@angular-devkit/schematics'; -import {findPropertyInAstObject} from '@schematics/angular/utility/json-utils'; - -/** - * Replace the value of the key-value pair in the 'node' object with a different - * 'value' and record the update using the specified 'recorder'. - */ -export function replacePropertyInAstObject( - recorder: UpdateRecorder, node: JsonAstObject, propertyName: string, value: JsonValue, - indent: number = 0) { - const property = findPropertyInAstObject(node, propertyName); - if (property === null) { - throw new Error(`Property '${propertyName}' does not exist in JSON object`); - } - const {start, text} = property; - recorder.remove(start.offset, text.length); - const indentStr = '\n' + - ' '.repeat(indent); - const content = JSON.stringify(value, null, ' ').replace(/\n/g, indentStr); - recorder.insertLeft(start.offset, content); -} - -/** - * Remove the key-value pair with the specified 'key' in the specified 'node' - * object and record the update using the specified 'recorder'. - */ -export function removeKeyValueInAstObject( - recorder: UpdateRecorder, content: string, node: JsonAstObject, key: string) { - for (const [i, prop] of node.properties.entries()) { - if (prop.key.value === key) { - const start = prop.start.offset; - const end = prop.end.offset; - let length = end - start; - const match = content.slice(end).match(/^[,\s]+/); - if (match) { - length += match.pop()!.length; - } - recorder.remove(start, length); - if (i === node.properties.length - 1) { // last property - let offset = 0; - while (/(,|\s)/.test(content.charAt(start - offset - 1))) { - offset++; - } - recorder.remove(start - offset, offset); - } - return; - } - } -} - -/** - * Returns true if the specified 'node' is a JsonAstObject, false otherwise. - */ -export function isJsonAstObject(node: JsonAstNode|null): node is JsonAstObject { - return !!node && node.kind === 'object'; -} diff --git a/packages/bazel/src/schematics/utility/json-utils_spec.ts b/packages/bazel/src/schematics/utility/json-utils_spec.ts deleted file mode 100644 index e8abe05120..0000000000 --- a/packages/bazel/src/schematics/utility/json-utils_spec.ts +++ /dev/null @@ -1,110 +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 - */ - -import {JsonAstObject, parseJsonAst} from '@angular-devkit/core'; -import {HostTree} from '@angular-devkit/schematics'; -import {UnitTestTree} from '@angular-devkit/schematics/testing'; -import {isJsonAstObject, removeKeyValueInAstObject, replacePropertyInAstObject} from './json-utils'; - -describe('JsonUtils', () => { - let tree: UnitTestTree; - beforeEach(() => { - tree = new UnitTestTree(new HostTree()); - }); - - describe('replacePropertyInAstObject', () => { - it('should replace property', () => { - const content = JSON.stringify({foo: {bar: 'baz'}}); - tree.create('tmp', content); - const ast = parseJsonAst(content) as JsonAstObject; - const recorder = tree.beginUpdate('tmp'); - replacePropertyInAstObject(recorder, ast, 'foo', [1, 2, 3]); - tree.commitUpdate(recorder); - const value = tree.readContent('tmp'); - expect(JSON.parse(value)).toEqual({ - foo: [1, 2, 3], - }); - expect(value).toBe(`{"foo":[ - 1, - 2, - 3 -]}`); - }); - - it('should respect the indent parameter', () => { - const content = JSON.stringify({hello: 'world'}, null, 2); - tree.create('tmp', content); - const ast = parseJsonAst(content) as JsonAstObject; - const recorder = tree.beginUpdate('tmp'); - replacePropertyInAstObject(recorder, ast, 'hello', 'world!', 2); - tree.commitUpdate(recorder); - const value = tree.readContent('tmp'); - expect(JSON.parse(value)).toEqual({ - hello: 'world!', - }); - expect(value).toBe(`{ - "hello": "world!" -}`); - }); - - it('should throw error if property is not found', () => { - const content = JSON.stringify({}); - tree.create('tmp', content); - const ast = parseJsonAst(content) as JsonAstObject; - const recorder = tree.beginUpdate('tmp'); - expect(() => replacePropertyInAstObject(recorder, ast, 'foo', 'bar')) - .toThrowError(`Property 'foo' does not exist in JSON object`); - }); - }); - - describe('removeKeyValueInAstObject', () => { - it('should remove key-value pair', () => { - const content = JSON.stringify({hello: 'world', foo: 'bar'}); - tree.create('tmp', content); - const ast = parseJsonAst(content) as JsonAstObject; - let recorder = tree.beginUpdate('tmp'); - removeKeyValueInAstObject(recorder, content, ast, 'foo'); - tree.commitUpdate(recorder); - const tmp = tree.readContent('tmp'); - expect(JSON.parse(tmp)).toEqual({ - hello: 'world', - }); - expect(tmp).toBe('{"hello":"world"}'); - recorder = tree.beginUpdate('tmp'); - const newContent = tree.readContent('tmp'); - removeKeyValueInAstObject(recorder, newContent, ast, 'hello'); - tree.commitUpdate(recorder); - const value = tree.readContent('tmp'); - expect(JSON.parse(value)).toEqual({}); - expect(value).toBe('{}'); - }); - - it('should be a noop if key is not found', () => { - const content = JSON.stringify({foo: 'bar'}); - tree.create('tmp', content); - const ast = parseJsonAst(content) as JsonAstObject; - let recorder = tree.beginUpdate('tmp'); - expect(() => removeKeyValueInAstObject(recorder, content, ast, 'hello')).not.toThrow(); - tree.commitUpdate(recorder); - const value = tree.readContent('tmp'); - expect(JSON.parse(value)).toEqual({foo: 'bar'}); - expect(value).toBe('{"foo":"bar"}'); - }); - }); - - describe('isJsonAstObject', () => { - it('should return true for an object', () => { - const ast = parseJsonAst(JSON.stringify({})); - expect(isJsonAstObject(ast)).toBe(true); - }); - it('should return false for a non-object', () => { - const ast = parseJsonAst(JSON.stringify([])); - expect(isJsonAstObject(ast)).toBe(false); - }); - }); -}); diff --git a/packages/bazel/src/schematics/utility/workspace-utils.ts b/packages/bazel/src/schematics/utility/workspace-utils.ts deleted file mode 100644 index ef1f43e608..0000000000 --- a/packages/bazel/src/schematics/utility/workspace-utils.ts +++ /dev/null @@ -1,40 +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 - */ - -import {JsonAstNode, JsonAstObject} from '@angular-devkit/core'; -import {findPropertyInAstObject} from '@schematics/angular/utility/json-utils'; -import {isJsonAstObject} from './json-utils'; - -/** - * Find the e2e architect node in the JSON ast. - * The e2e application is relocated alongside the existing application. - * This function supports looking up the e2e architect in both the new and old - * layout. - * See https://github.com/angular/angular-cli/pull/13780 - */ -export function findE2eArchitect(ast: JsonAstObject, name: string): JsonAstObject|null { - const projects = findPropertyInAstObject(ast, 'projects'); - if (!isJsonAstObject(projects)) { - return null; - } - let architect: JsonAstNode|null; - const e2e = findPropertyInAstObject(projects, `${name}-e2e`); - if (isJsonAstObject(e2e)) { - architect = findPropertyInAstObject(e2e, 'architect'); - } else { - const project = findPropertyInAstObject(projects, name); - if (!isJsonAstObject(project)) { - return null; - } - architect = findPropertyInAstObject(project, 'architect'); - } - if (!isJsonAstObject(architect)) { - return null; - } - return architect; -} diff --git a/packages/bazel/src/schematics/utility/workspace-utils_spec.ts b/packages/bazel/src/schematics/utility/workspace-utils_spec.ts deleted file mode 100644 index 6d8909f32a..0000000000 --- a/packages/bazel/src/schematics/utility/workspace-utils_spec.ts +++ /dev/null @@ -1,42 +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 - */ - -import {JsonAstObject, parseJsonAst} from '@angular-devkit/core'; -import {isJsonAstObject} from './json-utils'; -import {findE2eArchitect} from './workspace-utils'; - -describe('Workspace utils', () => { - describe('findE2eArchitect', () => { - it('should find e2e architect in old project layout', () => { - const workspace = { - projects: { - demo: {}, - 'demo-e2e': { - architect: {}, - }, - }, - }; - const ast = parseJsonAst(JSON.stringify(workspace)); - const architect = findE2eArchitect(ast as JsonAstObject, 'demo'); - expect(isJsonAstObject(architect)).toBe(true); - }); - - it('should find e2e architect in new project layout', () => { - const workspace = { - projects: { - demo: { - architect: {}, - }, - }, - }; - const ast = parseJsonAst(JSON.stringify(workspace)); - const architect = findE2eArchitect(ast as JsonAstObject, 'demo'); - expect(isJsonAstObject(architect)).toBe(true); - }); - }); -});