hunk.code_window:                   minimized: true,
                   });
                   continue;
                 }
               }
               const { source, map } = scriptAssetSource.sourceAndMap();
  
hunk.labels: keep replace keep keep keep keep keep
hunk.after_edit:                 }));
  
hunk.file_path: packages/angular_devkit/build_angular/src/webpack/plugins/javascript-optimizer-plugin.ts
hunk.type: replace
file: /**
   * @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 { Position, SourceNode } from 'source-map';
  
  // Matches <%= expr %>. This does not support structural JavaScript (for/if/...).
  const kInterpolateRe = /<%=([\s\S]+?)%>/g;
  // Matches <%# text %>. It's a comment and will be entirely ignored.
  const kCommentRe = /<%#([\s\S]+?)%>/g;
  
  // Used to match template delimiters.
  // <%- expr %>: HTML escape the value.
  // <% ... %>: Structural template code.
  const kEscapeRe = /<%-([\s\S]+?)%>/g;
  const kEvaluateRe = /<%([\s\S]+?)%>/g;
  
  /** Used to map characters to HTML entities. */
  const kHtmlEscapes: { [char: string]: string } = {
    '&': '&amp;',
    '<': '&lt;',
    '>': '&gt;',
    '"': '&quot;',
    "'": '&#39;',
    '`': '&#96;',
  };
  
  // Used to match HTML entities and HTML characters.
  const reUnescapedHtml = new RegExp(`[${Object.keys(kHtmlEscapes).join('')}]`, 'g');
  
  // Options to pass to template.
  export interface TemplateOptions {
    sourceURL?: string;
    sourceMap?: boolean;
    module?: boolean | { exports: {} };
    sourceRoot?: string;
    fileName?: string;
  }
  
  function _positionFor(content: string, offset: number): Position {
    let line = 1;
    let column = 0;
    for (let i = 0; i < offset - 1; i++) {
      if (content[i] == '\n') {
        line++;
        column = 0;
      } else {
        column++;
      }
    }
  
    return {
      line,
      column,
    };
  }
  
  /**
   * A simple AST for templates. There's only one level of AST nodes, but it's still useful
   * to have the information you're looking for.
   */
  export interface TemplateAst {
    fileName: string;
    content: string;
    children: TemplateAstNode[];
  }
  
  /**
   * The base, which contains positions.
   */
  export interface TemplateAstBase {
    start: Position;
    end: Position;
  }
  
  /**
   * A static content node.
   */
  export interface TemplateAstContent extends TemplateAstBase {
    kind: 'content';
    content: string;
  }
  
  /**
   * A comment node.
   */
  export interface TemplateAstComment extends TemplateAstBase {
    kind: 'comment';
    text: string;
  }
  
  /**
   * An evaluate node, which is the code between `<% ... %>`.
   */
  export interface TemplateAstEvaluate extends TemplateAstBase {
    kind: 'evaluate';
    expression: string;
  }
  
  /**
   * An escape node, which is the code between `<%- ... %>`.
   */
  export interface TemplateAstEscape extends TemplateAstBase {
    kind: 'escape';
    expression: string;
  }
  
  /**
   * An interpolation node, which is the code between `<%= ... %>`.
   */
  export interface TemplateAstInterpolate extends TemplateAstBase {
    kind: 'interpolate';
    expression: string;
  }
  
  export type TemplateAstNode =
    | TemplateAstContent
    | TemplateAstEvaluate
    | TemplateAstComment
    | TemplateAstEscape
    | TemplateAstInterpolate;
  
  /**
   * Given a source text (and a fileName), returns a TemplateAst.
   */
  export function templateParser(sourceText: string, fileName: string): TemplateAst {
    const children = [];
  
    // Compile the regexp to match each delimiter.
    const reExpressions = [kEscapeRe, kCommentRe, kInterpolateRe, kEvaluateRe];
    const reDelimiters = RegExp(reExpressions.map((x) => x.source).join('|') + '|$', 'g');
  
    const parsed = sourceText.split(reDelimiters);
    let offset = 0;
    // Optimization that uses the fact that the end of a node is always the beginning of the next
    // node, so we keep the positioning of the nodes in memory.
    let start = _positionFor(sourceText, offset);
    let end: Position | null;
  
    const increment = reExpressions.length + 1;
    for (let i = 0; i < parsed.length; i += increment) {
      const [content, escape, comment, interpolate, evaluate] = parsed.slice(i, i + increment);
      if (content) {
        end = _positionFor(sourceText, offset + content.length);
        offset += content.length;
        children.push({ kind: 'content', content, start, end } as TemplateAstContent);
        start = end;
      }
      if (escape) {
        end = _positionFor(sourceText, offset + escape.length + 5);
        offset += escape.length + 5;
        children.push({ kind: 'escape', expression: escape, start, end } as TemplateAstEscape);
        start = end;
      }
      if (comment) {
        end = _positionFor(sourceText, offset + comment.length + 5);
        offset += comment.length + 5;
        children.push({ kind: 'comment', text: comment, start, end } as TemplateAstComment);
        start = end;
      }
      if (interpolate) {
        end = _positionFor(sourceText, offset + interpolate.length + 5);
        offset += interpolate.length + 5;
        children.push({
          kind: 'interpolate',
          expression: interpolate,
          start,
          end,
        } as TemplateAstInterpolate);
        start = end;
      }
      if (evaluate) {
        end = _positionFor(sourceText, offset + evaluate.length + 5);
        offset += evaluate.length + 5;
        children.push({ kind: 'evaluate', expression: evaluate, start, end } as TemplateAstEvaluate);
        start = end;
      }
    }
  
    return {
      fileName,
      content: sourceText,
      children,
    };
  }
  
  /**
   * Fastest implementation of the templating algorithm. It only add strings and does not bother
   * with source maps.
   */
  function templateFast(ast: TemplateAst, options?: TemplateOptions): string {
    const module = options && options.module ? 'module.exports.default =' : '';
    const reHtmlEscape = reUnescapedHtml.source.replace(/[']/g, "\\\\\\'");
  
    return `
      return ${module} function(obj) {
        obj || (obj = {});
        let __t;
        let __p = '';
        const __escapes = ${JSON.stringify(kHtmlEscapes)};
        const __escapesre = new RegExp('${reHtmlEscape}', 'g');
  
        const __e = function(s) {
          return s ? s.replace(__escapesre, function(key) { return __escapes[key]; }) : '';
        };
        with (obj) {
          ${ast.children
            .map((node) => {
              switch (node.kind) {
                case 'content':
                  return `__p += ${JSON.stringify(node.content)};`;
                case 'interpolate':
                  return `__p += ((__t = (${node.expression})) == null) ? '' : __t;`;
                case 'escape':
                  return `__p += __e(${node.expression});`;
                case 'evaluate':
                  return node.expression;
              }
            })
            .join('\n')}
        }
  
        return __p;
      };
    `;
  }
  
  /**
   * Templating algorithm with source map support. The map is outputted as //# sourceMapUrl=...
   */
  function templateWithSourceMap(ast: TemplateAst, options?: TemplateOptions): string {
    const sourceUrl = ast.fileName;
    const module = options && options.module ? 'module.exports.default =' : '';
    const reHtmlEscape = reUnescapedHtml.source.replace(/[']/g, "\\\\\\'");
  
    const preamble = new SourceNode(1, 0, sourceUrl, '').add(
      new SourceNode(1, 0, sourceUrl, [
        `return ${module} function(obj) {\n`,
        '  obj || (obj = {});\n',
        '  let __t;\n',
        '  let __p = "";\n',
        `  const __escapes = ${JSON.stringify(kHtmlEscapes)};\n`,
        `  const __escapesre = new RegExp('${reHtmlEscape}', 'g');\n`,
        `\n`,
        `  const __e = function(s) { `,
        `    return s ? s.replace(__escapesre, function(key) { return __escapes[key]; }) : '';`,
        `  };\n`,
        `  with (obj) {\n`,
      ]),
    );
  
    const end = ast.children.length
      ? ast.children[ast.children.length - 1].end
      : { line: 0, column: 0 };
    const nodes = ast.children
      .reduce((chunk, node) => {
        let code: string | SourceNode | (SourceNode | string)[] = '';
        switch (node.kind) {
          case 'content':
            code = [
              new SourceNode(node.start.line, node.start.column, sourceUrl, '__p = __p'),
              ...node.content.split('\n').map((line, i, arr) => {
                return new SourceNode(
                  node.start.line + i,
                  i == 0 ? node.start.column : 0,
                  sourceUrl,
                  '\n    + ' + JSON.stringify(line + (i == arr.length - 1 ? '' : '\n')),
                );
              }),
              new SourceNode(node.end.line, node.end.column, sourceUrl, ';\n'),
            ];
            break;
          case 'interpolate':
            code = [
              new SourceNode(node.start.line, node.start.column, sourceUrl, '__p += ((__t = '),
              ...node.expression.split('\n').map((line, i, arr) => {
                return new SourceNode(
                  node.start.line + i,
                  i == 0 ? node.start.column : 0,
                  sourceUrl,
                  line + (i == arr.length - 1 ? '' : '\n'),
                );
              }),
              new SourceNode(node.end.line, node.end.column, sourceUrl, ') == null ? "" : __t);\n'),
            ];
            break;
          case 'escape':
            code = [
              new SourceNode(node.start.line, node.start.column, sourceUrl, '__p += __e('),
              ...node.expression.split('\n').map((line, i, arr) => {
                return new SourceNode(
                  node.start.line + i,
                  i == 0 ? node.start.column : 0,
                  sourceUrl,
                  line + (i == arr.length - 1 ? '' : '\n'),
                );
              }),
              new SourceNode(node.end.line, node.end.column, sourceUrl, ');\n'),
            ];
            break;
          case 'evaluate':
            code = [
              ...node.expression.split('\n').map((line, i, arr) => {
                return new SourceNode(
                  node.start.line + i,
                  i == 0 ? node.start.column : 0,
                  sourceUrl,
                  line + (i == arr.length - 1 ? '' : '\n'),
                );
              }),
              new SourceNode(node.end.line, node.end.column, sourceUrl, '\n'),
            ];
            break;
        }
  
        return chunk.add(new SourceNode(node.start.line, node.start.column, sourceUrl, code));
      }, preamble)
      .add(
        new SourceNode(end.line, end.column, sourceUrl, ['  };\n', '\n', '  return __p;\n', '}\n']),
      );
  
    const code = nodes.toStringWithSourceMap({
      file: sourceUrl,
      sourceRoot: (options && options.sourceRoot) || '.',
    });
  
    // Set the source content in the source map, otherwise the sourceUrl is not enough
    // to find the content.
    code.map.setSourceContent(sourceUrl, ast.content);
  
    return (
      code.code +
      '\n//# sourceMappingURL=data:application/json;base64,' +
      Buffer.from(code.map.toString()).toString('base64')
    );
  }
  
  /**
   * An equivalent of EJS templates, which is based on John Resig's `tmpl` implementation
   * (http://ejohn.org/blog/javascript-micro-templating/) and Laura Doktorova's doT.js
   * (https://github.com/olado/doT).
   *
   * This version differs from lodash by removing support from ES6 quasi-literals, and making the
   * code slightly simpler to follow. It also does not depend on any third party, which is nice.
   *
   * Finally, it supports SourceMap, if you ever need to debug, which is super nice.
   *
   * @param content The template content.
   * @param options Optional Options. See TemplateOptions for more description.
   * @return {(input: T) => string} A function that accept an input object and returns the content
   *         of the template with the input applied.
   */
  export function template<T>(content: string, options?: TemplateOptions): (input: T) => string {
    const sourceUrl = (options && options.sourceURL) || 'ejs';
    const ast = templateParser(content, sourceUrl);
  
    let source: string;
    // If there's no need for source map support, we revert back to the fast implementation.
    if (options && options.sourceMap) {
      source = templateWithSourceMap(ast, options);
    } else {
      source = templateFast(ast, options);
    }
  
    // We pass a dummy module in case the module option is passed. If `module: true` is passed, we
    // need to only use the source, not the function itself. Otherwise expect a module object to be
    // passed, and we use that one.
    const fn = Function('module', source);
    const module =
      options && options.module ? (options.module === true ? { exports: {} } : options.module) : null;
    const result = fn(module);
  
    // Provide the compiled function's source by its `toString` method or
    // the `source` property as a convenience for inlining compiled templates.
    result.source = source;
  
    return result;
  }
  