2020-01-28 13:07:56 +08:00
( function ( global , factory ) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory ( exports ) :
typeof define === 'function' && define . amd ? define ( [ 'exports' ] , factory ) :
( global = global || self , factory ( global . doc = { } ) ) ;
} ( this , ( function ( exports ) { 'use strict' ;
/ * *
* @ param { Doc [ ] } parts
* @ returns Doc
* /
function concat ( parts ) {
// 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" ,
2020-03-31 20:40:00 +08:00
parts
2020-01-28 13:07:56 +08:00
} ;
}
/ * *
* @ param { Doc } contents
* @ returns Doc
* /
function indent ( contents ) {
return {
type : "indent" ,
2020-03-31 20:40:00 +08:00
contents
2020-01-28 13:07:56 +08:00
} ;
}
/ * *
* @ param { number } n
* @ param { Doc } contents
* @ returns Doc
* /
function align ( n , contents ) {
return {
type : "align" ,
2020-03-31 20:40:00 +08:00
contents ,
n
2020-01-28 13:07:56 +08:00
} ;
}
/ * *
* @ param { Doc } contents
* @ param { object } [ opts ] - TBD ? ? ?
* @ returns Doc
* /
function group ( contents , opts ) {
opts = opts || { } ;
return {
type : "group" ,
id : opts . id ,
2020-03-31 20:40:00 +08:00
contents ,
2020-01-28 13:07:56 +08:00
break : ! ! opts . shouldBreak ,
expandedStates : opts . expandedStates
} ;
}
/ * *
* @ param { Doc } contents
* @ returns Doc
* /
function dedentToRoot ( contents ) {
return align ( - Infinity , contents ) ;
}
/ * *
* @ param { Doc } contents
* @ returns Doc
* /
function markAsRoot ( contents ) {
// @ts-ignore - TBD ???:
return align ( {
type : "root"
} , contents ) ;
}
/ * *
* @ param { Doc } contents
* @ returns Doc
* /
function dedent ( contents ) {
return align ( - 1 , contents ) ;
}
/ * *
* @ param { Doc [ ] } states
* @ param { object } [ opts ] - TBD ? ? ?
* @ returns Doc
* /
function conditionalGroup ( states , opts ) {
2020-03-31 20:40:00 +08:00
return group ( states [ 0 ] , Object . assign ( { } , opts , {
2020-01-28 13:07:56 +08:00
expandedStates : states
} ) ) ;
}
/ * *
* @ param { Doc [ ] } parts
* @ returns Doc
* /
function fill ( parts ) {
return {
type : "fill" ,
2020-03-31 20:40:00 +08:00
parts
2020-01-28 13:07:56 +08:00
} ;
}
/ * *
* @ param { Doc } [ breakContents ]
* @ param { Doc } [ flatContents ]
* @ param { object } [ opts ] - TBD ? ? ?
* @ returns Doc
* /
function ifBreak ( breakContents , flatContents , opts ) {
opts = opts || { } ;
return {
type : "if-break" ,
2020-03-31 20:40:00 +08:00
breakContents ,
flatContents ,
2020-01-28 13:07:56 +08:00
groupId : opts . groupId
} ;
}
/ * *
* @ param { Doc } contents
* @ returns Doc
* /
function lineSuffix ( contents ) {
return {
type : "line-suffix" ,
2020-03-31 20:40:00 +08:00
contents
2020-01-28 13:07:56 +08:00
} ;
}
2020-03-31 20:40:00 +08:00
const lineSuffixBoundary = {
2020-01-28 13:07:56 +08:00
type : "line-suffix-boundary"
} ;
2020-03-31 20:40:00 +08:00
const breakParent = {
2020-01-28 13:07:56 +08:00
type : "break-parent"
} ;
2020-03-31 20:40:00 +08:00
const trim = {
2020-01-28 13:07:56 +08:00
type : "trim"
} ;
2020-03-31 20:40:00 +08:00
const line = {
2020-01-28 13:07:56 +08:00
type : "line"
} ;
2020-03-31 20:40:00 +08:00
const softline = {
2020-01-28 13:07:56 +08:00
type : "line" ,
soft : true
} ;
2020-03-31 20:40:00 +08:00
const hardline = concat ( [ {
2020-01-28 13:07:56 +08:00
type : "line" ,
hard : true
} , breakParent ] ) ;
2020-03-31 20:40:00 +08:00
const literalline = concat ( [ {
2020-01-28 13:07:56 +08:00
type : "line" ,
hard : true ,
literal : true
} , breakParent ] ) ;
2020-03-31 20:40:00 +08:00
const cursor = {
2020-01-28 13:07:56 +08:00
type : "cursor" ,
placeholder : Symbol ( "cursor" )
} ;
/ * *
* @ param { Doc } sep
* @ param { Doc [ ] } arr
* @ returns Doc
* /
function join ( sep , arr ) {
2020-03-31 20:40:00 +08:00
const res = [ ] ;
2020-01-28 13:07:56 +08:00
2020-03-31 20:40:00 +08:00
for ( let i = 0 ; i < arr . length ; i ++ ) {
2020-01-28 13:07:56 +08:00
if ( i !== 0 ) {
res . push ( sep ) ;
}
res . push ( arr [ i ] ) ;
}
return concat ( res ) ;
}
/ * *
* @ param { Doc } doc
* @ param { number } size
* @ param { number } tabWidth
* /
function addAlignmentToDoc ( doc , size , tabWidth ) {
2020-03-31 20:40:00 +08:00
let aligned = doc ;
2020-01-28 13:07:56 +08:00
if ( size > 0 ) {
// Use indent to add tabs for all the levels of tabs we need
2020-03-31 20:40:00 +08:00
for ( let i = 0 ; i < Math . floor ( size / tabWidth ) ; ++ i ) {
2020-01-28 13:07:56 +08:00
aligned = indent ( aligned ) ;
} // Use align for all the spaces that are needed
aligned = align ( size % tabWidth , aligned ) ; // size is absolute from 0 and not relative to the current
// indentation, so we use -Infinity to reset the indentation to 0
aligned = align ( - Infinity , aligned ) ;
}
return aligned ;
}
var docBuilders = {
2020-03-31 20:40:00 +08:00
concat ,
join ,
line ,
softline ,
hardline ,
literalline ,
group ,
conditionalGroup ,
fill ,
lineSuffix ,
lineSuffixBoundary ,
cursor ,
breakParent ,
ifBreak ,
trim ,
indent ,
align ,
addAlignmentToDoc ,
markAsRoot ,
dedentToRoot ,
dedent
2020-01-28 13:07:56 +08:00
} ;
2020-03-31 20:40:00 +08:00
var ansiRegex = ( {
onlyFirst = false
} = { } ) => {
const pattern = [ '[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)' , '(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))' ] . join ( '|' ) ;
return new RegExp ( pattern , onlyFirst ? undefined : 'g' ) ;
2020-01-28 13:07:56 +08:00
} ;
2020-03-31 20:40:00 +08:00
var stripAnsi = string => typeof string === 'string' ? string . replace ( ansiRegex ( ) , '' ) : string ;
2020-01-28 13:07:56 +08:00
/* eslint-disable yoda */
2020-03-31 20:40:00 +08:00
const isFullwidthCodePoint = codePoint => {
2020-01-28 13:07:56 +08:00
if ( Number . isNaN ( codePoint ) ) {
return false ;
} // Code points are derived from:
// http://www.unix.org/Public/UNIDATA/EastAsianWidth.txt
if ( codePoint >= 0x1100 && ( codePoint <= 0x115F || // Hangul Jamo
codePoint === 0x2329 || // LEFT-POINTING ANGLE BRACKET
codePoint === 0x232A || // RIGHT-POINTING ANGLE BRACKET
// CJK Radicals Supplement .. Enclosed CJK Letters and Months
0x2E80 <= codePoint && codePoint <= 0x3247 && codePoint !== 0x303F || // Enclosed CJK Letters and Months .. CJK Unified Ideographs Extension A
0x3250 <= codePoint && codePoint <= 0x4DBF || // CJK Unified Ideographs .. Yi Radicals
0x4E00 <= codePoint && codePoint <= 0xA4C6 || // Hangul Jamo Extended-A
0xA960 <= codePoint && codePoint <= 0xA97C || // Hangul Syllables
0xAC00 <= codePoint && codePoint <= 0xD7A3 || // CJK Compatibility Ideographs
0xF900 <= codePoint && codePoint <= 0xFAFF || // Vertical Forms
0xFE10 <= codePoint && codePoint <= 0xFE19 || // CJK Compatibility Forms .. Small Form Variants
0xFE30 <= codePoint && codePoint <= 0xFE6B || // Halfwidth and Fullwidth Forms
0xFF01 <= codePoint && codePoint <= 0xFF60 || 0xFFE0 <= codePoint && codePoint <= 0xFFE6 || // Kana Supplement
0x1B000 <= codePoint && codePoint <= 0x1B001 || // Enclosed Ideographic Supplement
0x1F200 <= codePoint && codePoint <= 0x1F251 || // CJK Unified Ideographs Extension B .. Tertiary Ideographic Plane
0x20000 <= codePoint && codePoint <= 0x3FFFD ) ) {
return true ;
}
return false ;
} ;
var isFullwidthCodePoint _1 = isFullwidthCodePoint ;
2020-03-31 20:40:00 +08:00
var default _1 = isFullwidthCodePoint ;
isFullwidthCodePoint _1 . default = default _1 ;
2020-01-28 13:07:56 +08:00
var emojiRegex = function emojiRegex ( ) {
// https://mths.be/emoji
return / \ u D 8 3 C \ u D F F 4 \ u D B 4 0 \ u D C 6 7 \ u D B 4 0 \ u D C 6 2 ( ? : \ u D B 4 0 \ u D C 6 5 \ u D B 4 0 \ u D C 6 E \ u D B 4 0 \ u D C 6 7 | \ u D B 4 0 \ u D C 7 3 \ u D B 4 0 \ u D C 6 3 \ u D B 4 0 \ u D C 7 4 | \ u D B 4 0 \ u D C 7 7 \ u D B 4 0 \ u D C 6 C \ u D B 4 0 \ u D C 7 3 ) \ u D B 4 0 \ u D C 7 F | \ u D 8 3 D \ u D C 6 8 ( ? : \ u D 8 3 C \ u D F F C \ u 2 0 0 D ( ? : \ u D 8 3 E \ u D D 1 D \ u 2 0 0 D \ u D 8 3 D \ u D C 6 8 \ u D 8 3 C \ u D F F B | \ u D 8 3 C [ \ u D F 3 E \ u D F 7 3 \ u D F 9 3 \ u D F A 4 \ u D F A 8 \ u D F E B \ u D F E D ] | \ u D 8 3 D [ \ u D C B B \ u D C B C \ u D D 2 7 \ u D D 2 C \ u D E 8 0 \ u D E 9 2 ] | \ u D 8 3 E [ \ u D D A F - \ u D D B 3 \ u D D B C \ u D D B D ] ) | \ u D 8 3 C \ u D F F F \ u 2 0 0 D ( ? : \ u D 8 3 E \ u D D 1 D \ u 2 0 0 D \ u D 8 3 D \ u D C 6 8 ( ? : \ u D 8 3 C [ \ u D F F B - \ u D F F E ] ) | \ u D 8 3 C [ \ u D F 3 E \ u D F 7 3 \ u D F 9 3 \ u D F A 4 \ u D F A 8 \ u D F E B \ u D F E D ] | \ u D 8 3 D [ \ u D C B B \ u D C B C \ u D D 2 7 \ u D D 2 C \ u D E 8 0 \ u D E 9 2 ] | \ u D 8 3 E [ \ u D D A F - \ u D D B 3 \ u D D B C \ u D D B D ] ) | \ u D 8 3 C \ u D F F E \ u 2 0 0 D ( ? : \ u D 8 3 E \ u D D 1 D \ u 2 0 0 D \ u D 8 3 D \ u D C 6 8 ( ? : \ u D 8 3 C [ \ u D F F B - \ u D F F D ] ) | \ u D 8 3 C [ \ u D F 3 E \ u D F 7 3 \ u D F 9 3 \ u D F A 4 \ u D F A 8 \ u D F E B \ u D F E D ] | \ u D 8 3 D [ \ u D C B B \ u D C B C \ u D D 2 7 \ u D D 2 C \ u D E 8 0 \ u D E 9 2 ] | \ u D 8 3 E [ \ u D D A F - \ u D D B 3 \ u D D B C \ u D D B D ] ) | \ u D 8 3 C \ u D F F D \ u 2 0 0 D ( ? : \ u D 8 3 E \ u D D 1 D \ u 2 0 0 D \ u D 8 3 D \ u D C 6 8 ( ? : \ u D 8 3 C [ \ u D F F B \ u D F F C ] ) | \ u D 8 3 C [ \ u D F 3 E \ u D F 7 3 \ u D F 9 3 \ u D F A 4 \ u D F A 8 \ u D F E B \ u D F E D ] | \ u D 8 3 D [ \ u D C B B \ u D C B C \ u D D 2 7 \ u D D 2 C \ u D E 8 0 \ u D E 9 2 ] | \ u D 8 3 E [ \ u D D A F - \ u D D B 3 \ u D D B C \ u D D B D ] ) | \ u 2 0 0 D ( ? : \ u 2 7 6 4 \ u F E 0 F \ u 2 0 0 D ( ? : \ u D 8 3 D \ u D C 8 B \ u 2 0 0 D ) ? \ u D 8 3 D \ u D C 6 8 | ( ? : \ u D 8 3 D [ \ u D C 6 8 \ u D C 6 9 ] ) \ u 2 0 0 D ( ? : \ u D 8 3 D \ u D C 6 6 \ u 2 0 0 D \ u D 8 3 D \ u D C 6 6 | \ u D 8 3 D \ u D C 6 7 \ u 2 0 0 D ( ? : \ u D 8 3 D [ \ u D C 6 6 \ u D C 6 7 ] ) ) | \ u D 8 3 D \ u D C 6 6 \ u 2 0 0 D \ u D 8 3 D \ u D C 6 6 | \ u D 8 3 D \ u D C 6 7 \ u 2 0 0 D ( ? : \ u D 8 3 D [ \ u D C 6 6 \ u D C 6 7 ] ) | ( ? : \ u D 8 3 D [ \ u D C 6 8 \ u D C 6 9 ] ) \ u 2 0 0 D ( ? : \ u D 8 3 D [ \ u D C 6 6 \ u D C 6 7 ] ) | [ \ u 2 6 9 5 \ u 2 6 9 6 \ u 2 7 0 8 ] \ u F E 0 F | \ u D 8 3 D [ \ u D C 6 6 \ u D C 6 7 ] | \ u D 8 3 C [ \ u D F 3 E \ u D F 7 3 \ u D F 9 3 \ u D F A 4 \ u D F A 8 \ u D F E B \ u D F E D ] | \ u D 8 3 D [ \ u D C B B \ u D C B C \ u D D 2 7 \ u D D 2 C \ u D E 8 0 \ u D E 9 2 ] | \ u D 8 3 E [ \ u D D A F - \ u D D B 3 \ u D D B C \ u D D B D ] ) | ( ? : \ u D 8 3 C \ u D F F B \ u 2 0 0 D [ \ u 2 6 9 5 \ u 2 6 9 6 \ u 2 7 0 8 ] | \ u D 8 3 C \ u D F F F \ u 2 0 0 D [ \ u 2 6 9 5 \ u 2 6 9 6 \ u 2 7 0 8 ] | \ u D 8 3 C \ u D F F E \ u 2 0 0 D [ \ u 2 6 9 5 \ u 2 6 9 6 \ u 2 7 0 8 ] | \ u D 8 3 C \ u D F F D \ u 2 0 0 D [ \ u 2 6 9 5 \ u 2 6 9 6 \ u 2 7 0 8 ] | \ u D 8 3 C \ u D F F C \ u 2 0 0 D [ \ u 2 6 9 5 \ u 2 6 9 6 \ u 2 7 0 8 ] ) \ u F E 0 F | \ u D 8 3 C \ u D F F B \ u 2 0 0 D ( ? : \ u D 8 3 C [ \ u D F 3 E \ u D F 7 3 \ u D F 9 3 \ u D F A 4 \ u D F A 8 \ u D F E B \ u D F E D ] | \ u D 8 3 D [ \ u D C B B \ u D C B C \ u D D 2 7 \ u D D 2 C \ u D E 8 0 \ u D E 9 2 ] | \ u D 8 3 E [ \ u D D A F - \ u D D B 3 \ u D D B C \ u D D B D ] ) | \ u D 8 3 C [ \ u D F F B - \ u D F F F ] ) | ( ? : \ u D 8 3 E \ u D D D 1 \ u D 8 3 C \ u D F F B \ u 2 0 0 D \ u D 8 3 E \ u D D 1 D \ u 2 0 0 D \ u D 8 3 E \ u D D D 1 | \ u D 8 3 D \ u D C 6 9 \ u D 8 3 C \ u D F F C \ u 2 0 0 D \ u D 8 3 E \ u D D 1 D \ u 2 0 0 D \ u D 8 3 D \ u D C 6 9 ) \ u D 8 3 C \ u D F F B | \ u D 8 3 E \ u D D D 1 ( ? : \ u D 8 3 C \ u D F F F \ u 2 0 0 D \ u D 8 3 E \ u D D 1 D \ u 2 0 0 D \ u D 8 3 E \ u D D D 1 ( ? : \ u D 8 3 C [ \ u D F F B - \ u D F F F ] ) | \ u 2 0 0 D \ u D 8 3 E \ u D D 1 D \ u 2 0 0 D \ u D 8 3 E \ u D D D 1 ) | ( ? : \ u D 8 3 E \ u D D D 1 \ u D 8 3 C \ u D F F E \ u 2 0 0 D \ u D 8 3 E \ u D D 1 D \ u 2 0 0 D \ u D 8 3 E \ u D D D 1 | \ u D 8 3 D \ u D C 6 9 \ u D 8 3 C \ u D F F F \ u 2 0 0 D \ u D 8 3 E \ u D D 1 D \ u 2 0 0 D ( ? : \ u D 8 3 D [ \ u D C 6 8 \ u D C 6 9 ] ) ) ( ? : \ u D 8 3 C [ \ u D F F B - \ u D F F E ] ) | ( ? : \ u D 8 3 E \ u D D D 1 \ u D 8 3 C \ u D F F C \ u 2 0 0 D \ u D 8 3 E \ u D D 1 D \ u 2 0 0 D \ u D 8 3 E \ u D D D 1 | \ u D 8 3 D \ u D C 6 9 \ u D 8 3 C \ u D F F D \ u 2 0 0 D \ u D 8 3 E \ u D D 1 D \ u 2 0 0 D \ u D 8 3 D \ u D C 6 9 ) ( ? : \ u D 8 3 C [ \ u D F F B \ u D F F C ] ) | \ u D 8 3 D \ u D C 6 9 ( ? : \ u D 8 3 C \ u D F F E \ u 2 0 0 D ( ? : \ u D 8 3 E \ u D D 1 D \ u 2 0 0 D \ u D 8 3 D \ u D C 6 8 ( ? : \ u D 8 3 C [ \ u D F F B - \ u D F F D \ u D F F F ] ) | \ u D 8 3 C [ \ u D F 3 E \ u D F 7 3 \ u D F 9 3 \ u D F A 4 \ u D F A 8 \ u D F E B \ u D F E D ] | \ u D 8 3 D [ \ u D C B B \ u D C B C \ u D D 2 7 \ u D D 2 C \ u D E 8 0 \ u D E 9 2 ] | \ u D 8 3 E [ \ u D D A F - \ u D D B 3 \ u D D B C \ u D D B D ] ) | \ u D 8 3 C \ u D F F C \ u 2 0 0 D ( ? : \ u D 8 3 E \ u D D 1 D \ u 2 0 0 D \ u D 8 3 D \ u D C 6 8 ( ? : \ u D 8 3 C [ \ u D F F B \ u D F F D - \ u D F F F ] ) | \ u D 8 3 C [ \ u D F 3 E \ u D F 7 3 \ u D F 9 3 \ u D F A 4 \ u D F A 8 \ u D F E B \ u D F E D ] | \ u D 8 3 D [ \ u D C B B \ u D C B C \ u D D 2 7 \ u D D 2 C \ u D E 8 0 \ u D E 9 2 ] | \ u D 8 3 E [ \ u D D A F - \ u D D B 3 \ u D D B C \ u D D B D ] ) | \ u D 8 3 C \ u D F F B \ u 2 0 0 D ( ? : \ u D 8 3 E \ u D D 1 D \ u 2 0 0 D \ u D 8 3 D \ u D C 6 8 ( ? : \ u D 8 3 C [ \ u D F F C - \ u D F F F ] ) | \ u D 8 3 C [ \ u D F 3 E \ u D F 7 3 \ u D F 9 3 \ u D F A 4 \ u D F A 8 \ u D F E B \ u D F E D ] | \ u D 8 3 D [ \ u D C B B \ u D C B C \ u D D 2 7 \ u D D 2 C \ u D E 8 0 \ u D E 9 2 ] | \ u D 8 3 E [ \ u D D A F - \ u D D B 3 \ u D D B C \ u D D B D ] ) | \ u D 8 3 C \ u D F F D \ u 2 0 0 D ( ? : \ u D 8 3 E \ u D D 1 D \ u 2 0 0 D \ u D 8 3 D \ u D C 6 8 ( ? : \ u D 8 3 C [ \ u D F F B \ u D F F C \ u D F F E \ u D F F F ] ) | \ u D 8 3 C [ \ u D F 3 E \ u D F 7 3 \ u D F 9 3 \ u D F A 4 \ u D F A 8 \ u D F E B \ u D F E D ] | \ u D 8 3 D [ \ u D C B B \ u D C B C \ u D D 2 7 \ u D D 2 C \ u D E 8 0 \ u D E 9 2 ] | \ u D 8 3 E [ \ u D D A F - \ u D D B 3 \ u D D B C \ u D D B D ] ) | \ u 2 0 0 D ( ? : \ u 2 7 6 4 \ u F E 0 F \ u 2 0 0 D ( ? : \ u D 8 3 D \ u D C 8 B \ u 2 0 0 D ( ? : \ u D 8 3 D [ \ u D C 6 8 \ u D C 6 9 ] ) | \ u D 8 3 D [ \ u D C 6 8 \ u D C 6 9 ] ) | \ u D 8 3 C [ \ u D F 3 E \ u D F 7 3 \ u D F 9 3 \ u D F A 4 \ u D F A 8 \ u D F E B \ u D F E D ] | \ u D 8 3 D [ \ u D C B B \ u D C B C \ u D D 2 7 \ u D D 2 C \ u D E 8 0 \ u D E 9 2 ] | \ u D 8 3 E [ \ u D D A F - \ u D D B 3 \ u D D B C \ u D D B D ] ) | \ u D 8 3 C \ u D F F F \ u 2 0 0 D ( ? : \ u D 8 3 C [ \ u D F 3 E \ u D F 7 3 \ u D F 9 3 \ u D F A 4 \ u D F A 8 \ u D F E B \ u D F E D ] | \ u D 8 3 D [ \ u D C B B \ u D C B C \ u D D 2 7 \ u D D 2 C \ u D E 8 0 \ u D E 9 2 ] | \ u D 8 3 E [ \ u D D A F - \ u D D B 3 \ u D D B C \ u D D B D ] ) ) | \ u D 8 3 D \ u D C 6 9 \ u 2 0 0 D \ u D 8 3 D \ u D C 6 9 \ u 2 0 0 D ( ? : \ u D 8 3 D \ u D C 6 6 \ u 2 0 0 D \ u D 8 3 D \ u D C 6 6 | \ u D 8 3 D \ u D C 6 7 \ u 2 0 0 D ( ? : \ u D 8 3 D [ \ u D C 6 6 \ u D C 6 7 ] ) ) | ( ? : \ u D 8 3 E \ u D D D 1 \ u D 8 3 C \ u D F F D \ u 2 0 0 D \ u D 8 3 E \ u D D 1 D \ u 2 0 0 D \ u D 8 3 E \ u D D D 1 | \ u D 8 3 D \ u D C 6 9 \ u D 8 3 C \ u D F F E \ u 2 0 0 D \ u D 8 3 E \ u D D 1 D \ u 2 0 0 D \ u D 8 3 D \ u D C 6 9 ) ( ? : \ u D 8 3 C [ \ u D F F B - \ u D F F D ] ) | \ u D 8 3 D \ u D C 6 9 \ u 2 0 0 D \ u D 8 3 D \ u D C 6 6 \ u 2 0 0 D \ u D 8 3 D \ u D C 6 6 | \ u D 8 3 D \ u D C 6 9 \ u 2 0 0 D \ u D 8 3 D \ u D C 6 9 \ u 2 0 0 D ( ? : \ u D 8 3 D [ \ u D C 6 6 \ u D C 6 7 ] ) | ( ? : \ u D 8 3 D \ u D C 4 1 \ u F E 0 F \ u 2 0 0
} ;
2020-03-31 20:40:00 +08:00
const stringWidth = string => {
2020-01-28 13:07:56 +08:00
string = string . replace ( emojiRegex ( ) , ' ' ) ;
if ( typeof string !== 'string' || string . length === 0 ) {
return 0 ;
}
2020-03-31 20:40:00 +08:00
string = stripAnsi ( string ) ;
let width = 0 ;
2020-01-28 13:07:56 +08:00
2020-03-31 20:40:00 +08:00
for ( let i = 0 ; i < string . length ; i ++ ) {
const code = string . codePointAt ( i ) ; // Ignore control characters
2020-01-28 13:07:56 +08:00
if ( code <= 0x1F || code >= 0x7F && code <= 0x9F ) {
continue ;
} // Ignore combining characters
if ( code >= 0x300 && code <= 0x36F ) {
continue ;
} // Surrogates
if ( code > 0xFFFF ) {
i ++ ;
}
width += isFullwidthCodePoint _1 ( code ) ? 2 : 1 ;
}
return width ;
} ;
var stringWidth _1 = stringWidth ; // TODO: remove this in the next major version
2020-03-31 20:40:00 +08:00
var default _1$1 = stringWidth ;
stringWidth _1 . default = default _1$1 ;
2020-01-28 13:07:56 +08:00
2020-03-31 20:40:00 +08:00
const matchOperatorsRegex = /[|\\{}()[\]^$+*?.-]/g ;
2020-01-28 13:07:56 +08:00
2020-03-31 20:40:00 +08:00
var escapeStringRegexp = string => {
if ( typeof string !== 'string' ) {
2020-01-28 13:07:56 +08:00
throw new TypeError ( 'Expected a string' ) ;
}
2020-03-31 20:40:00 +08:00
return string . replace ( matchOperatorsRegex , '\\$&' ) ;
2020-01-28 13:07:56 +08:00
} ;
2020-03-31 20:40:00 +08:00
var getLast = arr => arr [ arr . length - 1 ] ;
2020-01-28 13:07:56 +08:00
2020-03-31 20:40:00 +08:00
const notAsciiRegex = /[^\x20-\x7F]/ ;
2020-01-28 13:07:56 +08:00
function getPenultimate ( arr ) {
if ( arr . length > 1 ) {
return arr [ arr . length - 2 ] ;
}
return null ;
}
/ * *
* @ typedef { { backwards ? : boolean } } SkipOptions
* /
/ * *
* @ param { string | RegExp } chars
* @ returns { ( text : string , index : number | false , opts ? : SkipOptions ) => number | false }
* /
function skip ( chars ) {
2020-03-31 20:40:00 +08:00
return ( text , index , opts ) => {
const backwards = opts && opts . backwards ; // Allow `skip` functions to be threaded together without having
2020-01-28 13:07:56 +08:00
// to check for failures (did someone say monads?).
if ( index === false ) {
return false ;
}
2020-03-31 20:40:00 +08:00
const {
length
} = text ;
let cursor = index ;
2020-01-28 13:07:56 +08:00
while ( cursor >= 0 && cursor < length ) {
2020-03-31 20:40:00 +08:00
const c = text . charAt ( cursor ) ;
2020-01-28 13:07:56 +08:00
if ( chars instanceof RegExp ) {
if ( ! chars . test ( c ) ) {
return cursor ;
}
2020-03-31 20:40:00 +08:00
} else if ( ! chars . includes ( c ) ) {
2020-01-28 13:07:56 +08:00
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 ;
} ;
}
/ * *
* @ type { ( text : string , index : number | false , opts ? : SkipOptions ) => number | false }
* /
2020-03-31 20:40:00 +08:00
const skipWhitespace = skip ( /\s/ ) ;
2020-01-28 13:07:56 +08:00
/ * *
* @ type { ( text : string , index : number | false , opts ? : SkipOptions ) => number | false }
* /
2020-03-31 20:40:00 +08:00
const skipSpaces = skip ( " \t" ) ;
2020-01-28 13:07:56 +08:00
/ * *
* @ type { ( text : string , index : number | false , opts ? : SkipOptions ) => number | false }
* /
2020-03-31 20:40:00 +08:00
const skipToLineEnd = skip ( ",; \t" ) ;
2020-01-28 13:07:56 +08:00
/ * *
* @ type { ( text : string , index : number | false , opts ? : SkipOptions ) => number | false }
* /
2020-03-31 20:40:00 +08:00
const skipEverythingButNewLine = skip ( /[^\r\n]/ ) ;
2020-01-28 13:07:56 +08:00
/ * *
* @ param { string } text
* @ param { number | false } index
* @ returns { number | false }
* /
function skipInlineComment ( text , index ) {
if ( index === false ) {
return false ;
}
if ( text . charAt ( index ) === "/" && text . charAt ( index + 1 ) === "*" ) {
2020-03-31 20:40:00 +08:00
for ( let i = index + 2 ; i < text . length ; ++ i ) {
2020-01-28 13:07:56 +08:00
if ( text . charAt ( i ) === "*" && text . charAt ( i + 1 ) === "/" ) {
return i + 2 ;
}
}
}
return index ;
}
/ * *
* @ param { string } text
* @ param { number | false } index
* @ returns { number | false }
* /
function skipTrailingComment ( text , index ) {
if ( index === false ) {
return false ;
}
if ( text . charAt ( index ) === "/" && text . charAt ( index + 1 ) === "/" ) {
return skipEverythingButNewLine ( text , index ) ;
}
return index ;
} // 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.
/ * *
* @ param { string } text
* @ param { number | false } index
* @ param { SkipOptions = } opts
* @ returns { number | false }
* /
function skipNewline ( text , index , opts ) {
2020-03-31 20:40:00 +08:00
const backwards = opts && opts . backwards ;
2020-01-28 13:07:56 +08:00
if ( index === false ) {
return false ;
}
2020-03-31 20:40:00 +08:00
const atIndex = text . charAt ( index ) ;
2020-01-28 13:07:56 +08:00
if ( backwards ) {
if ( text . charAt ( index - 1 ) === "\r" && atIndex === "\n" ) {
return index - 2 ;
}
if ( atIndex === "\n" || atIndex === "\r" || atIndex === "\u2028" || atIndex === "\u2029" ) {
return index - 1 ;
}
} else {
if ( atIndex === "\r" && text . charAt ( index + 1 ) === "\n" ) {
return index + 2 ;
}
if ( atIndex === "\n" || atIndex === "\r" || atIndex === "\u2028" || atIndex === "\u2029" ) {
return index + 1 ;
}
}
return index ;
}
/ * *
* @ param { string } text
* @ param { number } index
* @ param { SkipOptions = } opts
* @ returns { boolean }
* /
function hasNewline ( text , index , opts ) {
opts = opts || { } ;
2020-03-31 20:40:00 +08:00
const idx = skipSpaces ( text , opts . backwards ? index - 1 : index , opts ) ;
const idx2 = skipNewline ( text , idx , opts ) ;
2020-01-28 13:07:56 +08:00
return idx !== idx2 ;
}
/ * *
* @ param { string } text
* @ param { number } start
* @ param { number } end
* @ returns { boolean }
* /
function hasNewlineInRange ( text , start , end ) {
2020-03-31 20:40:00 +08:00
for ( let i = start ; i < end ; ++ i ) {
2020-01-28 13:07:56 +08:00
if ( text . charAt ( i ) === "\n" ) {
return true ;
}
}
return false ;
} // Note: this function doesn't ignore leading comments unlike isNextLineEmpty
/ * *
* @ template N
* @ param { string } text
* @ param { N } node
* @ param { ( node : N ) => number } locStart
* /
function isPreviousLineEmpty ( text , node , locStart ) {
/** @type {number | false} */
2020-03-31 20:40:00 +08:00
let idx = locStart ( node ) - 1 ;
2020-01-28 13:07:56 +08:00
idx = skipSpaces ( text , idx , {
backwards : true
} ) ;
idx = skipNewline ( text , idx , {
backwards : true
} ) ;
idx = skipSpaces ( text , idx , {
backwards : true
} ) ;
2020-03-31 20:40:00 +08:00
const idx2 = skipNewline ( text , idx , {
2020-01-28 13:07:56 +08:00
backwards : true
} ) ;
return idx !== idx2 ;
}
/ * *
* @ param { string } text
* @ param { number } index
* @ returns { boolean }
* /
function isNextLineEmptyAfterIndex ( text , index ) {
/** @type {number | false} */
2020-03-31 20:40:00 +08:00
let oldIdx = null ;
2020-01-28 13:07:56 +08:00
/** @type {number | false} */
2020-03-31 20:40:00 +08:00
let idx = index ;
2020-01-28 13:07:56 +08:00
while ( idx !== oldIdx ) {
// We need to skip all the potential trailing inline comments
oldIdx = idx ;
idx = skipToLineEnd ( text , idx ) ;
idx = skipInlineComment ( text , idx ) ;
idx = skipSpaces ( text , idx ) ;
}
idx = skipTrailingComment ( text , idx ) ;
idx = skipNewline ( text , idx ) ;
return idx !== false && hasNewline ( text , idx ) ;
}
/ * *
* @ template N
* @ param { string } text
* @ param { N } node
* @ param { ( node : N ) => number } locEnd
* @ returns { boolean }
* /
function isNextLineEmpty ( text , node , locEnd ) {
return isNextLineEmptyAfterIndex ( text , locEnd ( node ) ) ;
}
/ * *
* @ param { string } text
* @ param { number } idx
* @ returns { number | false }
* /
function getNextNonSpaceNonCommentCharacterIndexWithStartIndex ( text , idx ) {
/** @type {number | false} */
2020-03-31 20:40:00 +08:00
let oldIdx = null ;
2020-01-28 13:07:56 +08:00
/** @type {number | false} */
2020-03-31 20:40:00 +08:00
let nextIdx = idx ;
2020-01-28 13:07:56 +08:00
while ( nextIdx !== oldIdx ) {
oldIdx = nextIdx ;
nextIdx = skipSpaces ( text , nextIdx ) ;
nextIdx = skipInlineComment ( text , nextIdx ) ;
nextIdx = skipTrailingComment ( text , nextIdx ) ;
nextIdx = skipNewline ( text , nextIdx ) ;
}
return nextIdx ;
}
/ * *
* @ template N
* @ param { string } text
* @ param { N } node
* @ param { ( node : N ) => number } locEnd
* @ returns { number | false }
* /
function getNextNonSpaceNonCommentCharacterIndex ( text , node , locEnd ) {
return getNextNonSpaceNonCommentCharacterIndexWithStartIndex ( text , locEnd ( node ) ) ;
}
/ * *
* @ template N
* @ param { string } text
* @ param { N } node
* @ param { ( node : N ) => number } locEnd
* @ returns { string }
* /
function getNextNonSpaceNonCommentCharacter ( text , node , locEnd ) {
return text . charAt ( // @ts-ignore => TBD: can return false, should we define a fallback?
getNextNonSpaceNonCommentCharacterIndex ( text , node , locEnd ) ) ;
}
/ * *
* @ param { string } text
* @ param { number } index
* @ param { SkipOptions = } opts
* @ returns { boolean }
* /
function hasSpaces ( text , index , opts ) {
opts = opts || { } ;
2020-03-31 20:40:00 +08:00
const idx = skipSpaces ( text , opts . backwards ? index - 1 : index , opts ) ;
2020-01-28 13:07:56 +08:00
return idx !== index ;
}
/ * *
* @ param { { range ? : [ number , number ] , start ? : number } } node
* @ param { number } index
* /
function setLocStart ( node , index ) {
if ( node . range ) {
node . range [ 0 ] = index ;
} else {
node . start = index ;
}
}
/ * *
* @ param { { range ? : [ number , number ] , end ? : number } } node
* @ param { number } index
* /
function setLocEnd ( node , index ) {
if ( node . range ) {
node . range [ 1 ] = index ;
} else {
node . end = index ;
}
}
2020-03-31 20:40:00 +08:00
const PRECEDENCE = { } ;
[ [ "|>" ] , [ "??" ] , [ "||" ] , [ "&&" ] , [ "|" ] , [ "^" ] , [ "&" ] , [ "==" , "===" , "!=" , "!==" ] , [ "<" , ">" , "<=" , ">=" , "in" , "instanceof" ] , [ ">>" , "<<" , ">>>" ] , [ "+" , "-" ] , [ "*" , "/" , "%" ] , [ "**" ] ] . forEach ( ( tier , i ) => {
tier . forEach ( op => {
2020-01-28 13:07:56 +08:00
PRECEDENCE [ op ] = i ;
} ) ;
} ) ;
function getPrecedence ( op ) {
return PRECEDENCE [ op ] ;
}
2020-03-31 20:40:00 +08:00
const equalityOperators = {
2020-01-28 13:07:56 +08:00
"==" : true ,
"!=" : true ,
"===" : true ,
"!==" : true
} ;
2020-03-31 20:40:00 +08:00
const multiplicativeOperators = {
2020-01-28 13:07:56 +08:00
"*" : true ,
"/" : true ,
"%" : true
} ;
2020-03-31 20:40:00 +08:00
const bitshiftOperators = {
2020-01-28 13:07:56 +08:00
">>" : true ,
">>>" : true ,
"<<" : true
} ;
function shouldFlatten ( parentOp , nodeOp ) {
if ( getPrecedence ( nodeOp ) !== getPrecedence ( parentOp ) ) {
return false ;
} // ** is right-associative
// x ** y ** z --> x ** (y ** z)
if ( parentOp === "**" ) {
return false ;
} // x == y == z --> (x == y) == z
if ( equalityOperators [ parentOp ] && equalityOperators [ nodeOp ] ) {
return false ;
} // x * y % z --> (x * y) % z
if ( nodeOp === "%" && multiplicativeOperators [ parentOp ] || parentOp === "%" && multiplicativeOperators [ nodeOp ] ) {
return false ;
} // x * y / z --> (x * y) / z
// x / y * z --> (x / y) * z
if ( nodeOp !== parentOp && multiplicativeOperators [ nodeOp ] && multiplicativeOperators [ parentOp ] ) {
return false ;
} // x << y << z --> (x << y) << z
if ( bitshiftOperators [ parentOp ] && bitshiftOperators [ nodeOp ] ) {
return false ;
}
return true ;
}
function isBitwiseOperator ( operator ) {
return ! ! bitshiftOperators [ operator ] || operator === "|" || operator === "^" || operator === "&" ;
} // Tests if an expression starts with `{`, or (if forbidFunctionClassAndDoExpr
// holds) `function`, `class`, or `do {}`. Will be overzealous if there's
// already necessary grouping parentheses.
function startsWithNoLookaheadToken ( node , forbidFunctionClassAndDoExpr ) {
node = getLeftMost ( node ) ;
switch ( node . type ) {
case "FunctionExpression" :
case "ClassExpression" :
case "DoExpression" :
return forbidFunctionClassAndDoExpr ;
case "ObjectExpression" :
return true ;
case "MemberExpression" :
case "OptionalMemberExpression" :
return startsWithNoLookaheadToken ( node . object , forbidFunctionClassAndDoExpr ) ;
case "TaggedTemplateExpression" :
if ( node . tag . type === "FunctionExpression" ) {
// IIFEs are always already parenthesized
return false ;
}
return startsWithNoLookaheadToken ( node . tag , forbidFunctionClassAndDoExpr ) ;
case "CallExpression" :
case "OptionalCallExpression" :
if ( node . callee . type === "FunctionExpression" ) {
// IIFEs are always already parenthesized
return false ;
}
return startsWithNoLookaheadToken ( node . callee , forbidFunctionClassAndDoExpr ) ;
case "ConditionalExpression" :
return startsWithNoLookaheadToken ( node . test , forbidFunctionClassAndDoExpr ) ;
case "UpdateExpression" :
return ! node . prefix && startsWithNoLookaheadToken ( node . argument , forbidFunctionClassAndDoExpr ) ;
case "BindExpression" :
return node . object && startsWithNoLookaheadToken ( node . object , forbidFunctionClassAndDoExpr ) ;
case "SequenceExpression" :
return startsWithNoLookaheadToken ( node . expressions [ 0 ] , forbidFunctionClassAndDoExpr ) ;
case "TSAsExpression" :
return startsWithNoLookaheadToken ( node . expression , forbidFunctionClassAndDoExpr ) ;
default :
return false ;
}
}
function getLeftMost ( node ) {
if ( node . left ) {
return getLeftMost ( node . left ) ;
}
return node ;
}
/ * *
* @ param { string } value
* @ param { number } tabWidth
* @ param { number = } startIndex
* @ returns { number }
* /
function getAlignmentSize ( value , tabWidth , startIndex ) {
startIndex = startIndex || 0 ;
2020-03-31 20:40:00 +08:00
let size = 0 ;
2020-01-28 13:07:56 +08:00
2020-03-31 20:40:00 +08:00
for ( let i = startIndex ; i < value . length ; ++ i ) {
2020-01-28 13:07:56 +08:00
if ( value [ i ] === "\t" ) {
// Tabs behave in a way that they are aligned to the nearest
// multiple of tabWidth:
// 0 -> 4, 1 -> 4, 2 -> 4, 3 -> 4
// 4 -> 8, 5 -> 8, 6 -> 8, 7 -> 8 ...
size = size + tabWidth - size % tabWidth ;
} else {
size ++ ;
}
}
return size ;
}
/ * *
* @ param { string } value
* @ param { number } tabWidth
* @ returns { number }
* /
function getIndentSize ( value , tabWidth ) {
2020-03-31 20:40:00 +08:00
const lastNewlineIndex = value . lastIndexOf ( "\n" ) ;
2020-01-28 13:07:56 +08:00
if ( lastNewlineIndex === - 1 ) {
return 0 ;
}
return getAlignmentSize ( // All the leading whitespaces
value . slice ( lastNewlineIndex + 1 ) . match ( /^[ \t]*/ ) [ 0 ] , tabWidth ) ;
}
/ * *
* @ typedef { '"' | "'" } Quote
* /
/ * *
*
* @ param { string } raw
* @ param { Quote } preferredQuote
* @ returns { Quote }
* /
function getPreferredQuote ( raw , preferredQuote ) {
// `rawContent` is the string exactly like it appeared in the input source
// code, without its enclosing quotes.
2020-03-31 20:40:00 +08:00
const rawContent = raw . slice ( 1 , - 1 ) ;
2020-01-28 13:07:56 +08:00
/** @type {{ quote: '"', regex: RegExp }} */
2020-03-31 20:40:00 +08:00
const double = {
2020-01-28 13:07:56 +08:00
quote : '"' ,
regex : /"/g
} ;
/** @type {{ quote: "'", regex: RegExp }} */
2020-03-31 20:40:00 +08:00
const single = {
2020-01-28 13:07:56 +08:00
quote : "'" ,
regex : /'/g
} ;
2020-03-31 20:40:00 +08:00
const preferred = preferredQuote === "'" ? single : double ;
const alternate = preferred === single ? double : single ;
let result = preferred . quote ; // If `rawContent` contains at least one of the quote preferred for enclosing
2020-01-28 13:07:56 +08:00
// the string, we might want to enclose with the alternate quote instead, to
// minimize the number of escaped quotes.
if ( rawContent . includes ( preferred . quote ) || rawContent . includes ( alternate . quote ) ) {
2020-03-31 20:40:00 +08:00
const numPreferredQuotes = ( rawContent . match ( preferred . regex ) || [ ] ) . length ;
const numAlternateQuotes = ( rawContent . match ( alternate . regex ) || [ ] ) . length ;
2020-01-28 13:07:56 +08:00
result = numPreferredQuotes > numAlternateQuotes ? alternate . quote : preferred . quote ;
}
return result ;
}
function printString ( raw , options , isDirectiveLiteral ) {
// `rawContent` is the string exactly like it appeared in the input source
// code, without its enclosing quotes.
2020-03-31 20:40:00 +08:00
const rawContent = raw . slice ( 1 , - 1 ) ; // Check for the alternate quote, to determine if we're allowed to swap
2020-01-28 13:07:56 +08:00
// the quotes on a DirectiveLiteral.
2020-03-31 20:40:00 +08:00
const canChangeDirectiveQuotes = ! rawContent . includes ( '"' ) && ! rawContent . includes ( "'" ) ;
2020-01-28 13:07:56 +08:00
/** @type {Quote} */
2020-03-31 20:40:00 +08:00
const enclosingQuote = options . parser === "json" ? '"' : options . _ _isInHtmlAttribute ? "'" : getPreferredQuote ( raw , options . singleQuote ? "'" : '"' ) ; // Directives are exact code unit sequences, which means that you can't
2020-01-28 13:07:56 +08:00
// change the escape sequences they use.
// See https://github.com/prettier/prettier/issues/1555
// and https://tc39.github.io/ecma262/#directive-prologue
if ( isDirectiveLiteral ) {
if ( canChangeDirectiveQuotes ) {
return enclosingQuote + rawContent + enclosingQuote ;
}
return raw ;
} // It might sound unnecessary to use `makeString` even if the string already
// is enclosed with `enclosingQuote`, but it isn't. The string could contain
// unnecessary escapes (such as in `"\'"`). Always using `makeString` makes
// sure that we consistently output the minimum amount of escaped quotes.
return makeString ( rawContent , enclosingQuote , ! ( options . parser === "css" || options . parser === "less" || options . parser === "scss" || options . embeddedInHtml ) ) ;
}
/ * *
* @ param { string } rawContent
* @ param { Quote } enclosingQuote
* @ param { boolean = } unescapeUnnecessaryEscapes
* @ returns { string }
* /
function makeString ( rawContent , enclosingQuote , unescapeUnnecessaryEscapes ) {
2020-03-31 20:40:00 +08:00
const otherQuote = enclosingQuote === '"' ? "'" : '"' ; // Matches _any_ escape and unescaped quotes (both single and double).
2020-01-28 13:07:56 +08:00
2020-03-31 20:40:00 +08:00
const regex = /\\([\s\S])|(['"])/g ; // Escape and unescape single and double quotes as needed to be able to
2020-01-28 13:07:56 +08:00
// enclose `rawContent` with `enclosingQuote`.
2020-03-31 20:40:00 +08:00
const newContent = rawContent . replace ( regex , ( match , escaped , quote ) => {
2020-01-28 13:07:56 +08:00
// If we matched an escape, and the escaped character is a quote of the
// other type than we intend to enclose the string with, there's no need for
// it to be escaped, so return it _without_ the backslash.
if ( escaped === otherQuote ) {
return escaped ;
} // If we matched an unescaped quote and it is of the _same_ type as we
// intend to enclose the string with, it must be escaped, so return it with
// a backslash.
if ( quote === enclosingQuote ) {
return "\\" + quote ;
}
if ( quote ) {
return quote ;
} // Unescape any unnecessarily escaped character.
// Adapted from https://github.com/eslint/eslint/blob/de0b4ad7bd820ade41b1f606008bea68683dc11a/lib/rules/no-useless-escape.js#L27
return unescapeUnnecessaryEscapes && /^[^\\nrvtbfux\r\n\u2028\u2029"'0-7]$/ . test ( escaped ) ? escaped : "\\" + escaped ;
} ) ;
return enclosingQuote + newContent + enclosingQuote ;
}
function printNumber ( rawNumber ) {
return rawNumber . toLowerCase ( ) // Remove unnecessary plus and zeroes from scientific notation.
. replace ( /^([+-]?[\d.]+e)(?:\+|(-))?0*(\d)/ , "$1$2$3" ) // Remove unnecessary scientific notation (1e0).
. replace ( /^([+-]?[\d.]+)e[+-]?0+$/ , "$1" ) // Make sure numbers always start with a digit.
. replace ( /^([+-])?\./ , "$10." ) // Remove extraneous trailing decimal zeroes.
. replace ( /(\.\d+?)0+(?=e|$)/ , "$1" ) // Remove trailing dot.
. replace ( /\.(?=e|$)/ , "" ) ;
}
/ * *
* @ param { string } str
* @ param { string } target
* @ returns { number }
* /
function getMaxContinuousCount ( str , target ) {
2020-03-31 20:40:00 +08:00
const results = str . match ( new RegExp ( "(" . concat ( escapeStringRegexp ( target ) , ")+" ) , "g" ) ) ;
2020-01-28 13:07:56 +08:00
if ( results === null ) {
return 0 ;
}
2020-03-31 20:40:00 +08:00
return results . reduce ( ( maxCount , result ) => Math . max ( maxCount , result . length / target . length ) , 0 ) ;
2020-01-28 13:07:56 +08:00
}
function getMinNotPresentContinuousCount ( str , target ) {
2020-03-31 20:40:00 +08:00
const matches = str . match ( new RegExp ( "(" . concat ( escapeStringRegexp ( target ) , ")+" ) , "g" ) ) ;
2020-01-28 13:07:56 +08:00
if ( matches === null ) {
return 0 ;
}
2020-03-31 20:40:00 +08:00
const countPresent = new Map ( ) ;
let max = 0 ;
2020-01-28 13:07:56 +08:00
2020-03-31 20:40:00 +08:00
for ( const match of matches ) {
const count = match . length / target . length ;
countPresent . set ( count , true ) ;
2020-01-28 13:07:56 +08:00
2020-03-31 20:40:00 +08:00
if ( count > max ) {
max = count ;
2020-01-28 13:07:56 +08:00
}
}
2020-03-31 20:40:00 +08:00
for ( let i = 1 ; i < max ; i ++ ) {
2020-01-28 13:07:56 +08:00
if ( ! countPresent . get ( i ) ) {
return i ;
}
}
return max + 1 ;
}
/ * *
* @ param { string } text
* @ returns { number }
* /
function getStringWidth ( text ) {
if ( ! text ) {
return 0 ;
} // shortcut to avoid needless string `RegExp`s, replacements, and allocations within `string-width`
if ( ! notAsciiRegex . test ( text ) ) {
return text . length ;
}
return stringWidth _1 ( text ) ;
}
function hasIgnoreComment ( path ) {
2020-03-31 20:40:00 +08:00
const node = path . getValue ( ) ;
2020-01-28 13:07:56 +08:00
return hasNodeIgnoreComment ( node ) ;
}
function hasNodeIgnoreComment ( node ) {
2020-03-31 20:40:00 +08:00
return node && ( node . comments && node . comments . length > 0 && node . comments . some ( comment => isNodeIgnoreComment ( comment ) && ! comment . unignore ) || node . prettierIgnore ) ;
2020-01-28 13:07:56 +08:00
}
2020-03-31 20:40:00 +08:00
function isNodeIgnoreComment ( comment ) {
return comment . value . trim ( ) === "prettier-ignore" ;
2020-01-28 13:07:56 +08:00
}
function addCommentHelper ( node , comment ) {
2020-03-31 20:40:00 +08:00
const comments = node . comments || ( node . comments = [ ] ) ;
2020-01-28 13:07:56 +08:00
comments . push ( comment ) ;
comment . printed = false ; // For some reason, TypeScript parses `// x` inside of JSXText as a comment
// We already "print" it via the raw text, we don't need to re-print it as a
// comment
if ( node . type === "JSXText" ) {
comment . printed = true ;
}
}
function addLeadingComment ( node , comment ) {
comment . leading = true ;
comment . trailing = false ;
addCommentHelper ( node , comment ) ;
}
function addDanglingComment ( node , comment ) {
comment . leading = false ;
comment . trailing = false ;
addCommentHelper ( node , comment ) ;
}
function addTrailingComment ( node , comment ) {
comment . leading = false ;
comment . trailing = true ;
addCommentHelper ( node , comment ) ;
}
function isWithinParentArrayProperty ( path , propertyName ) {
2020-03-31 20:40:00 +08:00
const node = path . getValue ( ) ;
const parent = path . getParentNode ( ) ;
2020-01-28 13:07:56 +08:00
if ( parent == null ) {
return false ;
}
if ( ! Array . isArray ( parent [ propertyName ] ) ) {
return false ;
}
2020-03-31 20:40:00 +08:00
const key = path . getName ( ) ;
2020-01-28 13:07:56 +08:00
return parent [ propertyName ] [ key ] === node ;
}
function replaceEndOfLineWith ( text , replacement ) {
2020-03-31 20:40:00 +08:00
const parts = [ ] ;
2020-01-28 13:07:56 +08:00
2020-03-31 20:40:00 +08:00
for ( const part of text . split ( "\n" ) ) {
if ( parts . length !== 0 ) {
parts . push ( replacement ) ;
2020-01-28 13:07:56 +08:00
}
2020-03-31 20:40:00 +08:00
parts . push ( part ) ;
2020-01-28 13:07:56 +08:00
}
return parts ;
}
var util = {
2020-03-31 20:40:00 +08:00
replaceEndOfLineWith ,
getStringWidth ,
getMaxContinuousCount ,
getMinNotPresentContinuousCount ,
getPrecedence ,
shouldFlatten ,
isBitwiseOperator ,
getPenultimate ,
getLast ,
getNextNonSpaceNonCommentCharacterIndexWithStartIndex ,
getNextNonSpaceNonCommentCharacterIndex ,
getNextNonSpaceNonCommentCharacter ,
skip ,
skipWhitespace ,
skipSpaces ,
skipToLineEnd ,
skipEverythingButNewLine ,
skipInlineComment ,
skipTrailingComment ,
skipNewline ,
isNextLineEmptyAfterIndex ,
isNextLineEmpty ,
isPreviousLineEmpty ,
hasNewline ,
hasNewlineInRange ,
hasSpaces ,
setLocStart ,
setLocEnd ,
startsWithNoLookaheadToken ,
getAlignmentSize ,
getIndentSize ,
getPreferredQuote ,
printString ,
printNumber ,
hasIgnoreComment ,
hasNodeIgnoreComment ,
isNodeIgnoreComment ,
makeString ,
addLeadingComment ,
addDanglingComment ,
addTrailingComment ,
isWithinParentArrayProperty
2020-01-28 13:07:56 +08:00
} ;
function guessEndOfLine ( text ) {
2020-03-31 20:40:00 +08:00
const index = text . indexOf ( "\r" ) ;
2020-01-28 13:07:56 +08:00
if ( index >= 0 ) {
return text . charAt ( index + 1 ) === "\n" ? "crlf" : "cr" ;
}
return "lf" ;
}
function convertEndOfLineToChars ( value ) {
switch ( value ) {
case "cr" :
return "\r" ;
case "crlf" :
return "\r\n" ;
default :
return "\n" ;
}
}
var endOfLine = {
2020-03-31 20:40:00 +08:00
guessEndOfLine ,
convertEndOfLineToChars
2020-01-28 13:07:56 +08:00
} ;
2020-03-31 20:40:00 +08:00
const {
getStringWidth : getStringWidth$1
} = util ;
const {
convertEndOfLineToChars : convertEndOfLineToChars$1
} = endOfLine ;
const {
concat : concat$1 ,
fill : fill$1 ,
cursor : cursor$1
} = docBuilders ;
2020-01-28 13:07:56 +08:00
/** @type {Record<symbol, typeof MODE_BREAK | typeof MODE_FLAT>} */
2020-03-31 20:40:00 +08:00
let groupModeMap ;
const MODE _BREAK = 1 ;
const MODE _FLAT = 2 ;
2020-01-28 13:07:56 +08:00
function rootIndent ( ) {
return {
value : "" ,
length : 0 ,
queue : [ ]
} ;
}
function makeIndent ( ind , options ) {
return generateInd ( ind , {
type : "indent"
} , options ) ;
}
function makeAlign ( ind , n , options ) {
return n === - Infinity ? 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" ,
2020-03-31 20:40:00 +08:00
n
2020-01-28 13:07:56 +08:00
} , options ) : generateInd ( ind , {
type : "numberAlign" ,
2020-03-31 20:40:00 +08:00
n
2020-01-28 13:07:56 +08:00
} , options ) ;
}
function generateInd ( ind , newPart , options ) {
2020-03-31 20:40:00 +08:00
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 ) ;
}
2020-01-28 13:07:56 +08:00
2020-03-31 20:40:00 +08:00
break ;
2020-01-28 13:07:56 +08:00
2020-03-31 20:40:00 +08:00
case "stringAlign" :
flush ( ) ;
value += part . n ;
length += part . n . length ;
break ;
2020-01-28 13:07:56 +08:00
2020-03-31 20:40:00 +08:00
case "numberAlign" :
lastTabs += 1 ;
lastSpaces += part . n ;
break ;
2020-01-28 13:07:56 +08:00
2020-03-31 20:40:00 +08:00
/* istanbul ignore next */
2020-01-28 13:07:56 +08:00
2020-03-31 20:40:00 +08:00
default :
throw new Error ( "Unexpected type '" . concat ( part . type , "'" ) ) ;
2020-01-28 13:07:56 +08:00
}
}
flushSpaces ( ) ;
return Object . assign ( { } , ind , {
2020-03-31 20:40:00 +08:00
value ,
length ,
queue
2020-01-28 13:07:56 +08:00
} ) ;
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 trim$1 ( out ) {
if ( out . length === 0 ) {
return 0 ;
}
2020-03-31 20:40:00 +08:00
let trimCount = 0 ; // Trim whitespace at the end of line
2020-01-28 13:07:56 +08:00
while ( out . length > 0 && typeof out [ out . length - 1 ] === "string" && out [ out . length - 1 ] . match ( /^[ \t]*$/ ) ) {
trimCount += out . pop ( ) . length ;
}
if ( out . length && typeof out [ out . length - 1 ] === "string" ) {
2020-03-31 20:40:00 +08:00
const trimmed = out [ out . length - 1 ] . replace ( /[ \t]*$/ , "" ) ;
2020-01-28 13:07:56 +08:00
trimCount += out [ out . length - 1 ] . length - trimmed . length ;
out [ out . length - 1 ] = trimmed ;
}
return trimCount ;
}
function fits ( next , restCommands , width , options , mustBeFlat ) {
2020-03-31 20:40:00 +08:00
let restIdx = restCommands . length ;
const cmds = [ next ] ; // `out` is only used for width counting because `trim` requires to look
2020-01-28 13:07:56 +08:00
// backwards for space characters.
2020-03-31 20:40:00 +08:00
const out = [ ] ;
2020-01-28 13:07:56 +08:00
while ( width >= 0 ) {
if ( cmds . length === 0 ) {
if ( restIdx === 0 ) {
return true ;
}
cmds . push ( restCommands [ restIdx - 1 ] ) ;
restIdx -- ;
continue ;
}
2020-03-31 20:40:00 +08:00
const [ ind , mode , doc ] = cmds . pop ( ) ;
2020-01-28 13:07:56 +08:00
if ( typeof doc === "string" ) {
out . push ( doc ) ;
width -= getStringWidth$1 ( doc ) ;
} else {
switch ( doc . type ) {
case "concat" :
2020-03-31 20:40:00 +08:00
for ( let i = doc . parts . length - 1 ; i >= 0 ; i -- ) {
2020-01-28 13:07:56 +08:00
cmds . push ( [ ind , mode , doc . parts [ i ] ] ) ;
}
break ;
case "indent" :
cmds . push ( [ makeIndent ( ind , options ) , mode , doc . contents ] ) ;
break ;
case "align" :
cmds . push ( [ makeAlign ( ind , doc . n , options ) , mode , doc . contents ] ) ;
break ;
case "trim" :
width += trim$1 ( out ) ;
break ;
case "group" :
if ( mustBeFlat && doc . break ) {
return false ;
}
cmds . push ( [ ind , doc . break ? MODE _BREAK : mode , doc . contents ] ) ;
if ( doc . id ) {
groupModeMap [ doc . id ] = cmds [ cmds . length - 1 ] [ 1 ] ;
}
break ;
case "fill" :
2020-03-31 20:40:00 +08:00
for ( let i = doc . parts . length - 1 ; i >= 0 ; i -- ) {
cmds . push ( [ ind , mode , doc . parts [ i ] ] ) ;
2020-01-28 13:07:56 +08:00
}
break ;
case "if-break" :
{
2020-03-31 20:40:00 +08:00
const groupMode = doc . groupId ? groupModeMap [ doc . groupId ] : mode ;
2020-01-28 13:07:56 +08:00
if ( groupMode === MODE _BREAK ) {
if ( doc . breakContents ) {
cmds . push ( [ ind , mode , doc . breakContents ] ) ;
}
}
if ( groupMode === MODE _FLAT ) {
if ( doc . flatContents ) {
cmds . push ( [ ind , mode , doc . flatContents ] ) ;
}
}
break ;
}
case "line" :
switch ( mode ) {
// fallthrough
case MODE _FLAT :
if ( ! doc . hard ) {
if ( ! doc . soft ) {
out . push ( " " ) ;
width -= 1 ;
}
break ;
}
return true ;
case MODE _BREAK :
return true ;
}
break ;
}
}
}
return false ;
}
function printDocToString ( doc , options ) {
groupModeMap = { } ;
2020-03-31 20:40:00 +08:00
const width = options . printWidth ;
const newLine = convertEndOfLineToChars$1 ( options . endOfLine ) ;
let pos = 0 ; // cmds is basically a stack. We've turned a recursive call into a
2020-01-28 13:07:56 +08:00
// while loop which is much faster. The while loop below adds new
// cmds to the array instead of recursively calling `print`.
2020-03-31 20:40:00 +08:00
const cmds = [ [ rootIndent ( ) , MODE _BREAK , doc ] ] ;
const out = [ ] ;
let shouldRemeasure = false ;
let lineSuffix = [ ] ;
2020-01-28 13:07:56 +08:00
while ( cmds . length !== 0 ) {
2020-03-31 20:40:00 +08:00
const [ ind , mode , doc ] = cmds . pop ( ) ;
if ( typeof doc === "string" ) {
2020-04-30 20:40:07 +08:00
const formatted = newLine !== "\n" && doc . includes ( "\n" ) ? doc . replace ( /\n/g , newLine ) : doc ;
out . push ( formatted ) ;
pos += getStringWidth$1 ( formatted ) ;
2020-01-28 13:07:56 +08:00
} else {
2020-03-31 20:40:00 +08:00
switch ( doc . type ) {
2020-01-28 13:07:56 +08:00
case "cursor" :
out . push ( cursor$1 . placeholder ) ;
break ;
case "concat" :
2020-03-31 20:40:00 +08:00
for ( let i = doc . parts . length - 1 ; i >= 0 ; i -- ) {
cmds . push ( [ ind , mode , doc . parts [ i ] ] ) ;
2020-01-28 13:07:56 +08:00
}
break ;
case "indent" :
2020-03-31 20:40:00 +08:00
cmds . push ( [ makeIndent ( ind , options ) , mode , doc . contents ] ) ;
2020-01-28 13:07:56 +08:00
break ;
case "align" :
2020-03-31 20:40:00 +08:00
cmds . push ( [ makeAlign ( ind , doc . n , options ) , mode , doc . contents ] ) ;
2020-01-28 13:07:56 +08:00
break ;
case "trim" :
pos -= trim$1 ( out ) ;
break ;
case "group" :
switch ( mode ) {
case MODE _FLAT :
if ( ! shouldRemeasure ) {
2020-03-31 20:40:00 +08:00
cmds . push ( [ ind , doc . break ? MODE _BREAK : MODE _FLAT , doc . contents ] ) ;
2020-01-28 13:07:56 +08:00
break ;
}
// fallthrough
case MODE _BREAK :
{
shouldRemeasure = false ;
2020-03-31 20:40:00 +08:00
const next = [ ind , MODE _FLAT , doc . contents ] ;
const rem = width - pos ;
2020-01-28 13:07:56 +08:00
2020-03-31 20:40:00 +08:00
if ( ! doc . break && fits ( next , cmds , rem , options ) ) {
2020-01-28 13:07:56 +08:00
cmds . push ( next ) ;
} else {
// Expanded states are a rare case where a document
// can manually provide multiple representations of
// itself. It provides an array of documents
// going from the least expanded (most flattened)
// representation first to the most expanded. If a
// group has these, we need to manually go through
// these states and find the first one that fits.
2020-03-31 20:40:00 +08:00
if ( doc . expandedStates ) {
const mostExpanded = doc . expandedStates [ doc . expandedStates . length - 1 ] ;
2020-01-28 13:07:56 +08:00
2020-03-31 20:40:00 +08:00
if ( doc . break ) {
2020-01-28 13:07:56 +08:00
cmds . push ( [ ind , MODE _BREAK , mostExpanded ] ) ;
break ;
} else {
2020-03-31 20:40:00 +08:00
for ( let i = 1 ; i < doc . expandedStates . length + 1 ; i ++ ) {
if ( i >= doc . expandedStates . length ) {
2020-01-28 13:07:56 +08:00
cmds . push ( [ ind , MODE _BREAK , mostExpanded ] ) ;
break ;
} else {
2020-03-31 20:40:00 +08:00
const state = doc . expandedStates [ i ] ;
const cmd = [ ind , MODE _FLAT , state ] ;
2020-01-28 13:07:56 +08:00
if ( fits ( cmd , cmds , rem , options ) ) {
cmds . push ( cmd ) ;
break ;
}
}
}
}
} else {
2020-03-31 20:40:00 +08:00
cmds . push ( [ ind , MODE _BREAK , doc . contents ] ) ;
2020-01-28 13:07:56 +08:00
}
}
break ;
}
}
2020-03-31 20:40:00 +08:00
if ( doc . id ) {
groupModeMap [ doc . id ] = cmds [ cmds . length - 1 ] [ 1 ] ;
2020-01-28 13:07:56 +08:00
}
break ;
// Fills each line with as much code as possible before moving to a new
// line with the same indentation.
//
// Expects doc.parts to be an array of alternating content and
// whitespace. The whitespace contains the linebreaks.
//
// For example:
// ["I", line, "love", line, "monkeys"]
// or
// [{ type: group, ... }, softline, { type: group, ... }]
//
// It uses this parts structure to handle three main layout cases:
// * The first two content items fit on the same line without
// breaking
// -> output the first content item and the whitespace "flat".
// * Only the first content item fits on the line without breaking
// -> output the first content item "flat" and the whitespace with
// "break".
// * Neither content item fits on the line without breaking
// -> output the first content item and the whitespace with "break".
case "fill" :
{
2020-03-31 20:40:00 +08:00
const rem = width - pos ;
const {
parts
} = doc ;
2020-01-28 13:07:56 +08:00
if ( parts . length === 0 ) {
break ;
}
2020-03-31 20:40:00 +08:00
const [ content , whitespace ] = parts ;
const contentFlatCmd = [ ind , MODE _FLAT , content ] ;
const contentBreakCmd = [ ind , MODE _BREAK , content ] ;
const contentFits = fits ( contentFlatCmd , [ ] , rem , options , true ) ;
2020-01-28 13:07:56 +08:00
if ( parts . length === 1 ) {
if ( contentFits ) {
cmds . push ( contentFlatCmd ) ;
} else {
cmds . push ( contentBreakCmd ) ;
}
break ;
}
2020-03-31 20:40:00 +08:00
const whitespaceFlatCmd = [ ind , MODE _FLAT , whitespace ] ;
const whitespaceBreakCmd = [ ind , MODE _BREAK , whitespace ] ;
2020-01-28 13:07:56 +08:00
if ( parts . length === 2 ) {
if ( contentFits ) {
cmds . push ( whitespaceFlatCmd ) ;
cmds . push ( contentFlatCmd ) ;
} else {
cmds . push ( whitespaceBreakCmd ) ;
cmds . push ( contentBreakCmd ) ;
}
break ;
} // At this point we've handled the first pair (context, separator)
// and will create a new fill doc for the rest of the content.
2020-03-31 20:40:00 +08:00
// Ideally we wouldn't mutate the array here but copying all the
2020-01-28 13:07:56 +08:00
// elements to a new array would make this algorithm quadratic,
// which is unusable for large arrays (e.g. large texts in JSX).
parts . splice ( 0 , 2 ) ;
2020-03-31 20:40:00 +08:00
const remainingCmd = [ ind , mode , fill$1 ( parts ) ] ;
const secondContent = parts [ 0 ] ;
const firstAndSecondContentFlatCmd = [ ind , MODE _FLAT , concat$1 ( [ content , whitespace , secondContent ] ) ] ;
const firstAndSecondContentFits = fits ( firstAndSecondContentFlatCmd , [ ] , rem , options , true ) ;
2020-01-28 13:07:56 +08:00
if ( firstAndSecondContentFits ) {
cmds . push ( remainingCmd ) ;
cmds . push ( whitespaceFlatCmd ) ;
cmds . push ( contentFlatCmd ) ;
} else if ( contentFits ) {
cmds . push ( remainingCmd ) ;
cmds . push ( whitespaceBreakCmd ) ;
cmds . push ( contentFlatCmd ) ;
} else {
cmds . push ( remainingCmd ) ;
cmds . push ( whitespaceBreakCmd ) ;
cmds . push ( contentBreakCmd ) ;
}
break ;
}
case "if-break" :
{
2020-03-31 20:40:00 +08:00
const groupMode = doc . groupId ? groupModeMap [ doc . groupId ] : mode ;
2020-01-28 13:07:56 +08:00
if ( groupMode === MODE _BREAK ) {
2020-03-31 20:40:00 +08:00
if ( doc . breakContents ) {
cmds . push ( [ ind , mode , doc . breakContents ] ) ;
2020-01-28 13:07:56 +08:00
}
}
if ( groupMode === MODE _FLAT ) {
2020-03-31 20:40:00 +08:00
if ( doc . flatContents ) {
cmds . push ( [ ind , mode , doc . flatContents ] ) ;
2020-01-28 13:07:56 +08:00
}
}
break ;
}
case "line-suffix" :
2020-03-31 20:40:00 +08:00
lineSuffix . push ( [ ind , mode , doc . contents ] ) ;
2020-01-28 13:07:56 +08:00
break ;
case "line-suffix-boundary" :
if ( lineSuffix . length > 0 ) {
cmds . push ( [ ind , mode , {
type : "line" ,
hard : true
} ] ) ;
}
break ;
case "line" :
switch ( mode ) {
case MODE _FLAT :
2020-03-31 20:40:00 +08:00
if ( ! doc . hard ) {
if ( ! doc . soft ) {
2020-01-28 13:07:56 +08:00
out . push ( " " ) ;
pos += 1 ;
}
break ;
} else {
// This line was forced into the output even if we
// were in flattened mode, so we need to tell the next
// group that no matter what, it needs to remeasure
// because the previous measurement didn't accurately
// capture the entire expression (this is necessary
// for nested groups)
shouldRemeasure = true ;
}
// fallthrough
case MODE _BREAK :
if ( lineSuffix . length ) {
2020-03-31 20:40:00 +08:00
cmds . push ( [ ind , mode , doc ] ) ;
cmds . push ( ... lineSuffix . reverse ( ) ) ;
2020-01-28 13:07:56 +08:00
lineSuffix = [ ] ;
break ;
}
2020-03-31 20:40:00 +08:00
if ( doc . literal ) {
2020-01-28 13:07:56 +08:00
if ( ind . root ) {
out . push ( newLine , ind . root . value ) ;
pos = ind . root . length ;
} else {
out . push ( newLine ) ;
pos = 0 ;
}
} else {
pos -= trim$1 ( out ) ;
out . push ( newLine + ind . value ) ;
pos = ind . length ;
}
break ;
}
break ;
}
}
}
2020-03-31 20:40:00 +08:00
const cursorPlaceholderIndex = out . indexOf ( cursor$1 . placeholder ) ;
2020-01-28 13:07:56 +08:00
if ( cursorPlaceholderIndex !== - 1 ) {
2020-03-31 20:40:00 +08:00
const otherCursorPlaceholderIndex = out . indexOf ( cursor$1 . placeholder , cursorPlaceholderIndex + 1 ) ;
const beforeCursor = out . slice ( 0 , cursorPlaceholderIndex ) . join ( "" ) ;
const aroundCursor = out . slice ( cursorPlaceholderIndex + 1 , otherCursorPlaceholderIndex ) . join ( "" ) ;
const afterCursor = out . slice ( otherCursorPlaceholderIndex + 1 ) . join ( "" ) ;
2020-01-28 13:07:56 +08:00
return {
formatted : beforeCursor + aroundCursor + afterCursor ,
cursorNodeStart : beforeCursor . length ,
cursorNodeText : aroundCursor
} ;
}
return {
formatted : out . join ( "" )
} ;
}
var docPrinter = {
2020-03-31 20:40:00 +08:00
printDocToString
2020-01-28 13:07:56 +08:00
} ;
2020-03-31 20:40:00 +08:00
const traverseDocOnExitStackMarker = { } ;
2020-01-28 13:07:56 +08:00
function traverseDoc ( doc , onEnter , onExit , shouldTraverseConditionalGroups ) {
2020-03-31 20:40:00 +08:00
const docsStack = [ doc ] ;
2020-01-28 13:07:56 +08:00
while ( docsStack . length !== 0 ) {
2020-03-31 20:40:00 +08:00
const doc = docsStack . pop ( ) ;
2020-01-28 13:07:56 +08:00
2020-03-31 20:40:00 +08:00
if ( doc === traverseDocOnExitStackMarker ) {
2020-01-28 13:07:56 +08:00
onExit ( docsStack . pop ( ) ) ;
continue ;
}
2020-03-31 20:40:00 +08:00
let shouldRecurse = true ;
2020-01-28 13:07:56 +08:00
if ( onEnter ) {
2020-03-31 20:40:00 +08:00
if ( onEnter ( doc ) === false ) {
2020-01-28 13:07:56 +08:00
shouldRecurse = false ;
}
}
if ( onExit ) {
2020-03-31 20:40:00 +08:00
docsStack . push ( doc ) ;
2020-01-28 13:07:56 +08:00
docsStack . push ( traverseDocOnExitStackMarker ) ;
}
if ( shouldRecurse ) {
// When there are multiple parts to process,
// the parts need to be pushed onto the stack in reverse order,
// so that they are processed in the original order
// when the stack is popped.
2020-03-31 20:40:00 +08:00
if ( doc . type === "concat" || doc . type === "fill" ) {
for ( let ic = doc . parts . length , i = ic - 1 ; i >= 0 ; -- i ) {
docsStack . push ( doc . parts [ i ] ) ;
2020-01-28 13:07:56 +08:00
}
2020-03-31 20:40:00 +08:00
} else if ( doc . type === "if-break" ) {
if ( doc . flatContents ) {
docsStack . push ( doc . flatContents ) ;
2020-01-28 13:07:56 +08:00
}
2020-03-31 20:40:00 +08:00
if ( doc . breakContents ) {
docsStack . push ( doc . breakContents ) ;
2020-01-28 13:07:56 +08:00
}
2020-03-31 20:40:00 +08:00
} else if ( doc . type === "group" && doc . expandedStates ) {
2020-01-28 13:07:56 +08:00
if ( shouldTraverseConditionalGroups ) {
2020-03-31 20:40:00 +08:00
for ( let ic = doc . expandedStates . length , i = ic - 1 ; i >= 0 ; -- i ) {
docsStack . push ( doc . expandedStates [ i ] ) ;
2020-01-28 13:07:56 +08:00
}
} else {
2020-03-31 20:40:00 +08:00
docsStack . push ( doc . contents ) ;
2020-01-28 13:07:56 +08:00
}
2020-03-31 20:40:00 +08:00
} else if ( doc . contents ) {
docsStack . push ( doc . contents ) ;
2020-01-28 13:07:56 +08:00
}
}
}
}
function mapDoc ( doc , cb ) {
if ( doc . type === "concat" || doc . type === "fill" ) {
2020-03-31 20:40:00 +08:00
const parts = doc . parts . map ( part => mapDoc ( part , cb ) ) ;
2020-01-28 13:07:56 +08:00
return cb ( Object . assign ( { } , doc , {
2020-03-31 20:40:00 +08:00
parts
2020-01-28 13:07:56 +08:00
} ) ) ;
} else if ( doc . type === "if-break" ) {
2020-03-31 20:40:00 +08:00
const breakContents = doc . breakContents && mapDoc ( doc . breakContents , cb ) ;
const flatContents = doc . flatContents && mapDoc ( doc . flatContents , cb ) ;
2020-01-28 13:07:56 +08:00
return cb ( Object . assign ( { } , doc , {
2020-03-31 20:40:00 +08:00
breakContents ,
flatContents
2020-01-28 13:07:56 +08:00
} ) ) ;
} else if ( doc . contents ) {
2020-03-31 20:40:00 +08:00
const contents = mapDoc ( doc . contents , cb ) ;
2020-01-28 13:07:56 +08:00
return cb ( Object . assign ( { } , doc , {
2020-03-31 20:40:00 +08:00
contents
2020-01-28 13:07:56 +08:00
} ) ) ;
}
return cb ( doc ) ;
}
function findInDoc ( doc , fn , defaultValue ) {
2020-03-31 20:40:00 +08:00
let result = defaultValue ;
let hasStopped = false ;
2020-01-28 13:07:56 +08:00
function findInDocOnEnterFn ( doc ) {
2020-03-31 20:40:00 +08:00
const maybeResult = fn ( doc ) ;
2020-01-28 13:07:56 +08:00
if ( maybeResult !== undefined ) {
hasStopped = true ;
result = maybeResult ;
}
if ( hasStopped ) {
return false ;
}
}
traverseDoc ( doc , findInDocOnEnterFn ) ;
return result ;
}
function isEmpty ( n ) {
return typeof n === "string" && n . length === 0 ;
}
function isLineNextFn ( doc ) {
if ( typeof doc === "string" ) {
return false ;
}
if ( doc . type === "line" ) {
return true ;
}
}
function isLineNext ( doc ) {
return findInDoc ( doc , isLineNextFn , false ) ;
}
function willBreakFn ( doc ) {
if ( doc . type === "group" && doc . break ) {
return true ;
}
if ( doc . type === "line" && doc . hard ) {
return true ;
}
if ( doc . type === "break-parent" ) {
return true ;
}
}
function willBreak ( doc ) {
return findInDoc ( doc , willBreakFn , false ) ;
}
function breakParentGroup ( groupStack ) {
if ( groupStack . length > 0 ) {
2020-03-31 20:40:00 +08:00
const parentGroup = groupStack [ groupStack . length - 1 ] ; // Breaks are not propagated through conditional groups because
2020-01-28 13:07:56 +08:00
// the user is expected to manually handle what breaks.
if ( ! parentGroup . expandedStates ) {
parentGroup . break = true ;
}
}
return null ;
}
function propagateBreaks ( doc ) {
2020-03-31 20:40:00 +08:00
const alreadyVisitedSet = new Set ( ) ;
const groupStack = [ ] ;
2020-01-28 13:07:56 +08:00
function propagateBreaksOnEnterFn ( doc ) {
if ( doc . type === "break-parent" ) {
breakParentGroup ( groupStack ) ;
}
if ( doc . type === "group" ) {
groupStack . push ( doc ) ;
if ( alreadyVisitedSet . has ( doc ) ) {
return false ;
}
alreadyVisitedSet . add ( doc ) ;
}
}
function propagateBreaksOnExitFn ( doc ) {
if ( doc . type === "group" ) {
2020-03-31 20:40:00 +08:00
const group = groupStack . pop ( ) ;
2020-01-28 13:07:56 +08:00
if ( group . break ) {
breakParentGroup ( groupStack ) ;
}
}
}
traverseDoc ( doc , propagateBreaksOnEnterFn , propagateBreaksOnExitFn ,
/* shouldTraverseConditionalGroups */
true ) ;
}
function removeLinesFn ( doc ) {
// Force this doc into flat mode by statically converting all
// lines into spaces (or soft lines into nothing). Hard lines
// should still output because there's too great of a chance
// of breaking existing assumptions otherwise.
if ( doc . type === "line" && ! doc . hard ) {
return doc . soft ? "" : " " ;
} else if ( doc . type === "if-break" ) {
return doc . flatContents || "" ;
}
return doc ;
}
function removeLines ( doc ) {
return mapDoc ( doc , removeLinesFn ) ;
}
function stripTrailingHardline ( doc ) {
// HACK remove ending hardline, original PR: #1984
if ( doc . type === "concat" && doc . parts . length !== 0 ) {
2020-03-31 20:40:00 +08:00
const lastPart = doc . parts [ doc . parts . length - 1 ] ;
2020-01-28 13:07:56 +08:00
if ( lastPart . type === "concat" ) {
if ( lastPart . parts . length === 2 && lastPart . parts [ 0 ] . hard && lastPart . parts [ 1 ] . type === "break-parent" ) {
return {
type : "concat" ,
parts : doc . parts . slice ( 0 , - 1 )
} ;
}
return {
type : "concat" ,
parts : doc . parts . slice ( 0 , - 1 ) . concat ( stripTrailingHardline ( lastPart ) )
} ;
}
}
return doc ;
}
var docUtils = {
2020-03-31 20:40:00 +08:00
isEmpty ,
willBreak ,
isLineNext ,
traverseDoc ,
findInDoc ,
mapDoc ,
propagateBreaks ,
removeLines ,
stripTrailingHardline
2020-01-28 13:07:56 +08:00
} ;
function flattenDoc ( doc ) {
if ( doc . type === "concat" ) {
2020-03-31 20:40:00 +08:00
const res = [ ] ;
2020-01-28 13:07:56 +08:00
2020-03-31 20:40:00 +08:00
for ( let i = 0 ; i < doc . parts . length ; ++ i ) {
const doc2 = doc . parts [ i ] ;
2020-01-28 13:07:56 +08:00
if ( typeof doc2 !== "string" && doc2 . type === "concat" ) {
2020-03-31 20:40:00 +08:00
res . push ( ... flattenDoc ( doc2 ) . parts ) ;
2020-01-28 13:07:56 +08:00
} else {
2020-03-31 20:40:00 +08:00
const flattened = flattenDoc ( doc2 ) ;
2020-01-28 13:07:56 +08:00
if ( flattened !== "" ) {
res . push ( flattened ) ;
}
}
}
return Object . assign ( { } , doc , {
parts : res
} ) ;
} else if ( doc . type === "if-break" ) {
return Object . assign ( { } , doc , {
breakContents : doc . breakContents != null ? flattenDoc ( doc . breakContents ) : null ,
flatContents : doc . flatContents != null ? flattenDoc ( doc . flatContents ) : null
} ) ;
} else if ( doc . type === "group" ) {
return Object . assign ( { } , doc , {
contents : flattenDoc ( doc . contents ) ,
expandedStates : doc . expandedStates ? doc . expandedStates . map ( flattenDoc ) : doc . expandedStates
} ) ;
} else if ( doc . contents ) {
return Object . assign ( { } , doc , {
contents : flattenDoc ( doc . contents )
} ) ;
}
return doc ;
}
function printDoc ( doc ) {
if ( typeof doc === "string" ) {
return JSON . stringify ( doc ) ;
}
if ( doc . type === "line" ) {
if ( doc . literal ) {
return "literalline" ;
}
if ( doc . hard ) {
return "hardline" ;
}
if ( doc . soft ) {
return "softline" ;
}
return "line" ;
}
if ( doc . type === "break-parent" ) {
return "breakParent" ;
}
if ( doc . type === "trim" ) {
return "trim" ;
}
if ( doc . type === "concat" ) {
return "[" + doc . parts . map ( printDoc ) . join ( ", " ) + "]" ;
}
if ( doc . type === "indent" ) {
return "indent(" + printDoc ( doc . contents ) + ")" ;
}
if ( doc . type === "align" ) {
return doc . n === - Infinity ? "dedentToRoot(" + 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" ) {
return "ifBreak(" + printDoc ( doc . breakContents ) + ( doc . flatContents ? ", " + printDoc ( doc . flatContents ) : "" ) + ")" ;
}
if ( doc . type === "group" ) {
if ( doc . expandedStates ) {
return "conditionalGroup(" + "[" + doc . expandedStates . map ( printDoc ) . join ( "," ) + "])" ;
}
return ( doc . break ? "wrappedGroup" : "group" ) + "(" + printDoc ( doc . contents ) + ")" ;
}
if ( doc . type === "fill" ) {
return "fill" + "(" + doc . parts . map ( printDoc ) . join ( ", " ) + ")" ;
}
if ( doc . type === "line-suffix" ) {
return "lineSuffix(" + printDoc ( doc . contents ) + ")" ;
}
if ( doc . type === "line-suffix-boundary" ) {
return "lineSuffixBoundary" ;
}
throw new Error ( "Unknown doc type " + doc . type ) ;
}
var docDebug = {
2020-03-31 20:40:00 +08:00
printDocToDebug ( doc ) {
2020-01-28 13:07:56 +08:00
return printDoc ( flattenDoc ( doc ) ) ;
}
2020-03-31 20:40:00 +08:00
2020-01-28 13:07:56 +08:00
} ;
2020-03-31 20:40:00 +08:00
var document = {
2020-01-28 13:07:56 +08:00
builders : docBuilders ,
printer : docPrinter ,
utils : docUtils ,
debug : docDebug
} ;
2020-03-31 20:40:00 +08:00
var document _1 = document . builders ;
var document _2 = document . printer ;
var document _3 = document . utils ;
var document _4 = document . debug ;
exports . builders = document _1 ;
exports . debug = document _4 ;
exports . default = document ;
exports . printer = document _2 ;
exports . utils = document _3 ;
2020-01-28 13:07:56 +08:00
Object . defineProperty ( exports , '__esModule' , { value : true } ) ;
} ) ) ) ;