Socket
Socket
Sign inDemoInstall

prettier

Package Overview
Dependencies
31
Maintainers
2
Versions
162
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.11.0 to 0.13.1

Rationale.md

100

bin/prettier.js
#!/usr/bin/env node
"use strict";
const fs = require("fs");

@@ -17,4 +18,8 @@ const getStdin = require("get-stdin");

"bracket-spacing",
// See https://github.com/chalk/supports-color/#info
// The supports-color package (a sub sub dependency) looks directly at
// `process.argv` for `--no-color` and such-like options. The reason it is
// listed here is to avoid "Ignored unknown option: --no-color" warnings.
// See https://github.com/chalk/supports-color/#info for more information.
"color",
"help",
"version",

@@ -25,7 +30,9 @@ "debug-print-doc",

],
string: [ "print-width", "tab-width", "parser" ],
string: ["print-width", "tab-width", "parser"],
default: { color: true, "bracket-spacing": true, parser: "babylon" },
alias: { help: "h", version: "v" },
unknown: param => {
if (param.startsWith("-")) {
console.warn("Ignored unknown option: " + param + "\n");
return false;
}

@@ -42,5 +49,5 @@ }

const write = argv["write"];
const stdin = argv["stdin"];
const stdin = argv["stdin"] || !filepatterns.length && !process.stdin.isTTY;
if (!filepatterns.length && !stdin) {
if (argv["help"] || !filepatterns.length && !stdin) {
console.log(

@@ -64,6 +71,13 @@ "Usage: prettier [opts] [filename ...]\n\n" +

);
process.exit(1);
process.exit(argv["help"] ? 0 : 1);
}
function getParser() {
function getParserOption() {
const optionName = "parser";
const value = argv[optionName];
if (value === undefined) {
return value;
}
// For backward compatibility. Deprecated in 0.0.10

@@ -75,14 +89,42 @@ if (argv["flow-parser"]) {

if (argv["parser"] === "flow") {
return "flow";
if (value === "flow" || value === "babylon") {
return value;
}
console.warn(
"Ignoring unknown --" +
optionName +
' value, falling back to "babylon":\n' +
' Expected "flow" or "babylon", but received: ' +
JSON.stringify(value)
);
return "babylon";
}
function getIntOption(optionName) {
const value = argv[optionName];
if (value === undefined) {
return value;
}
if (/^\d+$/.test(value)) {
return Number(value);
}
console.error(
"Invalid --" +
optionName +
" value. Expected an integer, but received: " +
JSON.stringify(value)
);
process.exit(1);
}
const options = {
printWidth: argv["print-width"],
tabWidth: argv["tab-width"],
printWidth: getIntOption("print-width"),
tabWidth: getIntOption("tab-width"),
bracketSpacing: argv["bracket-spacing"],
parser: getParser(),
parser: getParserOption(),
singleQuote: argv["single-quote"],

@@ -100,9 +142,33 @@ trailingComma: argv["trailing-comma"]

function handleError(filename, e) {
const isParseError = Boolean(e && e.loc);
const isValidationError = /Validation Error/.test(e && e.message);
// For parse errors and validation errors, we only want to show the error
// message formatted in a nice way. `String(e)` takes care of that. Other
// (unexpected) errors are passed as-is as a separate argument to
// `console.error`. That includes the stack trace (if any), and shows a nice
// `util.inspect` of throws things that aren't `Error` objects. (The Flow
// parser has mistakenly thrown arrays sometimes.)
if (isParseError) {
console.error(filename + ": " + String(e));
} else if (isValidationError) {
console.error(String(e));
// If validation fails for one file, it will fail for all of them.
process.exit(1);
} else {
console.error(filename + ":", e);
}
// Don't exit the process if one file failed
process.exitCode = 2;
}
if (stdin) {
getStdin().then(input => {
try {
console.log(format(input));
// Don't use `console.log` here since it adds an extra newline at the end.
process.stdout.write(format(input));
} catch (e) {
process.exitCode = 2;
console.error("stdin: " + e);
handleError("stdin", e);
return;

@@ -129,4 +195,3 @@ }

} catch (e) {
process.exitCode = 2;
console.error(filename + ": " + e);
handleError(filename, e);
return;

@@ -144,3 +209,4 @@ }

} else {
console.log(output);
// Don't use `console.log` here since it adds an extra newline at the end.
process.stdout.write(output);
}

@@ -147,0 +213,0 @@ });

@@ -0,1 +1,52 @@

# 0.13.0
[link](https://github.com/jlongster/prettier/compare/0.12.0...0.13.0)
* Simplify arrow functions that use blocks (#496)
* Properly print comments for BinaryExpression (#494)
* Preserve empty line after comment (#493)
* [JSX] Handle each line of text separately (#455)
* Proper support for dangling comments (#492)
# 0.12.0
[link](https://github.com/jlongster/prettier/compare/0.11.0...0.12.0)
* [WIP] Add rationale document (#372)
* Proper parenthesis for yield and await in conditional (#436)
* Don't print double newlines at EOF to stdout (#437)
* Explain the `--color` option in a comment (#434)
* Validate user-provided config with jest-validate (#301)
* Propagate breaks upwards automatically, introduce `breakParent` (#440)
* Fix typo in variable name (#441)
* Refactor traversal (#442)
* Do not put a newline on empty `{}` for functions (#447)
* Better error message for assertDoc (#449)
* Remove `multilineGroup` (#450)
* Ability to break on `:` for objects (#314)
* Update snapshots
* [RFC] Do not put spacing inside of arrays with bracketSpacing (#446)
* Fix integer CLI arguments (#452)
* Move tests around (#454)
* Update package.json, use ast-types 0.9.4 (#453)
* Update lockfile
* Support printing import("a") (#458)
* Explain that you can pass options to the spec runner (#460)
* Fix spurious whitespace (#463)
* Preserve new lines after directives (#464)
* Put decorators on the same line (#459)
* docs: add related projects (#456)
* Add break points for class declaration (#466)
* Added parens around in operator in for loops 🚀. (#468)
* CLI improvements (#478)
* [RFC] Hug Conditionals in JSX (#473)
* Refactor comment algorithm and improve newline/spaces detection (#482)
* Indent ternaries (#484)
* Indent computed member (#471)
* Maintain windows line ending (#472)
* Don't break up JSXOpeningElement if it only has a single text (#488)
* Add CallExpression to the last argument expansion whitelist (#470)
* Mention eslint-plugin-prettier in Related Projects (#490)
* Stop using conditionalGroup inside of UnionTypeAnnotation (#491)
# 0.11.0

@@ -52,3 +103,2 @@

# 0.0.10

@@ -55,0 +105,0 @@

25

commands.md

@@ -27,8 +27,9 @@

### multilineGroup
A document can force parent groups to break by including `breakParent`
(see below). A hard and literal line automatically include this so
they always break parent groups. Breaks are propagated to all parent
groups, so if a deeply nested expression has a hard break, everything
with break. This only matters for "hard" breaks, i.e. newlines that
are printed no matter what and can be statically analyzed.
This is the same as `group`, but with an additional behavior: if this
group spans any other groups that have hard breaks (see below) this
group *always* breaks. Otherwise it acts the same as `group`.
For example, an array will try to fit on one line:

@@ -57,2 +58,16 @@

### breakParent
Include this anywhere to force all parent groups to break. See `group`
for more info. Example:
```js
group(concat([
" ",
expr,
" ",
breakParent
]))
```
### join

@@ -59,0 +74,0 @@

"use strict";
const codeFrame = require("babel-code-frame");

@@ -11,2 +12,10 @@ const comments = require("./src/comments");

function guessLineEnding(text) {
const index = text.indexOf("\n");
if (index >= 0 && text.charAt(index - 1) === "\r") {
return "\r\n";
}
return "\n";
}
function parse(text, opts) {

@@ -46,3 +55,3 @@ const parseFunction = opts.parser === "flow"

const doc = printAstToDoc(ast, opts);
const str = printDocToString(doc, opts.printWidth);
const str = printDocToString(doc, opts.printWidth, guessLineEnding(text));
return str;

@@ -60,5 +69,5 @@ }

const nextChar = text.charAt(index + 1);
const addNewline = nextChar == "\n" || nextChar == "\r";
const newLine = nextChar === "\n" ? "\n" : nextChar === "\r" ? "\r\n" : "";
return shebang + (addNewline ? "\n" : "") + format(programText, opts);
return shebang + newLine + format(programText, opts);
}

@@ -65,0 +74,0 @@

{
"name": "prettier",
"version": "0.11.0",
"version": "0.13.1",
"description": "Prettier is an opinionated JavaScript formatter",

@@ -19,3 +19,3 @@ "bin": {

"dependencies": {
"ast-types": "git+https://github.com/jlongster/ast-types.git",
"ast-types": "0.9.4",
"babel-code-frame": "6.22.0",

@@ -27,2 +27,3 @@ "babylon": "6.15.0",

"glob": "7.1.1",
"jest-validate": "18.2.0",
"minimist": "1.2.0"

@@ -29,0 +30,0 @@ },

@@ -36,3 +36,3 @@ # Prettier

```js
foo(arg1, arg2, arg3);
foo(arg1, arg2, arg3, arg4);
```

@@ -211,2 +211,13 @@

## Related Projects
- [`eslint-plugin-prettier`](https://github.com/not-an-aardvark/eslint-plugin-prettier) plugs `prettier` into your `eslint` workflow
- [`prettier-eslint`](https://github.com/kentcdodds/prettier-eslint)
passes `prettier` output to `eslint --fix`
- [`prettier-standard-formatter`](https://github.com/dtinth/prettier-standard-formatter)
passes `prettier` output to `standard --fix`
- [`prettier-with-tabs`](https://github.com/arijs/prettier-with-tabs)
allows you to configure prettier to use `tabs`
## Technical Details

@@ -256,1 +267,2 @@

original one and makes sure they are semantically equivalent.
* Each test folder has a `jsfmt.spec.js` that runs the tests. Normally you can just put `run_spec(__dirname);` there but if you want to pass specific options you can add the options object as the 2nd parameter like: `run_spec(__dirname, { parser: 'babylon' });`

@@ -10,5 +10,8 @@ var assert = require("assert");

var hardline = docBuilders.hardline;
var breakParent = docBuilders.breakParent;
var indent = docBuilders.indent;
var lineSuffix = docBuilders.lineSuffix;
var util = require("./util");
var comparePos = util.comparePos;
var childNodesCacheKey = Symbol('child-nodes');
var childNodesCacheKey = Symbol("child-nodes");
var locStart = util.locStart;

@@ -73,3 +76,3 @@ var locEnd = util.locEnd;

var childNodes = getSortedChildNodes(node, text);
var precedingNode, followingNode;
// Time to dust off the old binary search robes and wizard hat.

@@ -87,2 +90,10 @@ var left = 0, right = childNodes.length;

comment.enclosingNode = child;
if (middle > 0) {
// Store the global preceding node separately from
// `precedingNode` because they mean different things. This is
// the previous node, ignoring any delimiters/blocks/etc.
comment.globalPrecedingNode = childNodes[middle - 1];
}
decorateComment(child, comment, text);

@@ -97,3 +108,3 @@ return; // Abandon the binary search at this level.

// node we have encountered so far.
var precedingNode = child;
precedingNode = child;
left = middle + 1;

@@ -108,3 +119,3 @@ continue;

// have encountered so far.
var followingNode = child;
followingNode = child;
right = middle;

@@ -136,36 +147,60 @@ continue;

var pn = comment.precedingNode;
var en = comment.enclosingNode;
var fn = comment.followingNode;
const precedingNode = comment.precedingNode;
const globalPrecedingNode = comment.globalPrecedingNode;
const enclosingNode = comment.enclosingNode;
const followingNode = comment.followingNode;
const isStartOfFile = comment.loc.start.line === 1;
if (pn && fn) {
var tieCount = tiesToBreak.length;
if (tieCount > 0) {
var lastTie = tiesToBreak[tieCount - 1];
if (
util.hasNewline(text, locStart(comment), { backwards: true }) ||
isStartOfFile
) {
// If a comment exists on its own line, prefer a leading comment.
// We also need to check if it's the first line of the file.
assert.strictEqual(
lastTie.precedingNode === comment.precedingNode,
lastTie.followingNode === comment.followingNode
);
if (lastTie.followingNode !== comment.followingNode) {
breakTies(tiesToBreak, text);
if (followingNode) {
// Always a leading comment.
addLeadingComment(followingNode, comment);
} else if (precedingNode) {
addTrailingComment(precedingNode, comment);
} else if (enclosingNode) {
addDanglingComment(enclosingNode, comment);
} else {
// TODO: If there are no nodes at all, we should still somehow
// print the comment.
}
} else if (util.hasNewline(text, locEnd(comment))) {
// There is content before this comment on the same line, but
// none after it, so prefer a trailing comment. A trailing
// comment *always* attaches itself to the previous node, no
// matter if there's any syntax between them.
const lastNode = precedingNode || globalPrecedingNode;
if (lastNode) {
// Always a trailing comment
addTrailingComment(lastNode, comment);
} else {
throw new Error("Preceding node not found");
}
} else {
// Otherwise, text exists both before and after the comment on
// the same line. If there is both a preceding and following
// node, use a tie-breaking algorithm to determine if it should
// be attached to the next or previous node. In the last case,
// simply attach the right node;
if (precedingNode && followingNode) {
const tieCount = tiesToBreak.length;
if (tieCount > 0) {
var lastTie = tiesToBreak[tieCount - 1];
if (lastTie.followingNode !== comment.followingNode) {
breakTies(tiesToBreak, text);
}
}
tiesToBreak.push(comment);
} else if (precedingNode) {
addTrailingComment(precedingNode, comment);
} else if (followingNode) {
addLeadingComment(followingNode, comment);
} else if (enclosingNode) {
addDanglingComment(enclosingNode, comment);
}
tiesToBreak.push(comment);
} else if (pn) {
// No contest: we have a trailing comment.
breakTies(tiesToBreak, text);
addTrailingComment(pn, comment);
} else if (fn) {
// No contest: we have a leading comment.
breakTies(tiesToBreak, text);
addLeadingComment(fn, comment);
} else if (en) {
// The enclosing node has no child nodes at all, so what we
// have here is a dangling comment, e.g. [/* crickets */].
breakTies(tiesToBreak, text);
addDanglingComment(en, comment);
} else {
}

@@ -192,9 +227,9 @@ });

var pn = tiesToBreak[0].precedingNode;
var fn = tiesToBreak[0].followingNode;
var gapEndPos = locStart(fn);
var precedingNode = tiesToBreak[0].precedingNode;
var followingNode = tiesToBreak[0].followingNode;
var gapEndPos = locStart(followingNode);
// Iterate backwards through tiesToBreak, examining the gaps
// between the tied comments. In order to qualify as leading, a
// comment must be separated from fn by an unbroken series of
// comment must be separated from followingNode by an unbroken series of
// whitespace-only gaps (or other comments).

@@ -207,4 +242,4 @@ for (

var comment = tiesToBreak[indexOfFirstLeadingComment - 1];
assert.strictEqual(comment.precedingNode, pn);
assert.strictEqual(comment.followingNode, fn);
assert.strictEqual(comment.precedingNode, precedingNode);
assert.strictEqual(comment.followingNode, followingNode);

@@ -220,15 +255,7 @@ var gap = text.slice(locEnd(comment), gapEndPos);

// while (indexOfFirstLeadingComment <= tieCount &&
// (comment = tiesToBreak[indexOfFirstLeadingComment]) &&
// // If the comment is a //-style comment and indented more
// // deeply than the node itself, reconsider it as trailing.
// (comment.type === "Line" || comment.type === "CommentLine") &&
// comment.loc.start.column > fn.loc.start.column) {
// ++indexOfFirstLeadingComment;
// }
tiesToBreak.forEach(function(comment, i) {
if (i < indexOfFirstLeadingComment) {
addTrailingComment(pn, comment);
addTrailingComment(precedingNode, comment);
} else {
addLeadingComment(fn, comment);
addLeadingComment(followingNode, comment);
}

@@ -263,23 +290,74 @@ });

function printLeadingComment(commentPath, print) {
var comment = commentPath.getValue();
n.Comment.assert(comment);
return concat([ print(commentPath), hardline ]);
function printComment(commentPath) {
const comment = commentPath.getValue();
switch (comment.type) {
case "CommentBlock":
case "Block":
return "/*" + comment.value + "*/";
case "CommentLine":
case "Line":
return "//" + comment.value;
default:
throw new Error("Not a comment: " + JSON.stringify(comment));
}
}
function printTrailingComment(commentPath, print, options) {
const comment = commentPath.getValue(commentPath);
n.Comment.assert(comment);
function printLeadingComment(commentPath, print, options) {
const comment = commentPath.getValue();
const contents = printComment(commentPath);
const text = options.originalText;
const isBlock = comment.type === "Block" || comment.type === "CommentBlock";
return concat([
util.newlineExistsBefore(text, locStart(comment)) ? hardline : " ",
print(commentPath)
]);
// Leading block comments should see if they need to stay on the
// same line or not.
if (isBlock) {
return concat([
contents,
util.hasNewline(options.originalText, locEnd(comment)) ? hardline : " "
]);
}
return concat([contents, hardline]);
}
function printDanglingComments(path, print, options) {
function printTrailingComment(commentPath, print, options, parentNode) {
const comment = commentPath.getValue();
const contents = printComment(commentPath);
const isBlock = comment.type === "Block" || comment.type === "CommentBlock";
if (
util.hasNewline(options.originalText, locStart(comment), {
backwards: true
})
) {
// This allows comments at the end of nested structures:
// {
// x: 1,
// y: 2
// // A comment
// }
// Those kinds of comments are almost always leading comments, but
// here it doesn't go "outside" the block and turns it into a
// trailing comment for `2`. We can simulate the above by checking
// if this a comment on its own line; normal trailing comments are
// always at the end of another expression.
return concat([hardline, contents]);
} else if (isBlock) {
// Trailing block comments never need a newline
return concat([" ", contents]);
}
return concat([lineSuffix(" " + contents), !isBlock ? breakParent : ""]);
}
function printDanglingComments(path, options, noIndent) {
const text = options.originalText;
const parts = [];
const node = path.getValue();
const parts = [];
if (!node || !node.comments) {
return "";
}
path.each(

@@ -289,6 +367,6 @@ commentPath => {

if (!comment.leading && !comment.trailing) {
parts.push(
util.newlineExistsBefore(text, locStart(comment)) ? hardline : " "
);
parts.push(commentPath.call(print));
if (util.hasNewline(text, locStart(comment), { backwards: true })) {
parts.push(hardline);
}
parts.push(printComment(commentPath));
}

@@ -298,2 +376,6 @@ },

);
if (!noIndent) {
return indent(options.tabWidth, concat(parts));
}
return concat(parts);

@@ -307,3 +389,2 @@ }

var comments = n.Node.check(value) && types.getFieldValue(value, "comments");
var isFirstInProgram = n.Program.check(parent) && parent.body[0] === value;

@@ -315,3 +396,3 @@ if (!comments || comments.length === 0) {

var leadingParts = [];
var trailingParts = [ printed ];
var trailingParts = [printed];

@@ -324,17 +405,8 @@ path.each(

if (
leading ||
trailing &&
!(n.Statement.check(value) ||
comment.type === "Block" ||
comment.type === "CommentBlock")
) {
leadingParts.push(printLeadingComment(commentPath, print));
if (leading) {
leadingParts.push(printLeadingComment(commentPath, print, options));
// Support a special case where a comment exists at the very top
// of the file. Allow the user to add spacing between that file
// and any code beneath it.
const text = options.originalText;
if (
isFirstInProgram &&
util.newlineExistsAfter(options.originalText, util.locEnd(comment))
util.hasNewline(text, util.skipNewline(text, util.locEnd(comment)))
) {

@@ -344,3 +416,5 @@ leadingParts.push(hardline);

} else if (trailing) {
trailingParts.push(printTrailingComment(commentPath, print, options));
trailingParts.push(
printTrailingComment(commentPath, print, options, parent)
);
}

@@ -351,6 +425,5 @@ },

leadingParts.push.apply(leadingParts, trailingParts);
return concat(leadingParts);
return concat(leadingParts.concat(trailingParts));
}
module.exports = { attach, printComments, printDanglingComments };
"use strict";
const assert = require("assert");
const utils = require("./doc-utils");
const hasHardLine = utils.hasHardLine;
const willBreak = utils.willBreak;
function assertDoc(val) {
assert(
typeof val === "string" || val != null && typeof val.type === "string",
"Value is a valid document"
);
if (
!(typeof val === "string" || val != null && typeof val.type === "string")
) {
throw new Error(
"Value " + JSON.stringify(val) + " is not a valid document"
);
}
}

@@ -16,2 +19,8 @@

// We cannot do this until we change `printJSXElement` to not
// access the internals of a document directly.
// if(parts.length === 1) {
// // If it's a single document, no need to concat it.
// return parts[0];
// }
return { type: "concat", parts };

@@ -39,9 +48,2 @@ }

function multilineGroup(contents, opts) {
return group(
contents,
Object.assign(opts || {}, { shouldBreak: hasHardLine(contents) })
);
}
function conditionalGroup(states, opts) {

@@ -65,6 +67,19 @@ return group(

function lineSuffix(contents) {
if (typeof contents !== "string") {
throw new Error(
"lineSuffix only takes a string, but given: " + JSON.stringify(contents)
);
}
return { type: "line-suffix", contents };
}
const breakParent = { type: "break-parent" };
const line = { type: "line" };
const softline = { type: "line", soft: true };
const hardline = { type: "line", hard: true };
const literalline = { type: "line", hard: true, literal: true };
const hardline = concat([{ type: "line", hard: true }, breakParent]);
const literalline = concat([
{ type: "line", hard: true, literal: true },
breakParent
]);

@@ -93,6 +108,7 @@ function join(sep, arr) {

group,
multilineGroup,
conditionalGroup,
lineSuffix,
breakParent,
ifBreak,
indent
};
"use strict";
function flattenDoc(doc) {
if (!doc || typeof doc === "string" || doc.type === "line") {
return doc;
}
if (doc.type === "concat") {

@@ -24,22 +20,24 @@ var res = [];

return Object.assign({}, doc, { parts: res });
}
if (doc.type === "indent") {
return Object.assign({}, doc, { contents: flattenDoc(doc.contents) });
}
if (doc.type === "if-break") {
} else if (doc.type === "if-break") {
return Object.assign({}, doc, {
breakContents: flattenDoc(doc.breakContents),
flatContents: flattenDoc(doc.flatContents)
breakContents: (
doc.breakContents != null ? flattenDoc(doc.breakContents) : null
),
flatContents: (
doc.flatContents != null ? flattenDoc(doc.flatContents) : null
)
});
}
if (doc.type === "group") {
} else if (doc.type === "group") {
return Object.assign({}, doc, {
contents: flattenDoc(doc.contents),
expandedStates: doc.expandedStates
? doc.expandedStates.map(flattenDoc)
: doc.expandedStates
expandedStates: (
doc.expandedStates
? doc.expandedStates.map(flattenDoc)
: doc.expandedStates
)
});
} else if (doc.contents) {
return Object.assign({}, doc, { contents: flattenDoc(doc.contents) });
} else {
return doc;
}

@@ -66,2 +64,6 @@ }

if (doc.type === "break-parent") {
return "breakParent";
}
if (doc.type === "concat") {

@@ -83,10 +85,12 @@ return "[" + doc.parts.map(printDoc).join(", ") + "]";

if (doc.type === "group") {
return (doc.break
? "multilineGroup"
: doc.expandedStates ? "conditionalGroup" : "group") +
if (doc.expandedStates) {
return "conditionalGroup(" +
"[" +
doc.expandedStates.map(printDoc).join(",") +
"])";
}
return (doc.break ? "wrappedGroup" : "group") +
"(" +
printDoc(doc.contents) +
(doc.expandedStates
? ", [" + doc.expandedStates.map(printDoc).join(",") + "]"
: "") +
")";

@@ -93,0 +97,0 @@ }

"use strict";
const MODE_BREAK = 1;

@@ -7,3 +8,3 @@ const MODE_FLAT = 2;

let restIdx = restCommands.length;
const cmds = [ next ];
const cmds = [next];
while (width >= 0) {

@@ -33,3 +34,3 @@ if (cmds.length === 0) {

for (var i = doc.parts.length - 1; i >= 0; i--) {
cmds.push([ ind, mode, doc.parts[i] ]);
cmds.push([ind, mode, doc.parts[i]]);
}

@@ -39,7 +40,7 @@

case "indent":
cmds.push([ ind + doc.n, mode, doc.contents ]);
cmds.push([ind + doc.n, mode, doc.contents]);
break;
case "group":
cmds.push([ ind, doc.break ? MODE_BREAK : mode, doc.contents ]);
cmds.push([ind, doc.break ? MODE_BREAK : mode, doc.contents]);

@@ -50,3 +51,3 @@ break;

if (doc.breakContents) {
cmds.push([ ind, mode, doc.breakContents ]);
cmds.push([ind, mode, doc.breakContents]);
}

@@ -56,3 +57,3 @@ }

if (doc.flatContents) {
cmds.push([ ind, mode, doc.flatContents ]);
cmds.push([ind, mode, doc.flatContents]);
}

@@ -84,3 +85,5 @@ }

function printDocToString(doc, w) {
function printDocToString(doc, width, newLine) {
newLine = newLine || "\n";
let pos = 0;

@@ -90,5 +93,7 @@ // cmds is basically a stack. We've turned a recursive call into a

// cmds to the array instead of recursively calling `print`.
let cmds = [ [ 0, MODE_BREAK, doc ] ];
let cmds = [[0, MODE_BREAK, doc]];
let out = [];
let shouldRemeasure = false;
let lineSuffix = "";
while (cmds.length !== 0) {

@@ -108,3 +113,3 @@ const x = cmds.pop();

for (var i = doc.parts.length - 1; i >= 0; i--) {
cmds.push([ ind, mode, doc.parts[i] ]);
cmds.push([ind, mode, doc.parts[i]]);
}

@@ -114,3 +119,3 @@

case "indent":
cmds.push([ ind + doc.n, mode, doc.contents ]);
cmds.push([ind + doc.n, mode, doc.contents]);

@@ -135,4 +140,4 @@ break;

const next = [ ind, MODE_FLAT, doc.contents ];
let rem = w - pos;
const next = [ind, MODE_FLAT, doc.contents];
let rem = width - pos;

@@ -150,7 +155,8 @@ if (!doc.break && fits(next, cmds, rem)) {

if (doc.expandedStates) {
const mostExpanded = doc.expandedStates[doc.expandedStates.length -
1];
const mostExpanded = doc.expandedStates[
doc.expandedStates.length - 1
];
if (doc.break) {
cmds.push([ ind, MODE_BREAK, mostExpanded ]);
cmds.push([ind, MODE_BREAK, mostExpanded]);

@@ -161,3 +167,3 @@ break;

if (i >= doc.expandedStates.length) {
cmds.push([ ind, MODE_BREAK, mostExpanded ]);
cmds.push([ind, MODE_BREAK, mostExpanded]);

@@ -167,3 +173,3 @@ break;

const state = doc.expandedStates[i];
const cmd = [ ind, MODE_FLAT, state ];
const cmd = [ind, MODE_FLAT, state];

@@ -179,3 +185,3 @@ if (fits(cmd, cmds, rem)) {

} else {
cmds.push([ ind, MODE_BREAK, doc.contents ]);
cmds.push([ind, MODE_BREAK, doc.contents]);
}

@@ -190,3 +196,3 @@ }

if (doc.breakContents) {
cmds.push([ ind, mode, doc.breakContents ]);
cmds.push([ind, mode, doc.breakContents]);
}

@@ -196,3 +202,3 @@ }

if (doc.flatContents) {
cmds.push([ ind, mode, doc.flatContents ]);
cmds.push([ind, mode, doc.flatContents]);
}

@@ -202,2 +208,5 @@ }

break;
case "line-suffix":
lineSuffix += doc.contents;
break;
case "line":

@@ -227,4 +236,3 @@ switch (mode) {

if (doc.literal) {
out.push("\n");
out.push(lineSuffix + newLine);
pos = 0;

@@ -240,7 +248,7 @@ } else {

out.push("\n" + " ".repeat(ind));
out.push(lineSuffix + newLine + " ".repeat(ind));
pos = ind;
}
lineSuffix = "";
break;

@@ -247,0 +255,0 @@ }

"use strict";
function iterDoc(topDoc, func) {
const docs = [ topDoc ];
while (docs.length !== 0) {
const doc = docs.pop();
let res = undefined;
if (typeof doc === "string") {
const res = func("string", doc);
function traverseDoc(doc, onEnter, onExit) {
var hasStopped = false;
function traverseDocRec(doc) {
if (onEnter) {
hasStopped = hasStopped || onEnter(doc) === false;
}
if (hasStopped) {
return;
}
if (res) {
return res;
if (doc.type === "concat") {
for (var i = 0; i < doc.parts.length; i++) {
traverseDocRec(doc.parts[i]);
}
} else {
const res = func(doc.type, doc);
if (res) {
return res;
} else if (doc.type === "if-break") {
if (doc.breakContents) {
traverseDocRec(doc.breakContents);
}
if (doc.type === "concat") {
for (var i = doc.parts.length - 1; i >= 0; i--) {
docs.push(doc.parts[i]);
}
} else if (doc.type === "if-break") {
if (doc.breakContents) {
docs.push(doc.breakContents);
}
if (doc.flatContents) {
docs.push(doc.flatContents);
}
} else if (doc.type !== "line") {
docs.push(doc.contents);
if (doc.flatContents) {
traverseDocRec(doc.flatContents);
}
} else if (doc.contents) {
traverseDocRec(doc.contents);
}
if (onExit) {
onExit(doc);
}
}
traverseDocRec(doc);
}
function findInDoc(doc, fn, defaultValue) {
var result = defaultValue;
traverseDoc(doc, function(doc) {
var maybeResult = fn(doc);
if (maybeResult !== undefined) {
result = maybeResult;
return false;
}
});
return result;
}
function isEmpty(n) {

@@ -44,24 +53,85 @@ return typeof n === "string" && n.length === 0;

function getFirstString(doc) {
return iterDoc(doc, (type, doc) => {
if (type === "string" && doc.trim().length !== 0) {
return doc;
return findInDoc(
doc,
doc => {
if (typeof doc === "string" && doc.trim().length !== 0) {
return doc;
}
},
null
);
}
function isLineNext(doc) {
return findInDoc(
doc,
doc => {
if (typeof doc === "string") {
return false;
}
if (doc.type === "line") {
return true;
}
},
false
);
}
function willBreak(doc) {
return findInDoc(
doc,
doc => {
if (doc.type === "group" && doc.break) {
return true;
}
if (doc.type === "line" && doc.hard) {
return true;
}
},
false
);
}
function breakParentGroup(groupStack) {
if (groupStack.length > 0) {
const parentGroup = groupStack[groupStack.length - 1];
// Breaks are not propagated through conditional groups because
// the user is expected to manually handle what breaks.
if (!parentGroup.expandedStates) {
parentGroup.break = true;
}
});
}
return null;
}
function hasHardLine(doc) {
// TODO: If we hit a group, check if it's already marked as a
// multiline group because they should be marked bottom-up.
return !!iterDoc(doc, (type, doc) => {
switch (type) {
case "line":
if (doc.hard) {
return true;
function propagateBreaks(doc) {
const groupStack = [];
traverseDoc(
doc,
doc => {
if (doc.type === "break-parent") {
breakParentGroup(groupStack);
}
if (doc.type === "group") {
groupStack.push(doc);
}
},
doc => {
if (doc.type === "group") {
const group = groupStack.pop();
if (group.break) {
breakParentGroup(groupStack);
}
break;
}
}
});
);
}
module.exports = { isEmpty, getFirstString, hasHardLine };
module.exports = {
isEmpty,
getFirstString,
willBreak,
isLineNext,
traverseDoc,
propagateBreaks
};

@@ -11,3 +11,3 @@ var assert = require("assert");

assert.ok(this instanceof FastPath);
this.stack = [ value ];
this.stack = [value];
}

@@ -28,4 +28,5 @@

var copy = Object.create(FastPath.prototype);
var stack = [ obj.value ];
for (var pp; pp = obj.parentPath; obj = pp) stack.push(obj.name, pp.value);
var stack = [obj.value];
for (var pp; pp = obj.parentPath; obj = pp)
stack.push(obj.name, pp.value);
copy.stack = stack.reverse();

@@ -86,2 +87,18 @@ return copy;

FPp.isLast = function isLast() {
var s = this.stack;
if (this.getParentNode()) {
var idx = s[s.length - 2];
// The name of this node should be an index
assert.ok(typeof idx === "number");
const arr = s[s.length - 3];
// We should have an array as a parent node
assert.ok(Array.isArray(arr));
return idx === arr.length - 1;
}
return false;
};
// Temporarily push properties named by string arguments given after the

@@ -202,4 +219,4 @@ // callback function onto this.stack, then call the callback with a

(parent.type === "ClassDeclaration" || parent.type === "ClassExpression") &&
parent.superClass === node && (
node.type === "ArrowFunctionExpression" ||
parent.superClass === node &&
(node.type === "ArrowFunctionExpression" ||
node.type === "AssignmentExpression" ||

@@ -217,4 +234,3 @@ node.type === "AwaitExpression" ||

node.type === "UpdateExpression" ||
node.type === "YieldExpression"
)
node.type === "YieldExpression")
) {

@@ -255,9 +271,11 @@ return true;

case "UnaryExpression":
if (node.prefix &&
((node.operator === '++' && parent.operator === '+') ||
(node.operator === '--' && parent.operator === '-'))) {
if (
node.prefix &&
(node.operator === "++" && parent.operator === "+" ||
node.operator === "--" && parent.operator === "-")
) {
return true;
}
return false;
return false;
}

@@ -276,6 +294,14 @@

case "BinaryExpression":
if (node.operator === "in" && parent.type === "ForStatement" && parent.init === node) {
if (
node.operator === "in" &&
parent.type === "ForStatement" &&
parent.init === node
) {
return true;
}
if (node.operator === "in" && parent.type === "AssignmentExpression") {
return true;
}
case "LogicalExpression":

@@ -338,7 +364,2 @@ switch (parent.type) {

case "YieldExpression":
if (parent.type === "ConditionalExpression" &&
parent.test === node &&
!node.argument) {
return true;
}
case "AwaitExpression":

@@ -359,2 +380,5 @@ switch (parent.type) {

case "ConditionalExpression":
return parent.test === node;
default:

@@ -388,5 +412,7 @@ return false;

case "AssignmentExpression":
if (parent.type === "ArrowFunctionExpression" &&
if (
parent.type === "ArrowFunctionExpression" &&
parent.body === node &&
node.left.type === "ObjectPattern") {
node.left.type === "ObjectPattern"
) {
return true;

@@ -393,0 +419,0 @@ }

"use strict";
var validate = require("jest-validate").validate;
var deprecatedConfig = require("./deprecated");
var defaults = {

@@ -17,4 +21,11 @@ // Number of spaces the pretty-printer should use per tab

var exampleConfig = Object.assign({}, defaults, {
filename: "testFilename",
printWidth: 80,
originalText: "text"
});
// Copy options and fill in default values.
function normalize(options) {
validate(options, { exampleConfig, deprecatedConfig });
const normalized = Object.assign({}, options || {});

@@ -24,3 +35,2 @@

if ("useFlowParser" in normalized) {
console.warn('The `"useFlowParser": true/false` option is deprecated. Use `parser: "flow"` instead.');
normalized.parser = normalized.useFlowParser ? "flow" : "babylon";

@@ -27,0 +37,0 @@ delete normalized.useFlowParser;

"use strict";
function parseWithFlow(text) {

@@ -16,6 +17,10 @@ // Inline the require to avoid loading all the JS if we don't use it

line: ast.errors[0].loc.start.line,
column: ast.errors[0].loc.start.column,
}
column: ast.errors[0].loc.start.column
};
const msg = ast.errors[0].message +
" (" + loc.line + ":" + loc.column + ")";
" (" +
loc.line +
":" +
loc.column +
")";
const error = new SyntaxError(msg);

@@ -22,0 +27,0 @@ error.loc = loc;

"use strict";
var assert = require("assert");

@@ -58,3 +59,4 @@ var types = require("ast-types");

function isExportDeclaration(node) {
if (node) switch (node.type) {
if (node)
switch (node.type) {
case "ExportDeclaration":

@@ -88,9 +90,58 @@ case "ExportDefaultDeclaration":

function skipNewLineForward(text, index) {
// What the "end" location points to is not consistent in parsers.
// For some statement/expressions, it's the character immediately
// afterward. For others, it's the last character in it. We need to
// scan until we hit a newline in order to skip it.
while (index < text.length) {
function skip(chars) {
return (text, index, opts) => {
const backwards = opts && opts.backwards;
// Allow `skip` functions to be threaded together without having
// to check for failures (did someone say monads?).
if (index === false) {
return false;
}
const length = text.length;
let cursor = index;
while (cursor >= 0 && cursor < length) {
const c = text.charAt(cursor);
if (chars instanceof RegExp) {
if (!chars.test(c)) {
return cursor;
}
} else if (chars.indexOf(c) === -1) {
return cursor;
}
backwards ? cursor-- : cursor++;
}
if (cursor === -1 || cursor === length) {
// If we reached the beginning or end of the file, return the
// out-of-bounds cursor. It's up to the caller to handle this
// correctly. We don't want to indicate `false` though if it
// actually skipped valid characters.
return cursor;
}
return false;
};
}
const skipWhitespace = skip(/\s/);
const skipSpaces = skip(" \t");
const skipToLineEnd = skip("; \t");
// This one doesn't use the above helper function because it wants to
// test \r\n in order and `skip` doesn't support ordering and we only
// want to skip one newline. It's simple to implement.
function skipNewline(text, index, opts) {
const backwards = opts && opts.backwards;
if (index === false) {
return false;
} else if (backwards) {
if (text.charAt(index) === "\n") {
return index - 1;
}
if (text.charAt(index - 1) === "\r" && text.charAt(index) === "\n") {
return index - 2;
}
} else {
if (text.charAt(index) === "\n") {
return index + 1;

@@ -101,49 +152,20 @@ }

}
index++;
}
return index;
}
function findNewline(text, index, backwards) {
const length = text.length;
let cursor = backwards ? index - 1 : skipNewLineForward(text, index);
// Look forward and see if there is a newline after/before this code
// by scanning up/back to the next non-indentation character.
while (cursor > 0 && cursor < length) {
const c = text.charAt(cursor);
// Skip any indentation characters
if (c !== " " && c !== "\t") {
// Check if the next non-indentation character is a newline or
// not.
return c === "\n" || c === "\r";
}
backwards ? cursor-- : cursor++;
}
return false;
function hasNewline(text, index, opts) {
opts = opts || {};
const idx = skipSpaces(text, opts.backwards ? index - 1 : index, opts);
const idx2 = skipNewline(text, idx, opts);
return idx !== idx2;
}
function newlineExistsBefore(text, index) {
return findNewline(text, index, true);
function hasSpaces(text, index, opts) {
opts = opts || {};
const idx = skipSpaces(text, opts.backwards ? index - 1 : index, opts);
return idx !== index;
}
function newlineExistsAfter(text, index) {
return findNewline(text, index);
}
function skipSpaces(text, index, backwards) {
const length = text.length;
let cursor = backwards ? index - 1 : index;
// Look forward and see if there is a newline after/before this code
// by scanning up/back to the next non-indentation character.
while (cursor > 0 && cursor < length) {
const c = text.charAt(cursor);
// Skip any whitespace chars
if (!c.match(/\S/)) {
return cursor;
}
backwards ? cursor-- : cursor++;
}
return false;
}
function locStart(node) {

@@ -201,12 +223,12 @@ if (node.range) {

[
[ "||" ],
[ "&&" ],
[ "|" ],
[ "^" ],
[ "&" ],
[ "==", "===", "!=", "!==" ],
[ "<", ">", "<=", ">=", "in", "instanceof" ],
[ ">>", "<<", ">>>" ],
[ "+", "-" ],
[ "*", "/", "%", "**" ]
["||"],
["&&"],
["|"],
["^"],
["&"],
["==", "===", "!=", "!=="],
["<", ">", "<=", ">=", "in", "instanceof"],
[">>", "<<", ">>>"],
["+", "-"],
["*", "/", "%", "**"]
].forEach(function(tier, i) {

@@ -229,5 +251,8 @@ tier.forEach(function(op) {

getLast,
newlineExistsBefore,
newlineExistsAfter,
skipWhitespace,
skipSpaces,
skipToLineEnd,
skipNewline,
hasNewline,
hasSpaces,
locStart,

@@ -234,0 +259,0 @@ locEnd,

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc