fix(javascript): ternary with `--use-tabs` (#3745)

* test: add test cases

* test: add test cases

* fix(javascript): ternary with `--use-tabs`

* chore: add istanbul ignore comment

* fix: remove unnecessary condition

* docs(commands): update `align`

* fix: do not transform the middle part

* refactor: markAsRoot

* fix: print tabs in sub-ternaries

* docs(commands): update

* test: add a cool test case
master
Ika 2018-01-26 10:02:42 +08:00 committed by GitHub
parent acf5e66408
commit 03292a6488
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 1446 additions and 52 deletions

View File

@ -193,13 +193,33 @@ declare function indent(doc: Doc): Doc;
Increase the level of indentation.
### dedent
```ts
declare function dedent(doc: Doc): Doc;
```
Decrease the level of indentation. (Each `align` is considered one level of indentation.)
### align
```ts
declare function align(n: number, doc: Doc): Doc;
declare function align(n: number | string, doc: Doc): Doc;
```
This is similar to indent but it increases the level of indentation by a fixed number. When using tabs, it's going to print spaces. You should prefer using `indent` whenever possible.
This is similar to indent but it increases the level of indentation by a fixed number or a string.
Trailing alignments in indentation are still spaces, but middle ones are transformed into one tab per `align` when `useTabs` enabled.
If it's using in a whitespace-sensitive language, e.g. markdown, you should use `n` with string value to force print it.
For example:
* `useTabs`
* `tabWidth: 2`
* `<indent><align 2><indent><align 2>` -> `<tab><tab><tab><2 space>`
* `<indent><align 4><indent><align 2>` -> `<tab><tab><tab><2 space>`
* `tabWidth: 4`
* `<indent><align 2><indent><align 2>` -> `<tab><tab><tab><2 space>`
* `<indent><align 4><indent><align 2>` -> `<tab><tab><tab><2 space>`
### markAsRoot

View File

@ -61,7 +61,11 @@ function dedentToRoot(contents) {
}
function markAsRoot(contents) {
return align(Infinity, contents);
return align({ type: "root" }, contents);
}
function dedent(contents) {
return align(-1, contents);
}
function conditionalGroup(states, opts) {
@ -159,5 +163,6 @@ module.exports = {
align,
addAlignmentToDoc,
markAsRoot,
dedentToRoot
dedentToRoot,
dedent
};

View File

@ -70,13 +70,15 @@ function printDoc(doc) {
if (doc.type === "align") {
return doc.n === -Infinity
? "dedentToRoot(" + printDoc(doc.contents) + ")"
: doc.n === Infinity
? "markAsRoot(" + printDoc(doc.contents) + ")"
: "align(" +
JSON.stringify(doc.n) +
", " +
printDoc(doc.contents) +
")";
: doc.n < 0
? "dedent(" + printDoc(doc.contents) + ")"
: doc.n.type === "root"
? "markAsRoot(" + printDoc(doc.contents) + ")"
: "align(" +
JSON.stringify(doc.n) +
", " +
printDoc(doc.contents) +
")";
}
if (doc.type === "if-break") {

View File

@ -10,42 +10,103 @@ const MODE_BREAK = 1;
const MODE_FLAT = 2;
function rootIndent() {
return {
length: 0,
value: ""
};
return { value: "", length: 0, queue: [] };
}
function makeIndent(ind, options) {
return {
length: ind.length + options.tabWidth,
value: ind.value + (options.useTabs ? "\t" : " ".repeat(options.tabWidth)),
root: ind.root
};
return generateInd(ind, { type: "indent" }, options);
}
function makeAlign(ind, n, options) {
return n === -Infinity
? ind.root ? ind.root : rootIndent()
: n === Infinity
? {
length: ind.length,
value: ind.value,
root: ind
? ind.root || rootIndent()
: n < 0
? generateInd(ind, { type: "dedent" }, options)
: !n
? ind
: n.type === "root"
? Object.assign({}, ind, { root: ind })
: typeof n === "string"
? generateInd(ind, { type: "stringAlign", n }, options)
: generateInd(ind, { type: "numberAlign", n }, options);
}
function generateInd(ind, newPart, options) {
const queue =
newPart.type === "dedent"
? ind.queue.slice(0, -1)
: ind.queue.concat(newPart);
let value = "";
let length = 0;
let lastTabs = 0;
let lastSpaces = 0;
for (const part of queue) {
switch (part.type) {
case "indent":
flush();
if (options.useTabs) {
addTabs(1);
} else {
addSpaces(options.tabWidth);
}
: typeof n === "string"
? {
length: ind.length + n.length,
value: ind.value + n,
root: ind.root
}
: options.useTabs && n > 0
? makeIndent(ind, options)
: {
length: ind.length + n,
value: ind.value + " ".repeat(n),
root: ind.root
};
break;
case "stringAlign":
flush();
value += part.n;
length += part.n.length;
break;
case "numberAlign":
lastTabs += 1;
lastSpaces += part.n;
break;
/* istanbul ignore next */
default:
throw new Error(`Unexpected type '${part.type}'`);
}
}
flushSpaces();
return Object.assign({}, ind, { value, length, queue });
function addTabs(count) {
value += "\t".repeat(count);
length += options.tabWidth * count;
}
function addSpaces(count) {
value += " ".repeat(count);
length += count;
}
function flush() {
if (options.useTabs) {
flushTabs();
} else {
flushSpaces();
}
}
function flushTabs() {
if (lastTabs > 0) {
addTabs(lastTabs);
}
resetLast();
}
function flushSpaces() {
if (lastSpaces > 0) {
addSpaces(lastSpaces);
}
resetLast();
}
function resetLast() {
lastTabs = 0;
lastSpaces = 0;
}
}
function fits(next, restCommands, width, options, mustBeFlat) {

View File

@ -26,6 +26,7 @@ const ifBreak = docBuilders.ifBreak;
const breakParent = docBuilders.breakParent;
const lineSuffixBoundary = docBuilders.lineSuffixBoundary;
const addAlignmentToDoc = docBuilders.addAlignmentToDoc;
const dedent = docBuilders.dedent;
const docUtils = doc.utils;
const willBreak = docUtils.willBreak;
@ -1270,9 +1271,10 @@ function printPathNoParens(path, options, print, args) {
align(2, path.call(print, "alternate"))
]);
parts.push(
// TODO: remove `!options.useTabs` condition if #3745 merged
parent.type === "ConditionalExpression" && !options.useTabs
? align(Math.max(0, options.tabWidth - 2), part)
parent.type === "ConditionalExpression"
? options.useTabs
? dedent(indent(part))
: align(Math.max(0, options.tabWidth - 2), part)
: part
);
}

File diff suppressed because it is too large Load Diff

View File

@ -13,3 +13,155 @@ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
:
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
a
? {
a: 0
}
: {
a: {
a: 0
}
? {
a: 0
}
: {
y: {
a: 0
}
? {
a: 0
}
: {
a: 0
}
}
}
a
? {
a: function() {
return a
? {
a: [
a
? {
a: 0,
b: [
a
? [
0,
1
]
: []
]
}
: [
[
0,
{
a: 0
},
a
? 0
: 1
],
function() {
return a
? {
a: 0
}
: [
{
a: 0
},
{}
];
}
]
]
}
: [
a
? function() {
a
? a(
a
? {
a: a(
{
a: 0
}
)
}
: [
0,
a(),
a(
a(),
{
a: 0
},
a
? a()
: a(
{
a: 0
}
)
),
a()
? {
a: a(),
b: []
}
: {}
]
):
a(
a()
? {
a: 0
}
: (function(a) {
return a()
? [
{
a: 0,
b: a()
}
]
: a(
[
a
? {
a: 0
}
: {},
{
a: 0
}
]
);
})(
a
? function(a) {
return function() {
return 0;
};
}
: function(a) {
return function() {
return 1;
}
}
)
);
}
: function() {
}
];
}
}
: a;