tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

prettyFast.spec.js (11078B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
      4 
      5 /*
      6 * Copyright 2013 Mozilla Foundation and contributors
      7 * Licensed under the New BSD license. See LICENSE.md or:
      8 * http://opensource.org/licenses/BSD-2-Clause
      9 */
     10 import { prettyFast } from "../pretty-fast";
     11 import { SourceMapConsumer } from "devtools/client/shared/vendor/source-map/source-map";
     12 
     13 const cases = [
     14  {
     15    name: "Simple function",
     16    input: "function foo() { bar(); }",
     17  },
     18  {
     19    name: "Nested function",
     20    input: "function foo() { function bar() { debugger; } bar(); }",
     21  },
     22  {
     23    name: "Immediately invoked function expression",
     24    input: "(function(){thingy()}())",
     25  },
     26  {
     27    name: "Single line comment",
     28    input: `
     29    // Comment
     30    function foo() { bar(); }`,
     31  },
     32  {
     33    name: "Multi line comment",
     34    input: `
     35    /* Comment
     36    more comment */
     37    function foo() { bar(); }
     38    `,
     39  },
     40  { name: "Null assignment", input: "var i=null;" },
     41  { name: "Undefined assignment", input: "var i=undefined;" },
     42  { name: "Void 0 assignment", input: "var i=void 0;" },
     43  {
     44    name: "This property access",
     45    input: "var foo=this.foo;\n",
     46  },
     47 
     48  {
     49    name: "True assignment",
     50    input: "var foo=true;\n",
     51  },
     52 
     53  {
     54    name: "False assignment",
     55    input: "var foo=false;\n",
     56  },
     57 
     58  {
     59    name: "For loop",
     60    input: "for (var i = 0; i < n; i++) { console.log(i); }",
     61  },
     62 
     63  {
     64    name: "for..of loop",
     65    input: "for (const x of [1,2,3]) { console.log(x) }",
     66  },
     67 
     68  {
     69    name: "String with semicolon",
     70    input: "var foo = ';';\n",
     71  },
     72 
     73  {
     74    name: "String with quote",
     75    input: 'var foo = "\'";\n',
     76  },
     77 
     78  {
     79    name: "Function calls",
     80    input: "var result=func(a,b,c,d);",
     81  },
     82 
     83  {
     84    name: "Regexp",
     85    input: "var r=/foobar/g;",
     86  },
     87 
     88  {
     89    name: "In operator",
     90    input: "if(foo in bar){doThing()}",
     91    output: "if (foo in bar) {\n" + "  doThing()\n" + "}\n",
     92  },
     93  {
     94    name: "With statement",
     95    input: "with(obj){crock()}",
     96  },
     97  {
     98    name: "New expression",
     99    input: "var foo=new Foo();",
    100  },
    101  {
    102    name: "Continue/break statements",
    103    input: "while(1){if(x){continue}if(y){break}if(z){break foo}}",
    104  },
    105  {
    106    name: "Instanceof",
    107    input: "var a=x instanceof y;",
    108  },
    109  {
    110    name: "Binary operators",
    111    input: "var a=5*30;var b=5>>3;",
    112  },
    113  {
    114    name: "Delete",
    115    input: "delete obj.prop;",
    116  },
    117 
    118  {
    119    name: "Try/catch/finally statement",
    120    input: "try{dangerous()}catch(e){handle(e)}finally{cleanup()}",
    121  },
    122  {
    123    name: "If/else statement",
    124    input: "if(c){then()}else{other()}",
    125  },
    126  {
    127    name: "If/else without curlies",
    128    input: "if(c) a else b",
    129  },
    130  {
    131    name: "Objects",
    132    input: `
    133      var o={a:1,
    134      b:2};`,
    135  },
    136  {
    137    name: "Do/while loop",
    138    input: "do{x}while(y)",
    139  },
    140  {
    141    name: "Arrays",
    142    input: "var a=[1,2,3];",
    143  },
    144  {
    145    name: "Arrays and spread operator",
    146    input: "var a=[1,...[2,3],...[], 4];",
    147  },
    148  {
    149    name: "Empty object/array literals",
    150    input: `let a=[];const b={};c={...{},d: 42};for(let x of []){for(let y in {}){}}`,
    151  },
    152  {
    153    name: "Code that relies on ASI",
    154    input: `
    155           var foo = 10
    156           var bar = 20
    157           function g() {
    158             a()
    159             b()
    160           }`,
    161  },
    162  {
    163    name: "Ternary operator",
    164    input: "bar?baz:bang;",
    165  },
    166  {
    167    name: "Switch statements",
    168    input: "switch(x){case a:foo();break;default:bar()}",
    169  },
    170 
    171  {
    172    name: "Multiple single line comments",
    173    input: `function f() {
    174             // a
    175             // b
    176             // c
    177           }`,
    178  },
    179  {
    180    name: "Indented multiline comment",
    181    input: `function foo() {
    182             /**
    183              * java doc style comment
    184              * more comment
    185              */
    186             bar();
    187           }`,
    188  },
    189  {
    190    name: "ASI return",
    191    input: `function f() {
    192             return
    193             {}
    194           }`,
    195  },
    196  {
    197    name: "Non-ASI property access",
    198    input: `[1,2,3]
    199           [0]`,
    200  },
    201  {
    202    name: "Non-ASI in",
    203    input: `'x'
    204           in foo`,
    205  },
    206 
    207  {
    208    name: "Non-ASI function call",
    209    input: `f
    210           ()`,
    211  },
    212  {
    213    name: "Non-ASI new",
    214    input: `new
    215           F()`,
    216  },
    217  {
    218    name: "Getter and setter literals",
    219    input: "var obj={get foo(){return this._foo},set foo(v){this._foo=v}}",
    220  },
    221  {
    222    name: "Escaping backslashes in strings",
    223    input: "'\\\\'\n",
    224  },
    225  {
    226    name: "Escaping carriage return in strings",
    227    input: "'\\r'\n",
    228  },
    229  {
    230    name: "Escaping tab in strings",
    231    input: "'\\t'\n",
    232  },
    233  {
    234    name: "Escaping vertical tab in strings",
    235    input: "'\\v'\n",
    236  },
    237  {
    238    name: "Escaping form feed in strings",
    239    input: "'\\f'\n",
    240  },
    241  {
    242    name: "Escaping null character in strings",
    243    input: "'\\0'\n",
    244  },
    245  {
    246    name: "Escaping single quote character in strings",
    247    input: "'\\''\n",
    248  },
    249  {
    250    name: "Escaping backslashes in template strings",
    251    input: "`\\\\`\n",
    252  },
    253  {
    254    name: "Escaping carriage return in template strings",
    255    input: "`\\r`\n",
    256  },
    257  {
    258    name: "Escaped line feed in template strings",
    259    input: "`\\n`\n",
    260  },
    261  {
    262    name: "Raw line feed in template strings",
    263    input: "`\n`\n",
    264  },
    265  {
    266    name: "Escaping tab in template strings",
    267    input: "`\\t`\n",
    268  },
    269  {
    270    name: "Escaping vertical tab in template strings",
    271    input: "`\\v`\n",
    272  },
    273  {
    274    name: "Escaping form feed in template strings",
    275    input: "`\\f`\n",
    276  },
    277  {
    278    name: "Escaping null character in template strings",
    279    input: "`\\0`\n",
    280  },
    281  {
    282    name: "Escaping backtick character in template strings",
    283    input: "`\\``\n",
    284  },
    285  {
    286    name: "Bug 977082 - space between grouping operator and dot notation",
    287    input: `JSON.stringify(3).length;
    288           ([1,2,3]).length;
    289           (new Date()).toLocaleString();`,
    290  },
    291  {
    292    name: "Bug 975477 don't move end of line comments to next line",
    293    input: `switch (request.action) {
    294             case 'show': //$NON-NLS-0$
    295               if (localStorage.hideicon !== 'true') { //$NON-NLS-0$
    296                 chrome.pageAction.show(sender.tab.id);
    297               }
    298               break;
    299             case 'hide': /*Multiline
    300               Comment */
    301               break;
    302             default:
    303               console.warn('unknown request'); //$NON-NLS-0$
    304               // don't respond if you don't understand the message.
    305               return;
    306           }`,
    307  },
    308  {
    309    name: "Const handling",
    310    input: "const d = 'yes';\n",
    311  },
    312  {
    313    name: "Let handling without value",
    314    input: "let d;\n",
    315  },
    316  {
    317    name: "Let handling with value",
    318    input: "let d = 'yes';\n",
    319  },
    320  {
    321    name: "Template literals",
    322    // issue in acorn
    323    input: "`abc${JSON.stringify({clas: 'testing'})}def`;{a();}",
    324  },
    325  {
    326    name: "Class handling",
    327    input: "class  Class{constructor(){}}",
    328  },
    329  {
    330    name: "Subclass handling",
    331    input: "class  Class  extends  Base{constructor(){}}",
    332  },
    333  {
    334    name: "Unnamed class handling",
    335    input: "let unnamed=class{constructor(){}}",
    336  },
    337  {
    338    name: "Named class handling",
    339    input: "let unnamed=class Class{constructor(){}}",
    340  },
    341  {
    342    name: "Class extension within a function",
    343    input: "(function() {  class X extends Y { constructor() {} }  })()",
    344  },
    345  {
    346    name: "Bug 1261971 - indentation after switch statement",
    347    input: "{switch(x){}if(y){}done();}",
    348  },
    349  {
    350    name: "Bug 1206633 - spaces in for of",
    351    input: "for (let tab of tabs) {}",
    352  },
    353  {
    354    name: "Bug pretty-sure-3 - escaping line and paragraph separators",
    355    input: "x = '\\u2029\\u2028';",
    356  },
    357  {
    358    name: "Bug pretty-sure-4 - escaping null character before digit",
    359    input: "x = '\\u00001';",
    360  },
    361  {
    362    name: "Bug pretty-sure-5 - empty multiline comment shouldn't throw exception",
    363    input: `{
    364           /*
    365           */
    366             return;
    367           }`,
    368  },
    369  {
    370    name: "Bug pretty-sure-6 - inline comment shouldn't move parenthesis to next line",
    371    input: `return /* inline comment */ (
    372             1+1);`,
    373  },
    374  {
    375    name: "Bug pretty-sure-7 - accessing a literal number property requires a space",
    376    input: "0..toString()+x.toString();",
    377  },
    378  {
    379    name: "Bug pretty-sure-8 - return and yield only accept arguments when on the same line",
    380    input: `{
    381             return
    382             (x)
    383             yield
    384             (x)
    385             yield
    386             *x
    387           }`,
    388  },
    389  {
    390    name: "Bug pretty-sure-9 - accept unary operator at start of file",
    391    input: "+ 0",
    392  },
    393  {
    394    name: "Stack-keyword property access",
    395    input: "foo.a=1.1;foo.do.switch.case.default=2.2;foo.b=3.3;\n",
    396  },
    397  {
    398    name: "Dot handling with let which is identifier name",
    399    input: "y.let.let = 1.23;\n",
    400  },
    401  {
    402    name: "Dot handling with keywords which are identifier name",
    403    input: "y.await.break.const.delete.else.return.new.yield = 1.23;\n",
    404  },
    405  {
    406    name: "Optional chaining parsing support",
    407    input: "x?.y?.z?.['a']?.check();\n",
    408  },
    409  {
    410    name: "Private fields parsing support",
    411    input: `
    412      class MyClass {
    413        constructor(a) {
    414          this.#a = a;this.#b = Math.random();this.ab = this.#getAB();
    415        }
    416        #a
    417        #b = "default value"
    418        static #someStaticPrivate
    419        #getA() {
    420          return this.#a;
    421        }
    422        #getAB() {
    423          return this.#getA()+this.
    424            #b
    425        }
    426      }
    427    `,
    428  },
    429  {
    430    name: "Long parenthesis",
    431    input: `
    432      if (thisIsAVeryLongVariable && thisIsAnotherOne || yetAnotherVeryLongVariable) {
    433        (thisIsAnotherOne = thisMayReturnNull() || "hi", thisIsAVeryLongVariable = 42, yetAnotherVeryLongVariable && doSomething(true /* do it well */,thisIsAVeryLongVariable, thisIsAnotherOne, yetAnotherVeryLongVariable))
    434      }
    435      for (let thisIsAnotherVeryLongVariable = 0; i < thisIsAnotherVeryLongVariable.length; thisIsAnotherVeryLongVariable++) {}
    436      const x = ({thisIsAnotherVeryLongPropertyName: "but should not cause the paren to be a line delimiter"})
    437    `,
    438  },
    439  {
    440    name: "Fat arrow function",
    441    input: `
    442      const a = () => 42
    443      addEventListener("click", e => { return false });
    444      const sum = (c,d) => c+d
    445    `,
    446  },
    447 ];
    448 
    449 const includesOnly = cases.find(({ only }) => only);
    450 
    451 for (const { name, input, only, skip } of cases) {
    452  if ((includesOnly && !only) || skip) {
    453    continue;
    454  }
    455  // Wrapping name into a string to avoid jest/valid-title failures
    456  test(`${name}`, async () => {
    457    const actual = prettyFast(input, {
    458      indent: "  ",
    459      url: "test.js",
    460    });
    461 
    462    expect(actual.code).toMatchSnapshot();
    463 
    464    const smc = await new SourceMapConsumer(actual.map.toJSON());
    465    const mappings = [];
    466    smc.eachMapping(
    467      ({ generatedColumn, generatedLine, originalColumn, originalLine }) => {
    468        mappings.push(
    469          `(${originalLine}, ${originalColumn}) -> (${generatedLine}, ${generatedColumn})`
    470        );
    471      }
    472    );
    473    expect(mappings).toMatchSnapshot();
    474  });
    475 }