forked from mirrors/gecko-dev
Bug 1803360 - [devtools] Put pretty-fast library in tree. r=ochameau.
Differential Revision: https://phabricator.services.mozilla.com/D163560
This commit is contained in:
parent
79dd85e9fe
commit
60a24410b8
12 changed files with 14098 additions and 3388 deletions
|
|
@ -63,6 +63,7 @@ devtools/client/debugger/bin/
|
|||
devtools/client/debugger/configs/
|
||||
devtools/client/debugger/dist/
|
||||
devtools/client/debugger/images/
|
||||
devtools/client/debugger/packages/
|
||||
devtools/client/debugger/test/mochitest/examples/
|
||||
devtools/client/debugger/index.html
|
||||
devtools/client/debugger/webpack.config.js
|
||||
|
|
|
|||
|
|
@ -1250,7 +1250,10 @@
|
|||
"../node_modules/babel-loader/lib/index.js??ref--1!../../shared/vendor/source-map/lib/read-wasm.js": 1098,
|
||||
"../node_modules/babel-loader/lib/index.js??ref--1!../../shared/vendor/source-map/lib/url.js": 1099,
|
||||
"../node_modules/babel-loader/lib/index.js??ref--1!../../shared/vendor/whatwg-url.js": 1100,
|
||||
"../node_modules/path-browserify/index.js": 1101
|
||||
"../node_modules/path-browserify/index.js": 1101,
|
||||
"../node_modules/babel-loader/lib/index.js??ref--1!../packages/pretty-fast/pretty-fast.js": 1102,
|
||||
"../node_modules/acorn/dist/acorn.mjs": 1103,
|
||||
"../packages/pretty-fast/node_modules/acorn/dist/acorn.mjs": 1104
|
||||
},
|
||||
"usedIds": {
|
||||
"0": 0,
|
||||
|
|
@ -2354,7 +2357,10 @@
|
|||
"1098": 1098,
|
||||
"1099": 1099,
|
||||
"1100": 1100,
|
||||
"1101": 1101
|
||||
"1101": 1101,
|
||||
"1102": 1102,
|
||||
"1103": 1103,
|
||||
"1104": 1104
|
||||
}
|
||||
},
|
||||
"chunks": {
|
||||
|
|
|
|||
6614
devtools/client/debugger/dist/pretty-print-worker.js
vendored
6614
devtools/client/debugger/dist/pretty-print-worker.js
vendored
File diff suppressed because it is too large
Load diff
|
|
@ -25,7 +25,6 @@
|
|||
"codemirror": "^5.28.0",
|
||||
"fuzzaldrin-plus": "^0.6.0",
|
||||
"parse-script-tags": "github:loganfsmyth/parse-script-tags#d771732ca47e1b3554fe67d609fd18cc785c5f26",
|
||||
"pretty-fast": "^0.2.7",
|
||||
"react": "16.8.6",
|
||||
"react-aria-components": "^0.0.4",
|
||||
"react-dom": "16.8.6",
|
||||
|
|
|
|||
23
devtools/client/debugger/packages/pretty-fast/LICENSE.md
Normal file
23
devtools/client/debugger/packages/pretty-fast/LICENSE.md
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
Copyright (c) 2013, Nick Fitzgerald
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
73
devtools/client/debugger/packages/pretty-fast/README.md
Normal file
73
devtools/client/debugger/packages/pretty-fast/README.md
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
# Pretty Fast
|
||||
|
||||
Pretty Fast is a source-map-generating JavaScript pretty printer, that is pretty
|
||||
fast.
|
||||
|
||||
[](https://travis-ci.org/mozilla/pretty-fast)
|
||||
|
||||
## Install
|
||||
|
||||
npm install pretty-fast
|
||||
|
||||
## Usage
|
||||
|
||||
var prettyFast = require("pretty-fast");
|
||||
|
||||
var uglyJS = "function ugly(){code()}";
|
||||
|
||||
var pretty = prettyFast(uglyJS, {
|
||||
url: "test.js",
|
||||
indent: " "
|
||||
});
|
||||
|
||||
console.log(pretty.code);
|
||||
// function ugly() {
|
||||
// code()
|
||||
// }
|
||||
|
||||
console.log(pretty.map);
|
||||
// [object SourceMapGenerator]
|
||||
|
||||
(See the [mozilla/source-map][0] library for information on SourceMapGenerator
|
||||
instances, and source maps in general.)
|
||||
|
||||
[0]: https://github.com/mozilla/source-map
|
||||
|
||||
## Options
|
||||
|
||||
* `url` - The URL of the JavaScript source being prettified. Used in the
|
||||
generated source map. If you are prettifying JS that isn't from a file or
|
||||
doesn't have a URL, you can use a dummy value, such as "(anonymous)".
|
||||
|
||||
* `indent` - The string that you want your code indented by. Most people want
|
||||
one of `" "`, `" "`, or `"\t"`.
|
||||
|
||||
* `ecmaVersion` - Indicates the ECMAScript version to parse.
|
||||
See acorn.parse documentation for more details. Defaults to `"latest"`.
|
||||
|
||||
## Issues
|
||||
|
||||
[Please use Bugzilla](https://bugzilla.mozilla.org/enter_bug.cgi?product=Firefox&component=Developer%20Tools%3A%20Debugger)
|
||||
|
||||
## Goals
|
||||
|
||||
* To be pretty fast, while still generating source maps.
|
||||
|
||||
* To avoid fully parsing the source text; we should be able to get away with
|
||||
only a tokenizer and some heuristics.
|
||||
|
||||
* Preserve comments.
|
||||
|
||||
* Pretty Fast should be able to run inside Web Workers.
|
||||
|
||||
## Non-goals
|
||||
|
||||
* Extreme configurability of types of indentation, where curly braces go, etc.
|
||||
|
||||
* To be the very fastest pretty printer in the universe. This goal is
|
||||
unattainable given that generating source maps is a requirement. We just need
|
||||
to be Pretty Fast.
|
||||
|
||||
* To perfectly pretty print *exactly* as you would have written the code. This
|
||||
falls out from both not wanting to support extreme configurability, and
|
||||
avoiding full on parsing. We just aim to pretty print Pretty Well.
|
||||
File diff suppressed because it is too large
Load diff
6268
devtools/client/debugger/packages/pretty-fast/package-lock.json
generated
Normal file
6268
devtools/client/debugger/packages/pretty-fast/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
26
devtools/client/debugger/packages/pretty-fast/package.json
Normal file
26
devtools/client/debugger/packages/pretty-fast/package.json
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"name": "pretty-fast",
|
||||
"version": "0.2.7",
|
||||
"description": "A fast JavaScript pretty printer.",
|
||||
"author": "Nick Fitzgerald <fitzgen@gmail.com>",
|
||||
"homepage": "https://github.com/mozilla/pretty-fast",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/mozilla/pretty-fast.git"
|
||||
},
|
||||
"license": "BSD",
|
||||
"main": "pretty-fast.js",
|
||||
"scripts": {
|
||||
"eslint": "eslint -f compact *.js",
|
||||
"test": "jest"
|
||||
},
|
||||
"devDependencies": {
|
||||
"chalk": "^3.0.0",
|
||||
"eslint": "6.6.0",
|
||||
"jest": "^25.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"source-map": "^0.5.7",
|
||||
"acorn": "~8.2.4"
|
||||
}
|
||||
}
|
||||
999
devtools/client/debugger/packages/pretty-fast/pretty-fast.js
Normal file
999
devtools/client/debugger/packages/pretty-fast/pretty-fast.js
Normal file
|
|
@ -0,0 +1,999 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
|
||||
|
||||
(function(root, factory) {
|
||||
"use strict";
|
||||
|
||||
if (typeof define === "function" && define.amd) {
|
||||
define(factory);
|
||||
} else if (typeof exports === "object") {
|
||||
module.exports = factory();
|
||||
} else {
|
||||
root.prettyFast = factory();
|
||||
}
|
||||
})(
|
||||
this,
|
||||
function() {
|
||||
"use strict";
|
||||
|
||||
var acorn = this.acorn || require("acorn");
|
||||
var sourceMap = this.sourceMap || require("source-map");
|
||||
var SourceNode = sourceMap.SourceNode;
|
||||
|
||||
// If any of these tokens are seen before a "[" token, we know that "[" token
|
||||
// is the start of an array literal, rather than a property access.
|
||||
//
|
||||
// The only exception is "}", which would need to be disambiguated by
|
||||
// parsing. The majority of the time, an open bracket following a closing
|
||||
// curly is going to be an array literal, so we brush the complication under
|
||||
// the rug, and handle the ambiguity by always assuming that it will be an
|
||||
// array literal.
|
||||
var PRE_ARRAY_LITERAL_TOKENS = {
|
||||
typeof: true,
|
||||
void: true,
|
||||
delete: true,
|
||||
case: true,
|
||||
do: true,
|
||||
"=": true,
|
||||
in: true,
|
||||
"{": true,
|
||||
"*": true,
|
||||
"/": true,
|
||||
"%": true,
|
||||
else: true,
|
||||
";": true,
|
||||
"++": true,
|
||||
"--": true,
|
||||
"+": true,
|
||||
"-": true,
|
||||
"~": true,
|
||||
"!": true,
|
||||
":": true,
|
||||
"?": true,
|
||||
">>": true,
|
||||
">>>": true,
|
||||
"<<": true,
|
||||
"||": true,
|
||||
"&&": true,
|
||||
"<": true,
|
||||
">": true,
|
||||
"<=": true,
|
||||
">=": true,
|
||||
instanceof: true,
|
||||
"&": true,
|
||||
"^": true,
|
||||
"|": true,
|
||||
"==": true,
|
||||
"!=": true,
|
||||
"===": true,
|
||||
"!==": true,
|
||||
",": true,
|
||||
|
||||
"}": true,
|
||||
};
|
||||
|
||||
/**
|
||||
* Determines if we think that the given token starts an array literal.
|
||||
*
|
||||
* @param Object token
|
||||
* The token we want to determine if it is an array literal.
|
||||
* @param Object lastToken
|
||||
* The last token we added to the pretty printed results.
|
||||
*
|
||||
* @returns Boolean
|
||||
* True if we believe it is an array literal, false otherwise.
|
||||
*/
|
||||
function isArrayLiteral(token, lastToken) {
|
||||
if (token.type.label != "[") {
|
||||
return false;
|
||||
}
|
||||
if (!lastToken) {
|
||||
return true;
|
||||
}
|
||||
if (lastToken.type.isAssign) {
|
||||
return true;
|
||||
}
|
||||
return !!PRE_ARRAY_LITERAL_TOKENS[
|
||||
lastToken.type.keyword || lastToken.type.label
|
||||
];
|
||||
}
|
||||
|
||||
// If any of these tokens are followed by a token on a new line, we know that
|
||||
// ASI cannot happen.
|
||||
var PREVENT_ASI_AFTER_TOKENS = {
|
||||
// Binary operators
|
||||
"*": true,
|
||||
"/": true,
|
||||
"%": true,
|
||||
"+": true,
|
||||
"-": true,
|
||||
"<<": true,
|
||||
">>": true,
|
||||
">>>": true,
|
||||
"<": true,
|
||||
">": true,
|
||||
"<=": true,
|
||||
">=": true,
|
||||
instanceof: true,
|
||||
in: true,
|
||||
"==": true,
|
||||
"!=": true,
|
||||
"===": true,
|
||||
"!==": true,
|
||||
"&": true,
|
||||
"^": true,
|
||||
"|": true,
|
||||
"&&": true,
|
||||
"||": true,
|
||||
",": true,
|
||||
".": true,
|
||||
"=": true,
|
||||
"*=": true,
|
||||
"/=": true,
|
||||
"%=": true,
|
||||
"+=": true,
|
||||
"-=": true,
|
||||
"<<=": true,
|
||||
">>=": true,
|
||||
">>>=": true,
|
||||
"&=": true,
|
||||
"^=": true,
|
||||
"|=": true,
|
||||
// Unary operators
|
||||
delete: true,
|
||||
void: true,
|
||||
typeof: true,
|
||||
"~": true,
|
||||
"!": true,
|
||||
new: true,
|
||||
// Function calls and grouped expressions
|
||||
"(": true,
|
||||
};
|
||||
|
||||
// If any of these tokens are on a line after the token before it, we know
|
||||
// that ASI cannot happen.
|
||||
var PREVENT_ASI_BEFORE_TOKENS = {
|
||||
// Binary operators
|
||||
"*": true,
|
||||
"/": true,
|
||||
"%": true,
|
||||
"<<": true,
|
||||
">>": true,
|
||||
">>>": true,
|
||||
"<": true,
|
||||
">": true,
|
||||
"<=": true,
|
||||
">=": true,
|
||||
instanceof: true,
|
||||
in: true,
|
||||
"==": true,
|
||||
"!=": true,
|
||||
"===": true,
|
||||
"!==": true,
|
||||
"&": true,
|
||||
"^": true,
|
||||
"|": true,
|
||||
"&&": true,
|
||||
"||": true,
|
||||
",": true,
|
||||
".": true,
|
||||
"=": true,
|
||||
"*=": true,
|
||||
"/=": true,
|
||||
"%=": true,
|
||||
"+=": true,
|
||||
"-=": true,
|
||||
"<<=": true,
|
||||
">>=": true,
|
||||
">>>=": true,
|
||||
"&=": true,
|
||||
"^=": true,
|
||||
"|=": true,
|
||||
// Function calls
|
||||
"(": true,
|
||||
};
|
||||
|
||||
/**
|
||||
* Determine if a token can look like an identifier. More precisely,
|
||||
* this determines if the token may end or start with a character from
|
||||
* [A-Za-z0-9_].
|
||||
*
|
||||
* @param Object token
|
||||
* The token we are looking at.
|
||||
*
|
||||
* @returns Boolean
|
||||
* True if identifier-like.
|
||||
*/
|
||||
function isIdentifierLike(token) {
|
||||
var ttl = token.type.label;
|
||||
return (
|
||||
ttl == "name" ||
|
||||
ttl == "num" ||
|
||||
ttl == "privateId" ||
|
||||
!!token.type.keyword
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if Automatic Semicolon Insertion (ASI) occurs between these
|
||||
* tokens.
|
||||
*
|
||||
* @param Object token
|
||||
* The current token.
|
||||
* @param Object lastToken
|
||||
* The last token we added to the pretty printed results.
|
||||
*
|
||||
* @returns Boolean
|
||||
* True if we believe ASI occurs.
|
||||
*/
|
||||
function isASI(token, lastToken) {
|
||||
if (!lastToken) {
|
||||
return false;
|
||||
}
|
||||
if (token.loc.start.line === lastToken.loc.start.line) {
|
||||
return false;
|
||||
}
|
||||
if (
|
||||
lastToken.type.keyword == "return" ||
|
||||
lastToken.type.keyword == "yield" ||
|
||||
(lastToken.type.label == "name" && lastToken.value == "yield")
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
if (
|
||||
PREVENT_ASI_AFTER_TOKENS[lastToken.type.label || lastToken.type.keyword]
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
if (PREVENT_ASI_BEFORE_TOKENS[token.type.label || token.type.keyword]) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if we should add a newline after the given token.
|
||||
*
|
||||
* @param Object token
|
||||
* The token we are looking at.
|
||||
* @param Array stack
|
||||
* The stack of open parens/curlies/brackets/etc.
|
||||
*
|
||||
* @returns Boolean
|
||||
* True if we should add a newline.
|
||||
*/
|
||||
function isLineDelimiter(token, stack) {
|
||||
if (token.isArrayLiteral) {
|
||||
return true;
|
||||
}
|
||||
var ttl = token.type.label;
|
||||
var top = stack[stack.length - 1];
|
||||
return (
|
||||
(ttl == ";" && top != "(") ||
|
||||
ttl == "{" ||
|
||||
(ttl == "," && top != "(") ||
|
||||
(ttl == ":" && (top == "case" || top == "default"))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Append the necessary whitespace to the result after we have added the given
|
||||
* token.
|
||||
*
|
||||
* @param Object token
|
||||
* The token that was just added to the result.
|
||||
* @param Function write
|
||||
* The function to write to the pretty printed results.
|
||||
* @param Array stack
|
||||
* The stack of open parens/curlies/brackets/etc.
|
||||
*
|
||||
* @returns Boolean
|
||||
* Returns true if we added a newline to result, false in all other
|
||||
* cases.
|
||||
*/
|
||||
function appendNewline(token, write, stack) {
|
||||
if (isLineDelimiter(token, stack)) {
|
||||
write("\n", token.loc.start.line, token.loc.start.column);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if we need to add a space between the last token we added and
|
||||
* the token we are about to add.
|
||||
*
|
||||
* @param Object token
|
||||
* The token we are about to add to the pretty printed code.
|
||||
* @param Object lastToken
|
||||
* The last token added to the pretty printed code.
|
||||
*/
|
||||
function needsSpaceAfter(token, lastToken) {
|
||||
if (lastToken) {
|
||||
if (lastToken.type.isLoop) {
|
||||
return true;
|
||||
}
|
||||
if (lastToken.type.isAssign) {
|
||||
return true;
|
||||
}
|
||||
if (lastToken.type.binop != null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
var ltt = lastToken.type.label;
|
||||
if (ltt == "?") {
|
||||
return true;
|
||||
}
|
||||
if (ltt == ":") {
|
||||
return true;
|
||||
}
|
||||
if (ltt == ",") {
|
||||
return true;
|
||||
}
|
||||
if (ltt == ";") {
|
||||
return true;
|
||||
}
|
||||
if (ltt == "${") {
|
||||
return true;
|
||||
}
|
||||
if (ltt == "num" && token.type.label == ".") {
|
||||
return true;
|
||||
}
|
||||
|
||||
var ltk = lastToken.type.keyword;
|
||||
var ttl = token.type.label;
|
||||
if (ltk != null && ttl != ".") {
|
||||
if (ltk == "break" || ltk == "continue" || ltk == "return") {
|
||||
return token.type.label != ";";
|
||||
}
|
||||
if (
|
||||
ltk != "debugger" &&
|
||||
ltk != "null" &&
|
||||
ltk != "true" &&
|
||||
ltk != "false" &&
|
||||
ltk != "this" &&
|
||||
ltk != "default"
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
ltt == ")" &&
|
||||
token.type.label != ")" &&
|
||||
token.type.label != "]" &&
|
||||
token.type.label != ";" &&
|
||||
token.type.label != "," &&
|
||||
token.type.label != "."
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (isIdentifierLike(token) && isIdentifierLike(lastToken)) {
|
||||
// We must emit a space to avoid merging the tokens.
|
||||
return true;
|
||||
}
|
||||
|
||||
if (token.type.label == "{" && lastToken.type.label == "name") {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (token.type.isAssign) {
|
||||
return true;
|
||||
}
|
||||
if (token.type.binop != null && lastToken) {
|
||||
return true;
|
||||
}
|
||||
if (token.type.label == "?") {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the required whitespace before this token, whether that is a single
|
||||
* space, newline, and/or the indent on fresh lines.
|
||||
*
|
||||
* @param Object token
|
||||
* The token we are about to add to the pretty printed code.
|
||||
* @param Object lastToken
|
||||
* The last token we added to the pretty printed code.
|
||||
* @param Boolean addedNewline
|
||||
* Whether we added a newline after adding the last token to the pretty
|
||||
* printed code.
|
||||
* @param Boolean addedSpace
|
||||
* Whether we added a space after adding the last token to the pretty
|
||||
* printed code. This only happens if an inline comment was printed
|
||||
* since the last token.
|
||||
* @param Function write
|
||||
* The function to write pretty printed code to the result SourceNode.
|
||||
* @param Object options
|
||||
* The options object.
|
||||
* @param Number indentLevel
|
||||
* The number of indents deep we are.
|
||||
* @param Array stack
|
||||
* The stack of open curlies, brackets, etc.
|
||||
*/
|
||||
function prependWhiteSpace(
|
||||
token,
|
||||
lastToken,
|
||||
addedNewline,
|
||||
addedSpace,
|
||||
write,
|
||||
options,
|
||||
indentLevel,
|
||||
stack
|
||||
) {
|
||||
var ttk = token.type.keyword;
|
||||
var ttl = token.type.label;
|
||||
var newlineAdded = addedNewline;
|
||||
var spaceAdded = addedSpace;
|
||||
var ltt = lastToken ? lastToken.type.label : null;
|
||||
|
||||
// Handle whitespace and newlines after "}" here instead of in
|
||||
// `isLineDelimiter` because it is only a line delimiter some of the
|
||||
// time. For example, we don't want to put "else if" on a new line after
|
||||
// the first if's block.
|
||||
if (lastToken && ltt == "}") {
|
||||
if (ttk == "while" && stack[stack.length - 1] == "do") {
|
||||
write(" ", lastToken.loc.start.line, lastToken.loc.start.column);
|
||||
spaceAdded = true;
|
||||
} else if (ttk == "else" || ttk == "catch" || ttk == "finally") {
|
||||
write(" ", lastToken.loc.start.line, lastToken.loc.start.column);
|
||||
spaceAdded = true;
|
||||
} else if (
|
||||
ttl != "(" &&
|
||||
ttl != ";" &&
|
||||
ttl != "," &&
|
||||
ttl != ")" &&
|
||||
ttl != "." &&
|
||||
ttl != "template" &&
|
||||
ttl != "`"
|
||||
) {
|
||||
write("\n", lastToken.loc.start.line, lastToken.loc.start.column);
|
||||
newlineAdded = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
(ttl == ":" && stack[stack.length - 1] == "?") ||
|
||||
(ttl == "}" && stack[stack.length - 1] == "${")
|
||||
) {
|
||||
write(" ", lastToken.loc.start.line, lastToken.loc.start.column);
|
||||
spaceAdded = true;
|
||||
}
|
||||
|
||||
if (lastToken && ltt != "}" && ltt != "." && ttk == "else") {
|
||||
write(" ", lastToken.loc.start.line, lastToken.loc.start.column);
|
||||
spaceAdded = true;
|
||||
}
|
||||
|
||||
function ensureNewline() {
|
||||
if (!newlineAdded) {
|
||||
write("\n", lastToken.loc.start.line, lastToken.loc.start.column);
|
||||
newlineAdded = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (isASI(token, lastToken)) {
|
||||
ensureNewline();
|
||||
}
|
||||
|
||||
if (decrementsIndent(ttl, stack)) {
|
||||
ensureNewline();
|
||||
}
|
||||
|
||||
if (newlineAdded) {
|
||||
if (ttk == "case" || ttk == "default") {
|
||||
write(
|
||||
repeat(options.indent, indentLevel - 1),
|
||||
token.loc.start.line,
|
||||
token.loc.start.column
|
||||
);
|
||||
} else {
|
||||
write(
|
||||
repeat(options.indent, indentLevel),
|
||||
token.loc.start.line,
|
||||
token.loc.start.column
|
||||
);
|
||||
}
|
||||
} else if (!spaceAdded && needsSpaceAfter(token, lastToken)) {
|
||||
write(" ", lastToken.loc.start.line, lastToken.loc.start.column);
|
||||
spaceAdded = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Repeat the `str` string `n` times.
|
||||
*
|
||||
* @param String str
|
||||
* The string to be repeated.
|
||||
* @param Number n
|
||||
* The number of times to repeat the string.
|
||||
*
|
||||
* @returns String
|
||||
* The repeated string.
|
||||
*/
|
||||
function repeat(str, n) {
|
||||
var result = "";
|
||||
while (n > 0) {
|
||||
if (n & 1) {
|
||||
result += str;
|
||||
}
|
||||
n >>= 1;
|
||||
str += str;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure that we output the escaped character combination inside string
|
||||
* literals instead of various problematic characters.
|
||||
*/
|
||||
var sanitize = (function() {
|
||||
var escapeCharacters = {
|
||||
// Backslash
|
||||
"\\": "\\\\",
|
||||
// Newlines
|
||||
"\n": "\\n",
|
||||
// Carriage return
|
||||
"\r": "\\r",
|
||||
// Tab
|
||||
"\t": "\\t",
|
||||
// Vertical tab
|
||||
"\v": "\\v",
|
||||
// Form feed
|
||||
"\f": "\\f",
|
||||
// Null character
|
||||
"\0": "\\x00",
|
||||
// Line separator
|
||||
"\u2028": "\\u2028",
|
||||
// Paragraph separator
|
||||
"\u2029": "\\u2029",
|
||||
// Single quotes
|
||||
"'": "\\'",
|
||||
};
|
||||
|
||||
var regExpString =
|
||||
"(" +
|
||||
Object.keys(escapeCharacters)
|
||||
.map(function(c) {
|
||||
return escapeCharacters[c];
|
||||
})
|
||||
.join("|") +
|
||||
")";
|
||||
var escapeCharactersRegExp = new RegExp(regExpString, "g");
|
||||
|
||||
return function(str) {
|
||||
return str.replace(escapeCharactersRegExp, function(_, c) {
|
||||
return escapeCharacters[c];
|
||||
});
|
||||
};
|
||||
})();
|
||||
/**
|
||||
* Add the given token to the pretty printed results.
|
||||
*
|
||||
* @param Object token
|
||||
* The token to add.
|
||||
* @param Function write
|
||||
* The function to write pretty printed code to the result SourceNode.
|
||||
*/
|
||||
function addToken(token, write) {
|
||||
if (token.type.label == "string") {
|
||||
write(
|
||||
"'" + sanitize(token.value) + "'",
|
||||
token.loc.start.line,
|
||||
token.loc.start.column
|
||||
);
|
||||
} else if (token.type.label == "regexp") {
|
||||
write(
|
||||
String(token.value.value),
|
||||
token.loc.start.line,
|
||||
token.loc.start.column
|
||||
);
|
||||
} else {
|
||||
let value;
|
||||
if (token.value != null) {
|
||||
value = token.value;
|
||||
if (token.type.label === "privateId") {
|
||||
value = `#${value}`;
|
||||
}
|
||||
} else {
|
||||
value = token.type.label;
|
||||
}
|
||||
write(String(value), token.loc.start.line, token.loc.start.column);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given token type belongs on the stack.
|
||||
*/
|
||||
function belongsOnStack(token) {
|
||||
var ttl = token.type.label;
|
||||
var ttk = token.type.keyword;
|
||||
return (
|
||||
ttl == "{" ||
|
||||
ttl == "(" ||
|
||||
ttl == "[" ||
|
||||
ttl == "?" ||
|
||||
ttl == "${" ||
|
||||
ttk == "do" ||
|
||||
ttk == "switch" ||
|
||||
ttk == "case" ||
|
||||
ttk == "default"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given token should cause us to pop the stack.
|
||||
*/
|
||||
function shouldStackPop(token, stack) {
|
||||
var ttl = token.type.label;
|
||||
var ttk = token.type.keyword;
|
||||
var top = stack[stack.length - 1];
|
||||
return (
|
||||
ttl == "]" ||
|
||||
ttl == ")" ||
|
||||
ttl == "}" ||
|
||||
(ttl == ":" && (top == "case" || top == "default" || top == "?")) ||
|
||||
(ttk == "while" && top == "do")
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given token type should cause us to decrement the
|
||||
* indent level.
|
||||
*/
|
||||
function decrementsIndent(tokenType, stack) {
|
||||
return (
|
||||
(tokenType == "}" && stack[stack.length - 1] != "${") ||
|
||||
(tokenType == "]" && stack[stack.length - 1] == "[\n")
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given token should cause us to increment the indent
|
||||
* level.
|
||||
*/
|
||||
function incrementsIndent(token) {
|
||||
return (
|
||||
token.type.label == "{" ||
|
||||
token.isArrayLiteral ||
|
||||
token.type.keyword == "switch"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a comment to the pretty printed code.
|
||||
*
|
||||
* @param Function write
|
||||
* The function to write pretty printed code to the result SourceNode.
|
||||
* @param Number indentLevel
|
||||
* The number of indents deep we are.
|
||||
* @param Object options
|
||||
* The options object.
|
||||
* @param Boolean block
|
||||
* True if the comment is a multiline block style comment.
|
||||
* @param String text
|
||||
* The text of the comment.
|
||||
* @param Number line
|
||||
* The line number to comment appeared on.
|
||||
* @param Number column
|
||||
* The column number the comment appeared on.
|
||||
* @param Object nextToken
|
||||
* The next token if any.
|
||||
*
|
||||
* @returns Boolean newlineAdded
|
||||
* True if a newline was added.
|
||||
*/
|
||||
function addComment(
|
||||
write,
|
||||
indentLevel,
|
||||
options,
|
||||
block,
|
||||
text,
|
||||
line,
|
||||
column,
|
||||
nextToken
|
||||
) {
|
||||
var indentString = repeat(options.indent, indentLevel);
|
||||
var needNewline = true;
|
||||
|
||||
write(indentString, line, column);
|
||||
if (block) {
|
||||
write("/*");
|
||||
// We must pass ignoreNewline in case the comment happens to be "\n".
|
||||
write(
|
||||
text
|
||||
.split(new RegExp("/\n" + indentString + "/", "g"))
|
||||
.join("\n" + indentString),
|
||||
null,
|
||||
null,
|
||||
true
|
||||
);
|
||||
write("*/");
|
||||
needNewline = !(nextToken && nextToken.loc.start.line == line);
|
||||
} else {
|
||||
write("//");
|
||||
write(text);
|
||||
}
|
||||
if (needNewline) {
|
||||
write("\n");
|
||||
} else {
|
||||
write(" ");
|
||||
}
|
||||
return needNewline;
|
||||
}
|
||||
|
||||
/**
|
||||
* The main function.
|
||||
*
|
||||
* @param String input
|
||||
* The ugly JS code we want to pretty print.
|
||||
* @param Object options
|
||||
* The options object. Provides configurability of the pretty
|
||||
* printing. Properties:
|
||||
* - url: The URL string of the ugly JS code.
|
||||
* - indent: The string to indent code by.
|
||||
*
|
||||
* @returns Object
|
||||
* An object with the following properties:
|
||||
* - code: The pretty printed code string.
|
||||
* - map: A SourceMapGenerator instance.
|
||||
*/
|
||||
return function prettyFast(input, options) {
|
||||
// The level of indents deep we are.
|
||||
var indentLevel = 0;
|
||||
|
||||
// We will accumulate the pretty printed code in this SourceNode.
|
||||
var result = new SourceNode();
|
||||
|
||||
/**
|
||||
* Write a pretty printed string to the result SourceNode.
|
||||
*
|
||||
* We buffer our writes so that we only create one mapping for each line in
|
||||
* the source map. This enhances performance by avoiding extraneous mapping
|
||||
* serialization, and flattening the tree that
|
||||
* `SourceNode#toStringWithSourceMap` will have to recursively walk. When
|
||||
* timing how long it takes to pretty print jQuery, this optimization
|
||||
* brought the time down from ~390 ms to ~190ms!
|
||||
*
|
||||
* @param String str
|
||||
* The string to be added to the result.
|
||||
* @param Number line
|
||||
* The line number the string came from in the ugly source.
|
||||
* @param Number column
|
||||
* The column number the string came from in the ugly source.
|
||||
* @param Boolean ignoreNewline
|
||||
* If true, a single "\n" won't result in an additional mapping.
|
||||
*/
|
||||
var write = (function() {
|
||||
var buffer = [];
|
||||
var bufferLine = -1;
|
||||
var bufferColumn = -1;
|
||||
return function write(str, line, column, ignoreNewline) {
|
||||
if (line != null && bufferLine === -1) {
|
||||
bufferLine = line;
|
||||
}
|
||||
if (column != null && bufferColumn === -1) {
|
||||
bufferColumn = column;
|
||||
}
|
||||
buffer.push(str);
|
||||
|
||||
if (str == "\n" && !ignoreNewline) {
|
||||
var lineStr = "";
|
||||
for (var i = 0, len = buffer.length; i < len; i++) {
|
||||
lineStr += buffer[i];
|
||||
}
|
||||
result.add(
|
||||
new SourceNode(bufferLine, bufferColumn, options.url, lineStr)
|
||||
);
|
||||
buffer.splice(0, buffer.length);
|
||||
bufferLine = -1;
|
||||
bufferColumn = -1;
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
// Whether or not we added a newline on after we added the last token.
|
||||
var addedNewline = false;
|
||||
|
||||
// Whether or not we added a space after we added the last token.
|
||||
var addedSpace = false;
|
||||
|
||||
// The current token we will be adding to the pretty printed code.
|
||||
var token;
|
||||
|
||||
// Shorthand for token.type.label, so we don't have to repeatedly access
|
||||
// properties.
|
||||
var ttl;
|
||||
|
||||
// Shorthand for token.type.keyword, so we don't have to repeatedly access
|
||||
// properties.
|
||||
var ttk;
|
||||
|
||||
// The last token we added to the pretty printed code.
|
||||
var lastToken;
|
||||
|
||||
// Stack of token types/keywords that can affect whether we want to add a
|
||||
// newline or a space. We can make that decision based on what token type is
|
||||
// on the top of the stack. For example, a comma in a parameter list should
|
||||
// be followed by a space, while a comma in an object literal should be
|
||||
// followed by a newline.
|
||||
//
|
||||
// Strings that go on the stack:
|
||||
//
|
||||
// - "{"
|
||||
// - "("
|
||||
// - "["
|
||||
// - "[\n"
|
||||
// - "do"
|
||||
// - "?"
|
||||
// - "switch"
|
||||
// - "case"
|
||||
// - "default"
|
||||
//
|
||||
// The difference between "[" and "[\n" is that "[\n" is used when we are
|
||||
// treating "[" and "]" tokens as line delimiters and should increment and
|
||||
// decrement the indent level when we find them.
|
||||
var stack = [];
|
||||
|
||||
// Pass through acorn's tokenizer and append tokens and comments into a
|
||||
// single queue to process. For example, the source file:
|
||||
//
|
||||
// foo
|
||||
// // a
|
||||
// // b
|
||||
// bar
|
||||
//
|
||||
// After this process, tokenQueue has the following token stream:
|
||||
//
|
||||
// [ foo, '// a', '// b', bar]
|
||||
var tokenQueue = [];
|
||||
|
||||
var tokens = acorn.tokenizer(input, {
|
||||
locations: true,
|
||||
sourceFile: options.url,
|
||||
ecmaVersion: options.ecmaVersion || "latest",
|
||||
onComment(block, text, start, end, startLoc, endLoc) {
|
||||
tokenQueue.push({
|
||||
type: {},
|
||||
comment: true,
|
||||
block,
|
||||
text,
|
||||
loc: { start: startLoc, end: endLoc },
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
for (;;) {
|
||||
token = tokens.getToken();
|
||||
tokenQueue.push(token);
|
||||
if (token.type.label == "eof") {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < tokenQueue.length; i++) {
|
||||
token = tokenQueue[i];
|
||||
var nextToken = tokenQueue[i + 1];
|
||||
|
||||
if (token.comment) {
|
||||
var commentIndentLevel = indentLevel;
|
||||
if (lastToken && lastToken.loc.end.line == token.loc.start.line) {
|
||||
commentIndentLevel = 0;
|
||||
write(" ");
|
||||
}
|
||||
addedNewline = addComment(
|
||||
write,
|
||||
commentIndentLevel,
|
||||
options,
|
||||
token.block,
|
||||
token.text,
|
||||
token.loc.start.line,
|
||||
token.loc.start.column,
|
||||
nextToken
|
||||
);
|
||||
addedSpace = !addedNewline;
|
||||
continue;
|
||||
}
|
||||
|
||||
ttk = token.type.keyword;
|
||||
|
||||
if (ttk && lastToken && lastToken.type.label == ".") {
|
||||
token.type = acorn.tokTypes.name;
|
||||
}
|
||||
|
||||
ttl = token.type.label;
|
||||
|
||||
if (ttl == "eof") {
|
||||
if (!addedNewline) {
|
||||
write("\n");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
token.isArrayLiteral = isArrayLiteral(token, lastToken);
|
||||
|
||||
if (belongsOnStack(token)) {
|
||||
if (token.isArrayLiteral) {
|
||||
stack.push("[\n");
|
||||
} else {
|
||||
stack.push(ttl || ttk);
|
||||
}
|
||||
}
|
||||
|
||||
if (decrementsIndent(ttl, stack)) {
|
||||
indentLevel--;
|
||||
if (
|
||||
ttl == "}" &&
|
||||
stack.length > 1 &&
|
||||
stack[stack.length - 2] == "switch"
|
||||
) {
|
||||
indentLevel--;
|
||||
}
|
||||
}
|
||||
|
||||
prependWhiteSpace(
|
||||
token,
|
||||
lastToken,
|
||||
addedNewline,
|
||||
addedSpace,
|
||||
write,
|
||||
options,
|
||||
indentLevel,
|
||||
stack
|
||||
);
|
||||
addToken(token, write);
|
||||
addedSpace = false;
|
||||
|
||||
// If the next token is going to be a comment starting on the same line,
|
||||
// then no need to add one here
|
||||
if (
|
||||
!nextToken ||
|
||||
!nextToken.comment ||
|
||||
token.loc.end.line != nextToken.loc.start.line
|
||||
) {
|
||||
addedNewline = appendNewline(token, write, stack);
|
||||
}
|
||||
|
||||
if (shouldStackPop(token, stack)) {
|
||||
stack.pop();
|
||||
if (
|
||||
ttl == "}" &&
|
||||
stack.length &&
|
||||
stack[stack.length - 1] == "switch"
|
||||
) {
|
||||
stack.pop();
|
||||
}
|
||||
}
|
||||
|
||||
if (incrementsIndent(token)) {
|
||||
indentLevel++;
|
||||
}
|
||||
|
||||
// Acorn's tokenizer re-uses tokens, so we have to copy the last token on
|
||||
// every iteration. We follow acorn's lead here, and reuse the lastToken
|
||||
// object the same way that acorn reuses the token object. This allows us
|
||||
// to avoid allocations and minimize GC pauses.
|
||||
if (!lastToken) {
|
||||
lastToken = { loc: { start: {}, end: {} } };
|
||||
}
|
||||
lastToken.start = token.start;
|
||||
lastToken.end = token.end;
|
||||
lastToken.loc.start.line = token.loc.start.line;
|
||||
lastToken.loc.start.column = token.loc.start.column;
|
||||
lastToken.loc.end.line = token.loc.end.line;
|
||||
lastToken.loc.end.column = token.loc.end.column;
|
||||
lastToken.type = token.type;
|
||||
lastToken.value = token.value;
|
||||
lastToken.isArrayLiteral = token.isArrayLiteral;
|
||||
}
|
||||
|
||||
return result.toStringWithSourceMap({ file: options.url });
|
||||
};
|
||||
}.bind(this)
|
||||
);
|
||||
423
devtools/client/debugger/packages/pretty-fast/test.js
Normal file
423
devtools/client/debugger/packages/pretty-fast/test.js
Normal file
|
|
@ -0,0 +1,423 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
|
||||
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
* Copyright 2013 Mozilla Foundation and contributors
|
||||
* Licensed under the New BSD license. See LICENSE.md or:
|
||||
* http://opensource.org/licenses/BSD-2-Clause
|
||||
*/
|
||||
const prettyFast = require("./pretty-fast");
|
||||
const chalk = require("chalk");
|
||||
|
||||
const cases = [
|
||||
{
|
||||
name: "Simple function",
|
||||
input: "function foo() { bar(); }",
|
||||
},
|
||||
{
|
||||
name: "Nested function",
|
||||
input: "function foo() { function bar() { debugger; } bar(); }",
|
||||
},
|
||||
{
|
||||
name: "Immediately invoked function expression",
|
||||
input: "(function(){thingy()}())",
|
||||
},
|
||||
{
|
||||
name: "Single line comment",
|
||||
input: `
|
||||
// Comment
|
||||
function foo() { bar(); }`,
|
||||
},
|
||||
{
|
||||
name: "Multi line comment",
|
||||
input: `
|
||||
/* Comment
|
||||
more comment */
|
||||
function foo() { bar(); }
|
||||
`,
|
||||
},
|
||||
{ name: "Null assignment", input: "var i=null;" },
|
||||
{ name: "Undefined assignment", input: "var i=undefined;" },
|
||||
{ name: "Void 0 assignment", input: "var i=void 0;" },
|
||||
{
|
||||
name: "This property access",
|
||||
input: "var foo=this.foo;\n",
|
||||
},
|
||||
|
||||
{
|
||||
name: "True assignment",
|
||||
input: "var foo=true;\n",
|
||||
},
|
||||
|
||||
{
|
||||
name: "False assignment",
|
||||
input: "var foo=false;\n",
|
||||
},
|
||||
|
||||
{
|
||||
name: "For loop",
|
||||
input: "for (var i = 0; i < n; i++) { console.log(i); }",
|
||||
},
|
||||
|
||||
{
|
||||
name: "String with semicolon",
|
||||
input: "var foo = ';';\n",
|
||||
},
|
||||
|
||||
{
|
||||
name: "String with quote",
|
||||
input: 'var foo = "\'";\n',
|
||||
},
|
||||
|
||||
{
|
||||
name: "Function calls",
|
||||
input: "var result=func(a,b,c,d);",
|
||||
},
|
||||
|
||||
{
|
||||
name: "Regexp",
|
||||
input: "var r=/foobar/g;",
|
||||
},
|
||||
|
||||
{
|
||||
name: "In operator",
|
||||
input: "if(foo in bar){doThing()}",
|
||||
output: "if (foo in bar) {\n" + " doThing()\n" + "}\n",
|
||||
},
|
||||
{
|
||||
name: "With statement",
|
||||
input: "with(obj){crock()}",
|
||||
},
|
||||
{
|
||||
name: "New expression",
|
||||
input: "var foo=new Foo();",
|
||||
},
|
||||
{
|
||||
name: "Continue/break statements",
|
||||
input: "while(1){if(x){continue}if(y){break}if(z){break foo}}",
|
||||
},
|
||||
{
|
||||
name: "Instanceof",
|
||||
input: "var a=x instanceof y;",
|
||||
},
|
||||
{
|
||||
name: "Binary operators",
|
||||
input: "var a=5*30;var b=5>>3;",
|
||||
},
|
||||
{
|
||||
name: "Delete",
|
||||
input: "delete obj.prop;",
|
||||
},
|
||||
|
||||
{
|
||||
name: "Try/catch/finally statement",
|
||||
input: "try{dangerous()}catch(e){handle(e)}finally{cleanup()}",
|
||||
},
|
||||
{
|
||||
name: "If/else statement",
|
||||
input: "if(c){then()}else{other()}",
|
||||
},
|
||||
{
|
||||
name: "If/else without curlies",
|
||||
input: "if(c) a else b",
|
||||
},
|
||||
{
|
||||
name: "Objects",
|
||||
input: `
|
||||
var o={a:1,
|
||||
b:2};`,
|
||||
},
|
||||
{
|
||||
name: "Do/while loop",
|
||||
input: "do{x}while(y)",
|
||||
},
|
||||
{
|
||||
name: "Arrays",
|
||||
input: "var a=[1,2,3];",
|
||||
},
|
||||
{
|
||||
name: "Code that relies on ASI",
|
||||
input: `
|
||||
var foo = 10
|
||||
var bar = 20
|
||||
function g() {
|
||||
a()
|
||||
b()
|
||||
}`,
|
||||
},
|
||||
{
|
||||
name: "Ternary operator",
|
||||
input: "bar?baz:bang;",
|
||||
},
|
||||
{
|
||||
name: "Switch statements",
|
||||
input: "switch(x){case a:foo();break;default:bar()}",
|
||||
},
|
||||
|
||||
{
|
||||
name: "Multiple single line comments",
|
||||
input: `function f() {
|
||||
// a
|
||||
// b
|
||||
// c
|
||||
}`,
|
||||
},
|
||||
{
|
||||
name: "Indented multiline comment",
|
||||
input: `function foo() {
|
||||
/**
|
||||
* java doc style comment
|
||||
* more comment
|
||||
*/
|
||||
bar();
|
||||
}`,
|
||||
},
|
||||
{
|
||||
name: "ASI return",
|
||||
input: `function f() {
|
||||
return
|
||||
{}
|
||||
}`,
|
||||
},
|
||||
{
|
||||
name: "Non-ASI property access",
|
||||
input: `[1,2,3]
|
||||
[0]`,
|
||||
},
|
||||
{
|
||||
name: "Non-ASI in",
|
||||
input: `'x'
|
||||
in foo`,
|
||||
},
|
||||
|
||||
{
|
||||
name: "Non-ASI function call",
|
||||
input: `f
|
||||
()`,
|
||||
},
|
||||
{
|
||||
name: "Non-ASI new",
|
||||
input: `new
|
||||
F()`,
|
||||
},
|
||||
{
|
||||
name: "Getter and setter literals",
|
||||
input: "var obj={get foo(){return this._foo},set foo(v){this._foo=v}}",
|
||||
},
|
||||
{
|
||||
name: "Escaping backslashes in strings",
|
||||
input: "'\\\\'\n",
|
||||
},
|
||||
{
|
||||
name: "Escaping carriage return in strings",
|
||||
input: "'\\r'\n",
|
||||
},
|
||||
{
|
||||
name: "Escaping tab in strings",
|
||||
input: "'\\t'\n",
|
||||
},
|
||||
{
|
||||
name: "Escaping vertical tab in strings",
|
||||
input: "'\\v'\n",
|
||||
},
|
||||
{
|
||||
name: "Escaping form feed in strings",
|
||||
input: "'\\f'\n",
|
||||
},
|
||||
{
|
||||
name: "Escaping null character in strings",
|
||||
input: "'\\0'\n",
|
||||
},
|
||||
{
|
||||
name: "Bug 977082 - space between grouping operator and dot notation",
|
||||
input: `JSON.stringify(3).length;
|
||||
([1,2,3]).length;
|
||||
(new Date()).toLocaleString();`,
|
||||
},
|
||||
{
|
||||
name: "Bug 975477 don't move end of line comments to next line",
|
||||
input: `switch (request.action) {
|
||||
case 'show': //$NON-NLS-0$
|
||||
if (localStorage.hideicon !== 'true') { //$NON-NLS-0$
|
||||
chrome.pageAction.show(sender.tab.id);
|
||||
}
|
||||
break;
|
||||
case 'hide': /*Multiline
|
||||
Comment */
|
||||
break;
|
||||
default:
|
||||
console.warn('unknown request'); //$NON-NLS-0$
|
||||
// don't respond if you don't understand the message.
|
||||
return;
|
||||
}`,
|
||||
},
|
||||
{
|
||||
name: "Const handling",
|
||||
input: "const d = 'yes';\n",
|
||||
},
|
||||
{
|
||||
name: "Let handling without value",
|
||||
input: "let d;\n",
|
||||
},
|
||||
{
|
||||
name: "Let handling with value",
|
||||
input: "let d = 'yes';\n",
|
||||
},
|
||||
{
|
||||
name: "Template literals",
|
||||
// issue in acorn
|
||||
input: "`abc${JSON.stringify({clas: 'testing'})}def`;{a();}",
|
||||
},
|
||||
{
|
||||
name: "Class handling",
|
||||
input: "class Class{constructor(){}}",
|
||||
},
|
||||
{
|
||||
name: "Subclass handling",
|
||||
input: "class Class extends Base{constructor(){}}",
|
||||
},
|
||||
{
|
||||
name: "Unnamed class handling",
|
||||
input: "let unnamed=class{constructor(){}}",
|
||||
},
|
||||
{
|
||||
name: "Named class handling",
|
||||
input: "let unnamed=class Class{constructor(){}}",
|
||||
},
|
||||
{
|
||||
name: "Class extension within a function",
|
||||
input: "(function() { class X extends Y { constructor() {} } })()",
|
||||
},
|
||||
{
|
||||
name: "Bug 1261971 - indentation after switch statement",
|
||||
input: "{switch(x){}if(y){}done();}",
|
||||
},
|
||||
{
|
||||
name: "Bug 1206633 - spaces in for of",
|
||||
input: "for (let tab of tabs) {}",
|
||||
},
|
||||
{
|
||||
name: "Bug pretty-sure-3 - escaping line and paragraph separators",
|
||||
input: "x = '\\u2029\\u2028';",
|
||||
},
|
||||
{
|
||||
name: "Bug pretty-sure-4 - escaping null character before digit",
|
||||
input: "x = '\\u00001';",
|
||||
},
|
||||
{
|
||||
name:
|
||||
"Bug pretty-sure-5 - empty multiline comment shouldn't throw exception",
|
||||
input: `{
|
||||
/*
|
||||
*/
|
||||
return;
|
||||
}`,
|
||||
},
|
||||
{
|
||||
name:
|
||||
"Bug pretty-sure-6 - inline comment shouldn't move parenthesis to next line",
|
||||
input: `return /* inline comment */ (
|
||||
1+1);`,
|
||||
},
|
||||
{
|
||||
name:
|
||||
"Bug pretty-sure-7 - accessing a literal number property requires a space",
|
||||
input: "0..toString()+x.toString();",
|
||||
},
|
||||
{
|
||||
name:
|
||||
"Bug pretty-sure-8 - return and yield only accept arguments when on the same line",
|
||||
input: `{
|
||||
return
|
||||
(x)
|
||||
yield
|
||||
(x)
|
||||
yield
|
||||
*x
|
||||
}`,
|
||||
},
|
||||
{
|
||||
name: "Bug pretty-sure-9 - accept unary operator at start of file",
|
||||
input: "+ 0",
|
||||
},
|
||||
{
|
||||
name: "Stack-keyword property access",
|
||||
input: "foo.a=1.1;foo.do.switch.case.default=2.2;foo.b=3.3;\n",
|
||||
},
|
||||
{
|
||||
name: "Dot handling with let which is identifier name",
|
||||
input: "y.let.let = 1.23;\n",
|
||||
},
|
||||
{
|
||||
name: "Dot handling with keywords which are identifier name",
|
||||
input: "y.await.break.const.delete.else.return.new.yield = 1.23;\n",
|
||||
},
|
||||
{
|
||||
name: "Optional chaining parsing support",
|
||||
input: "x?.y?.z?.['a']?.check();\n",
|
||||
},
|
||||
{
|
||||
name: "Private fields parsing support",
|
||||
input: `
|
||||
class MyClass {
|
||||
constructor(a) {
|
||||
this.#a = a;this.#b = Math.random();this.ab = this.#getAB();
|
||||
}
|
||||
#a
|
||||
#b = "default value"
|
||||
static #someStaticPrivate
|
||||
#getA() {
|
||||
return this.#a;
|
||||
}
|
||||
#getAB() {
|
||||
return this.#getA()+this.
|
||||
#b
|
||||
}
|
||||
}
|
||||
`,
|
||||
},
|
||||
];
|
||||
|
||||
const sourceMap = this.sourceMap || require("source-map");
|
||||
const includesOnly = cases.find(({ only }) => only);
|
||||
|
||||
let output = ``;
|
||||
|
||||
for (const { name, input, only, skip } of cases) {
|
||||
if ((includesOnly && !only) || skip) {
|
||||
continue;
|
||||
}
|
||||
test(name, () => {
|
||||
const actual = prettyFast(input, {
|
||||
indent: " ",
|
||||
url: "test.js",
|
||||
});
|
||||
|
||||
expect(actual.code).toMatchSnapshot();
|
||||
|
||||
output += `${chalk.bold(name)}\n${chalk.yellow(input.trim())}\n${chalk.blue(
|
||||
actual.code
|
||||
)}\n`;
|
||||
const smc = new sourceMap.SourceMapConsumer(actual.map.toJSON());
|
||||
|
||||
const mappings = [];
|
||||
smc.eachMapping(
|
||||
({ generatedColumn, generatedLine, originalColumn, originalLine }) => {
|
||||
mappings.push(
|
||||
`(${originalLine}, ${originalColumn}) -> (${generatedLine}, ${generatedColumn})`
|
||||
);
|
||||
}
|
||||
);
|
||||
expect(mappings).toMatchSnapshot();
|
||||
});
|
||||
}
|
||||
|
||||
afterAll(() => {
|
||||
// Enable to view the test run output
|
||||
if (false) {
|
||||
console.log(output);
|
||||
}
|
||||
});
|
||||
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue