hunk.code_window:     builder: target.builder,
       ...(isEmpty(target.options) ? {} : { options: target.options as JsonObject }),
       ...(isEmpty(target.configurations)
         ? {}
         : { configurations: target.configurations as JsonObject }),
     };
   }
  
hunk.labels: keep keep keep keep add keep keep keep
hunk.after_edit:     ...(target.defaultConfiguration === undefined
         ? {}
         : { defaultConfiguration: target.defaultConfiguration }),
  
hunk.file_path: packages/angular_devkit/core/src/workspace/json/writer.ts
hunk.type: add
file: import * as express from 'express';
  import { resolve } from 'path';
  import { getGlobalVariable } from '../../utils/env';
  import {
    copyFile,
    expectFileToExist,
    expectFileToMatch,
    replaceInFile,
    writeFile,
  } from '../../utils/fs';
  import { installPackage } from '../../utils/packages';
  import { ng } from '../../utils/process';
  import { updateJsonFile } from '../../utils/project';
  import { expectToFail } from '../../utils/utils';
  import { readNgVersion } from '../../utils/version';
  
  export default async function() {
    // TEMP: disable pending i18n updates
    // TODO: when re-enabling, use setupI18nConfig and helpers like other i18n tests.
    return;
  
    let localizeVersion = '@angular/localize@' + readNgVersion();
    if (getGlobalVariable('argv')['ng-snapshots']) {
      localizeVersion = require('../../ng-snapshot/package.json').dependencies['@angular/localize'];
    }
    await installPackage(localizeVersion);
  
    let serviceWorkerVersion = '@angular/service-worker@' + readNgVersion();
    if (getGlobalVariable('argv')['ng-snapshots']) {
      serviceWorkerVersion = require('../../ng-snapshot/package.json').dependencies[
        '@angular/service-worker'
      ];
    }
    await installPackage(serviceWorkerVersion);
  
    await updateJsonFile('tsconfig.json', config => {
      config.compilerOptions.target = 'es2015';
      if (!config.angularCompilerOptions) {
        config.angularCompilerOptions = {};
      }
      config.angularCompilerOptions.disableTypeScriptVersionCheck = true;
    });
  
    const baseDir = 'dist/test-project';
  
    // Set configurations for each locale.
    const langTranslations = [
      { lang: 'en-US', translation: 'Hello i18n!' },
      { lang: 'fr', translation: 'Bonjour i18n!' },
    ];
  
    await updateJsonFile('angular.json', workspaceJson => {
      const appProject = workspaceJson.projects['test-project'];
      const appArchitect = appProject.architect || appProject.targets;
      const serveConfigs = appArchitect['serve'].configurations;
      const e2eConfigs = appArchitect['e2e'].configurations;
  
      // Make default builds prod.
      appArchitect['build'].options.optimization = true;
      appArchitect['build'].options.buildOptimizer = true;
      appArchitect['build'].options.aot = true;
      appArchitect['build'].options.fileReplacements = [
        {
          replace: 'src/environments/environment.ts',
          with: 'src/environments/environment.prod.ts',
        },
      ];
  
      // Enable service worker
      appArchitect['build'].options.serviceWorker = true;
  
      // Enable localization for all locales
      // appArchitect['build'].options.localize = true;
  
      // Add locale definitions to the project
      // tslint:disable-next-line: no-any
      const i18n: Record<string, any> = (appProject.i18n = { locales: {} });
      for (const { lang } of langTranslations) {
        if (lang == 'en-US') {
          i18n.sourceLocale = lang;
        } else {
          i18n.locales[lang] = `src/locale/messages.${lang}.xlf`;
        }
        serveConfigs[lang] = { browserTarget: `test-project:build:${lang}` };
        e2eConfigs[lang] = {
          specs: [`./src/app.${lang}.e2e-spec.ts`],
          devServerTarget: `test-project:serve:${lang}`,
        };
      }
    });
  
    // Add service worker source configuration
    const manifest = {
      index: '/index.html',
      assetGroups: [
        {
          name: 'app',
          installMode: 'prefetch',
          resources: {
            files: ['/favicon.ico', '/index.html', '/manifest.webmanifest', '/*.css', '/*.js'],
          },
        },
        {
          name: 'assets',
          installMode: 'lazy',
          updateMode: 'prefetch',
          resources: {
            files: ['/assets/**', '/*.(eot|svg|cur|jpg|png|webp|gif|otf|ttf|woff|woff2|ani)'],
          },
        },
      ],
    };
    await writeFile('ngsw-config.json', JSON.stringify(manifest));
  
    // Add a translatable element.
    await writeFile(
      'src/app/app.component.html',
      '<h1 i18n="An introduction header for this sample">Hello i18n!</h1>',
    );
  
    // Extract the translation messages and copy them for each language.
    await ng('extract-i18n', '--output-path=src/locale');
    await expectFileToExist('src/locale/messages.xlf');
    await expectFileToMatch('src/locale/messages.xlf', `source-language="en-US"`);
    await expectFileToMatch('src/locale/messages.xlf', `An introduction header for this sample`);
  
    for (const { lang, translation } of langTranslations) {
      if (lang != 'en-US') {
        await copyFile('src/locale/messages.xlf', `src/locale/messages.${lang}.xlf`);
        await replaceInFile(
          `src/locale/messages.${lang}.xlf`,
          'source-language="en-US"',
          `source-language="en-US" target-language="${lang}"`,
        );
        await replaceInFile(
          `src/locale/messages.${lang}.xlf`,
          '<source>Hello i18n!</source>',
          `<source>Hello i18n!</source>\n<target>${translation}</target>`,
        );
      }
    }
  
    // Build each locale and verify the output.
    await ng('build', '--i18n-missing-translation', 'error');
    for (const { lang, translation } of langTranslations) {
      await expectFileToMatch(`${baseDir}/${lang}/main-es5.js`, translation);
      await expectFileToMatch(`${baseDir}/${lang}/main-es2015.js`, translation);
      await expectToFail(() => expectFileToMatch(`${baseDir}/${lang}/main-es5.js`, '$localize`'));
      await expectToFail(() => expectFileToMatch(`${baseDir}/${lang}/main-es2015.js`, '$localize`'));
      await expectFileToMatch(`${baseDir}/${lang}/main-es5.js`, lang);
      await expectFileToMatch(`${baseDir}/${lang}/main-es2015.js`, lang);
  
      // Expect service worker configuration to be present
      await expectFileToExist(`${baseDir}/${lang}/ngsw.json`);
  
      // Ivy i18n doesn't yet work with `ng serve` so we must use a separate server.
      const app = express();
      app.use(express.static(resolve(baseDir, lang)));
      const server = app.listen(4200, 'localhost');
      try {
        // Add E2E test for locale
        await writeFile(
          'e2e/src/app.e2e-spec.ts',
          `
          import { browser, logging, element, by } from 'protractor';
          describe('workspace-project App', () => {
            it('should display welcome message', () => {
              browser.get(browser.baseUrl);
              expect(element(by.css('h1')).getText()).toEqual('${translation}');
            });
            afterEach(async () => {
              // Assert that there are no errors emitted from the browser
              const logs = await browser.manage().logs().get(logging.Type.BROWSER);
              expect(logs).not.toContain(jasmine.objectContaining({
                level: logging.Level.SEVERE,
              } as logging.Entry));
            });
          });
        `,
        );
  
        // Execute without a devserver.
        await ng('e2e', '--devServerTarget=');
      } finally {
        server.close();
      }
    }
  }
  