hunk.code_window:   /**
      * Shutdown the Sass render worker.
      * Executing this method will stop any pending render requests.
      *
      * The worker is unreferenced upon creation and will not block application exit. This method
      * is only needed if early cleanup is needed.
      */
     close(): void {
       for (const worker of this.workers) {
  
hunk.labels: keep keep keep keep replace replace replace keep keep keep
hunk.file_path: packages/angular_devkit/build_angular/src/sass/sass-service.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 { JsonParseMode, parseJson, parseJsonAst } from './parser';
  
  // Node 6 compatibility.
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  function entries(x: { [key: string]: any }): any {
    return Object.keys(x).map((k) => [k, x[k]]);
  }
  
  describe('parseJson and parseJsonAst', () => {
    describe('generic', () => {
      const numbers = {};
      const errors = ['', '-abcdefghijklmnopqrstuvwxyz'];
  
      for (const [n, [start, end, text]] of entries(numbers)) {
        it(`works for ${JSON.stringify(n)}`, () => {
          const ast = parseJsonAst(n);
          expect(ast.start).toEqual({ offset: start[0], line: start[1], character: start[2] });
          expect(ast.end).toEqual({ offset: end[0], line: end[1], character: end[2] });
          expect(ast.value).toEqual(JSON.parse(n));
          expect(parseJson(n)).toEqual(JSON.parse(n));
          expect(ast.text).toBe(text === undefined ? n : text);
        });
      }
  
      for (const n of errors) {
        it(`errors for ${JSON.stringify(n)}`, () => {
          expect(() => parseJsonAst(n)).toThrow();
          expect(() => parseJson(n)).toThrow();
          expect(() => JSON.parse(n)).toThrow();
        });
      }
    });
  
    describe('numbers', () => {
      const numbers = {
        '1234': [
          [0, 0, 0],
          [4, 0, 4],
        ],
        '12E34': [
          [0, 0, 0],
          [5, 0, 5],
        ],
        '12E+4': [
          [0, 0, 0],
          [5, 0, 5],
        ],
        '12E-4': [
          [0, 0, 0],
          [5, 0, 5],
        ],
        '12E-0004': [
          [0, 0, 0],
          [8, 0, 8],
        ],
        '   1234   ': [[3, 0, 3], [7, 0, 7], '1234'],
        '\r1234\t': [[1, 0, 1], [5, 0, 5], '1234'],
        '\n1234\n': [[1, 1, 0], [5, 1, 4], '1234'],
        '0.123': [
          [0, 0, 0],
          [5, 0, 5],
        ],
        '0': [
          [0, 0, 0],
          [1, 0, 1],
        ],
        '\n\n\n\n\n0': [[5, 5, 0], [6, 5, 1], '0'],
      };
      const errors = [
        '000',
        '01',
        '1E1+1',
        '--',
        '0-0',
        '-0-0',
        '0.0.0',
        '0\n.0\n.0',
        '0.',
        '+1',
        'Infinity',
        'NaN',
        '-Infinity',
        '+Infinity',
      ];
  
      for (const [n, [start, end, text]] of entries(numbers)) {
        it(`works for ${JSON.stringify(n)}`, () => {
          const ast = parseJsonAst(n);
          expect(ast.kind).toBe('number');
          expect(ast.start).toEqual({ offset: start[0], line: start[1], character: start[2] });
          expect(ast.end).toEqual({ offset: end[0], line: end[1], character: end[2] });
          expect(ast.value).toEqual(JSON.parse(n));
          expect(parseJson(n)).toEqual(JSON.parse(n));
          expect(ast.text).toBe(text === undefined ? n : text);
        });
      }
  
      for (const n of errors) {
        it(`errors for ${JSON.stringify(n)}`, () => {
          expect(() => parseJsonAst(n)).toThrow();
          expect(() => parseJson(n)).toThrow();
          expect(() => JSON.parse(n)).toThrow();
        });
      }
    });
  
    describe('strings', () => {
      const strings = {
        '""': [
          [0, 0, 0],
          [2, 0, 2],
        ],
        '"hello"': [
          [0, 0, 0],
          [7, 0, 7],
        ],
        '"a\\nb"': [
          [0, 0, 0],
          [6, 0, 6],
        ],
        '"a\\nb\\tc\\rd\\\\e\\/f\\"g\\bh\\fi"': [
          [0, 0, 0],
          [27, 0, 27],
        ],
        '"a\\u1234b"': [
          [0, 0, 0],
          [10, 0, 10],
        ],
      };
      const errors = ['"\\z"', "'hello'", '"\\', '"a\\zb"', '"a', '"a\nb"', '"\\\n "'];
  
      for (const [n, [start, end, text]] of entries(strings)) {
        it(`works for ${JSON.stringify(n)}`, () => {
          const ast = parseJsonAst(n);
          expect(ast.kind).toBe('string');
          expect(ast.start).toEqual({ offset: start[0], line: start[1], character: start[2] });
          expect(ast.end).toEqual({ offset: end[0], line: end[1], character: end[2] });
          expect(ast.value).toEqual(JSON.parse(n));
          expect(parseJson(n)).toEqual(JSON.parse(n));
          expect(ast.text).toBe(text === undefined ? n : text);
        });
      }
  
      for (const n of errors) {
        it(`errors for ${JSON.stringify(n)}`, () => {
          expect(() => parseJsonAst(n)).toThrow();
          expect(() => parseJson(n)).toThrow();
          expect(() => JSON.parse(n)).toThrow();
        });
      }
    });
  
    describe('constants', () => {
      const strings = {
        'true': ['true', [0, 0, 0], [4, 0, 4], true],
        'false': ['false', [0, 0, 0], [5, 0, 5], false],
        'null': ['null', [0, 0, 0], [4, 0, 4], null],
      };
      const errors = ['undefined'];
  
      for (const [n, [kind, start, end, value, text]] of entries(strings)) {
        it(`works for ${JSON.stringify(n)}`, () => {
          const ast = parseJsonAst(n);
          expect(ast.kind).toBe(kind);
          expect(ast.start).toEqual({ offset: start[0], line: start[1], character: start[2] });
          expect(ast.end).toEqual({ offset: end[0], line: end[1], character: end[2] });
          expect(ast.value).toEqual(value);
          expect(ast.text).toBe(text === undefined ? n : text);
        });
      }
  
      for (const n of errors) {
        it(`errors for ${JSON.stringify(n)}`, () => {
          expect(() => parseJsonAst(n)).toThrow();
          expect(() => parseJson(n)).toThrow();
          expect(() => JSON.parse(n)).toThrow();
        });
      }
    });
  
    describe('arrays', () => {
      const strings = {
        '[0,1,2,3]': [
          [0, 0, 0],
          [9, 0, 9],
        ],
        '[[0],1,2,3]': [
          [0, 0, 0],
          [11, 0, 11],
        ],
        '[0\n,\n1,2,3]': [
          [0, 0, 0],
          [11, 2, 6],
        ],
        '[]': [
          [0, 0, 0],
          [2, 0, 2],
        ],
        '\n[\n]\n': [[1, 1, 0], [4, 2, 1], '[\n]'],
        '[\n]': [
          [0, 0, 0],
          [3, 1, 1],
        ],
        '[\n\n]': [
          [0, 0, 0],
          [4, 2, 1],
        ],
      };
      const errors = ['[', '[,]', '[0,]', '[,0]'];
  
      for (const [n, [start, end, text]] of entries(strings)) {
        it(`works for ${JSON.stringify(n)}`, () => {
          const ast = parseJsonAst(n);
          expect(ast.kind).toBe('array');
          expect(ast.start).toEqual({ offset: start[0], line: start[1], character: start[2] });
          expect(ast.end).toEqual({ offset: end[0], line: end[1], character: end[2] });
          expect(ast.value).toEqual(JSON.parse(n));
          expect(parseJson(n)).toEqual(JSON.parse(n));
          expect(ast.text).toBe(text === undefined ? n : text);
        });
      }
  
      for (const n of errors) {
        it(`errors for ${JSON.stringify(n)}`, () => {
          expect(() => parseJsonAst(n)).toThrow();
          expect(() => parseJson(n)).toThrow();
          expect(() => JSON.parse(n)).toThrow();
        });
      }
    });
  
    describe('objects', () => {
      const strings = {
        '{}': [
          [0, 0, 0],
          [2, 0, 2],
        ],
        '{\n}': [
          [0, 0, 0],
          [3, 1, 1],
        ],
        '{"hello": "world"}': [
          [0, 0, 0],
          [18, 0, 18],
        ],
        '{"hello": 0, "world": 1}': [
          [0, 0, 0],
          [24, 0, 24],
        ],
        '{"hello": {"hello": {"hello": "world"}}}': [
          [0, 0, 0],
          [40, 0, 40],
        ],
      };
      const errors = ['{', '{,}', '{"hello": 0'];
  
      for (const [n, [start, end, text]] of entries(strings)) {
        it(`works for ${JSON.stringify(n)}`, () => {
          const ast = parseJsonAst(n);
          expect(ast.kind).toBe('object');
          expect(ast.start).toEqual({ offset: start[0], line: start[1], character: start[2] });
          expect(ast.end).toEqual({ offset: end[0], line: end[1], character: end[2] });
          expect(ast.value).toEqual(JSON.parse(n));
          expect(parseJson(n)).toEqual(JSON.parse(n));
          expect(ast.text).toBe(text === undefined ? n : text);
        });
      }
  
      for (const n of errors) {
        it(`errors for ${JSON.stringify(n)}`, () => {
          expect(() => parseJsonAst(n)).toThrow();
          expect(() => parseJson(n)).toThrow();
          expect(() => JSON.parse(n)).toThrow();
        });
      }
    });
  
    describe('loose', () => {
      const strings = {
        "{'hello': 0}": [[0, 0, 0], [12, 0, 12], { 'hello': 0 }],
        '{hello: 0}': [[0, 0, 0], [10, 0, 10], { hello: 0 }],
        '{1: 0}': [[0, 0, 0], [6, 0, 6], { 1: 0 }],
        '{hello\n:/**/ 0}': [[0, 0, 0], [15, 1, 8], { hello: 0 }],
        '{\n// hello\n}': [[0, 0, 0], [12, 2, 1], {}],
        '{\n/* hello\n*/ }': [[0, 0, 0], [15, 2, 4], {}],
        '{}//  ': [[0, 0, 0], [2, 0, 2], {}, '{}'],
        '{}//': [[0, 0, 0], [2, 0, 2], {}, '{}'],
        '{hello:0,}': [[0, 0, 0], [10, 0, 10], { hello: 0 }],
        '{hello:0/**/,}': [[0, 0, 0], [14, 0, 14], { hello: 0 }],
        '{hello:0,/**/}': [[0, 0, 0], [14, 0, 14], { hello: 0 }],
        '{hi:["hello",]}': [[0, 0, 0], [15, 0, 15], { hi: ['hello'] }],
        '{hi:["hello",/* */]}': [[0, 0, 0], [20, 0, 20], { hi: ['hello'] }],
        '{hi:["hello"/* */,]}': [[0, 0, 0], [20, 0, 20], { hi: ['hello'] }],
        '{hi:["hello" , ] , }': [[0, 0, 0], [20, 0, 20], { hi: ['hello'] }],
        '{hi:"\\\n "}': [[0, 0, 0], [10, 1, 3], { hi: '\n ' }],
        '{d: -0xdecaf, e: Infinity, f: -Infinity, g: +Infinity, h: NaN,}': [
          [0, 0, 0],
          [63, 0, 63],
          {
            d: -0xdecaf,
            e: Infinity,
            f: -Infinity,
            g: Infinity,
            h: NaN,
          },
        ],
      };
      const errors = ['{1b: 0}', ' /*', '', '.Infinity'];
  
      for (const [n, [start, end, value, text]] of entries(strings)) {
        it(`works for ${JSON.stringify(n)}`, () => {
          const ast = parseJsonAst(n, JsonParseMode.Loose);
          expect(ast.kind).toBe('object');
          expect(ast.start).toEqual({ offset: start[0], line: start[1], character: start[2] });
          expect(ast.end).toEqual({ offset: end[0], line: end[1], character: end[2] });
          expect(ast.value).toEqual(value);
          expect(parseJson(n, JsonParseMode.Loose)).toEqual(value);
          expect(ast.text).toBe(text === undefined ? n : text);
        });
      }
  
      for (const n of errors) {
        it(`errors for ${JSON.stringify(n)}`, () => {
          expect(() => parseJsonAst(n, JsonParseMode.Loose)).toThrow();
          expect(() => parseJson(n, JsonParseMode.Loose)).toThrow();
          expect(() => JSON.parse(n)).toThrow();
        });
      }
    });
  
    describe('complex', () => {
      it('strips comments', () => {
        expect(
          parseJson(
            `
          // THIS IS A COMMENT
          {
            /* THIS IS ALSO A COMMENT */ // IGNORED BECAUSE COMMENT
            // AGAIN, COMMENT /* THIS SHOULD NOT BE WEIRD
            "a": "this // should not be a comment",
            "a2": "this /* should also not be a comment",
            /* MULTIPLE
               LINE
               COMMENT
               \o/ */
            "b" /* COMMENT */: /* YOU GUESSED IT */ 1 // COMMENT
            , /* STILL VALID */
            "c": 2
          }
        `,
            JsonParseMode.Loose,
          ),
        ).toEqual({
          a: 'this // should not be a comment',
          a2: 'this /* should also not be a comment',
          b: 1,
          c: 2,
        });
      });
  
      it('works with json5.org example', () => {
        const input = `{
          // comments
          unquoted: 'and you can quote me on that',
          'singleQuotes': 'I can use "double quotes" here',
          lineBreaks: "Look, Mom! \\
  No \\\\n's!",
          hexadecimal: 0xdecaf,
          leadingDecimalPoint: .8675309, andTrailing: 8675309.,
          positiveSign: +1,
          trailingComma: 'in objects', andIn: ['arrays',],
          "backwardsCompatible": "with JSON",
        }`;
  
        expect(parseJson(input, JsonParseMode.Json5)).toEqual({
          unquoted: 'and you can quote me on that',
          singleQuotes: 'I can use "double quotes" here',
          lineBreaks: "Look, Mom! \nNo \\n's!",
          hexadecimal: 0xdecaf,
          leadingDecimalPoint: 0.8675309,
          andTrailing: 8675309,
          positiveSign: +1,
          trailingComma: 'in objects',
          andIn: ['arrays'],
          backwardsCompatible: 'with JSON',
        });
      });
    });
  });
  