UNPKG

66.2 kBJavaScriptView Raw
1(function (global, factory) {
2 typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
3 typeof define === 'function' && define.amd ? define(['exports'], factory) :
4 (global = global || self, factory(global.doc = {}));
5}(this, (function (exports) { 'use strict';
6
7 /**
8 * @param {Doc[]} parts
9 * @returns Doc
10 */
11
12
13 function concat(parts) {
14 // access the internals of a document directly.
15 // if(parts.length === 1) {
16 // // If it's a single document, no need to concat it.
17 // return parts[0];
18 // }
19
20
21 return {
22 type: "concat",
23 parts
24 };
25 }
26 /**
27 * @param {Doc} contents
28 * @returns Doc
29 */
30
31
32 function indent(contents) {
33
34 return {
35 type: "indent",
36 contents
37 };
38 }
39 /**
40 * @param {number} n
41 * @param {Doc} contents
42 * @returns Doc
43 */
44
45
46 function align(n, contents) {
47
48 return {
49 type: "align",
50 contents,
51 n
52 };
53 }
54 /**
55 * @param {Doc} contents
56 * @param {object} [opts] - TBD ???
57 * @returns Doc
58 */
59
60
61 function group(contents, opts) {
62 opts = opts || {};
63
64 return {
65 type: "group",
66 id: opts.id,
67 contents,
68 break: !!opts.shouldBreak,
69 expandedStates: opts.expandedStates
70 };
71 }
72 /**
73 * @param {Doc} contents
74 * @returns Doc
75 */
76
77
78 function dedentToRoot(contents) {
79 return align(-Infinity, contents);
80 }
81 /**
82 * @param {Doc} contents
83 * @returns Doc
84 */
85
86
87 function markAsRoot(contents) {
88 // @ts-ignore - TBD ???:
89 return align({
90 type: "root"
91 }, contents);
92 }
93 /**
94 * @param {Doc} contents
95 * @returns Doc
96 */
97
98
99 function dedent(contents) {
100 return align(-1, contents);
101 }
102 /**
103 * @param {Doc[]} states
104 * @param {object} [opts] - TBD ???
105 * @returns Doc
106 */
107
108
109 function conditionalGroup(states, opts) {
110 return group(states[0], Object.assign({}, opts, {
111 expandedStates: states
112 }));
113 }
114 /**
115 * @param {Doc[]} parts
116 * @returns Doc
117 */
118
119
120 function fill(parts) {
121
122 return {
123 type: "fill",
124 parts
125 };
126 }
127 /**
128 * @param {Doc} [breakContents]
129 * @param {Doc} [flatContents]
130 * @param {object} [opts] - TBD ???
131 * @returns Doc
132 */
133
134
135 function ifBreak(breakContents, flatContents, opts) {
136 opts = opts || {};
137
138 return {
139 type: "if-break",
140 breakContents,
141 flatContents,
142 groupId: opts.groupId
143 };
144 }
145 /**
146 * @param {Doc} contents
147 * @returns Doc
148 */
149
150
151 function lineSuffix(contents) {
152
153 return {
154 type: "line-suffix",
155 contents
156 };
157 }
158
159 const lineSuffixBoundary = {
160 type: "line-suffix-boundary"
161 };
162 const breakParent = {
163 type: "break-parent"
164 };
165 const trim = {
166 type: "trim"
167 };
168 const line = {
169 type: "line"
170 };
171 const softline = {
172 type: "line",
173 soft: true
174 };
175 const hardline = concat([{
176 type: "line",
177 hard: true
178 }, breakParent]);
179 const literalline = concat([{
180 type: "line",
181 hard: true,
182 literal: true
183 }, breakParent]);
184 const cursor = {
185 type: "cursor",
186 placeholder: Symbol("cursor")
187 };
188 /**
189 * @param {Doc} sep
190 * @param {Doc[]} arr
191 * @returns Doc
192 */
193
194 function join(sep, arr) {
195 const res = [];
196
197 for (let i = 0; i < arr.length; i++) {
198 if (i !== 0) {
199 res.push(sep);
200 }
201
202 res.push(arr[i]);
203 }
204
205 return concat(res);
206 }
207 /**
208 * @param {Doc} doc
209 * @param {number} size
210 * @param {number} tabWidth
211 */
212
213
214 function addAlignmentToDoc(doc, size, tabWidth) {
215 let aligned = doc;
216
217 if (size > 0) {
218 // Use indent to add tabs for all the levels of tabs we need
219 for (let i = 0; i < Math.floor(size / tabWidth); ++i) {
220 aligned = indent(aligned);
221 } // Use align for all the spaces that are needed
222
223
224 aligned = align(size % tabWidth, aligned); // size is absolute from 0 and not relative to the current
225 // indentation, so we use -Infinity to reset the indentation to 0
226
227 aligned = align(-Infinity, aligned);
228 }
229
230 return aligned;
231 }
232
233 var docBuilders = {
234 concat,
235 join,
236 line,
237 softline,
238 hardline,
239 literalline,
240 group,
241 conditionalGroup,
242 fill,
243 lineSuffix,
244 lineSuffixBoundary,
245 cursor,
246 breakParent,
247 ifBreak,
248 trim,
249 indent,
250 align,
251 addAlignmentToDoc,
252 markAsRoot,
253 dedentToRoot,
254 dedent
255 };
256
257 var ansiRegex = ({
258 onlyFirst = false
259 } = {}) => {
260 const pattern = ['[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)', '(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))'].join('|');
261 return new RegExp(pattern, onlyFirst ? undefined : 'g');
262 };
263
264 var stripAnsi = string => typeof string === 'string' ? string.replace(ansiRegex(), '') : string;
265
266 /* eslint-disable yoda */
267
268 const isFullwidthCodePoint = codePoint => {
269 if (Number.isNaN(codePoint)) {
270 return false;
271 } // Code points are derived from:
272 // http://www.unix.org/Public/UNIDATA/EastAsianWidth.txt
273
274
275 if (codePoint >= 0x1100 && (codePoint <= 0x115F || // Hangul Jamo
276 codePoint === 0x2329 || // LEFT-POINTING ANGLE BRACKET
277 codePoint === 0x232A || // RIGHT-POINTING ANGLE BRACKET
278 // CJK Radicals Supplement .. Enclosed CJK Letters and Months
279 0x2E80 <= codePoint && codePoint <= 0x3247 && codePoint !== 0x303F || // Enclosed CJK Letters and Months .. CJK Unified Ideographs Extension A
280 0x3250 <= codePoint && codePoint <= 0x4DBF || // CJK Unified Ideographs .. Yi Radicals
281 0x4E00 <= codePoint && codePoint <= 0xA4C6 || // Hangul Jamo Extended-A
282 0xA960 <= codePoint && codePoint <= 0xA97C || // Hangul Syllables
283 0xAC00 <= codePoint && codePoint <= 0xD7A3 || // CJK Compatibility Ideographs
284 0xF900 <= codePoint && codePoint <= 0xFAFF || // Vertical Forms
285 0xFE10 <= codePoint && codePoint <= 0xFE19 || // CJK Compatibility Forms .. Small Form Variants
286 0xFE30 <= codePoint && codePoint <= 0xFE6B || // Halfwidth and Fullwidth Forms
287 0xFF01 <= codePoint && codePoint <= 0xFF60 || 0xFFE0 <= codePoint && codePoint <= 0xFFE6 || // Kana Supplement
288 0x1B000 <= codePoint && codePoint <= 0x1B001 || // Enclosed Ideographic Supplement
289 0x1F200 <= codePoint && codePoint <= 0x1F251 || // CJK Unified Ideographs Extension B .. Tertiary Ideographic Plane
290 0x20000 <= codePoint && codePoint <= 0x3FFFD)) {
291 return true;
292 }
293
294 return false;
295 };
296
297 var isFullwidthCodePoint_1 = isFullwidthCodePoint;
298 var default_1 = isFullwidthCodePoint;
299 isFullwidthCodePoint_1.default = default_1;
300
301 var emojiRegex = function emojiRegex() {
302 // https://mths.be/emoji
303 return /\uD83C\uDFF4\uDB40\uDC67\uDB40\uDC62(?:\uDB40\uDC65\uDB40\uDC6E\uDB40\uDC67|\uDB40\uDC73\uDB40\uDC63\uDB40\uDC74|\uDB40\uDC77\uDB40\uDC6C\uDB40\uDC73)\uDB40\uDC7F|\uD83D\uDC68(?:\uD83C\uDFFC\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68\uD83C\uDFFB|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFF\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFE])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFE\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFD])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFD\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB\uDFFC])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\u200D(?:\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83D\uDC68|(?:\uD83D[\uDC68\uDC69])\u200D(?:\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67]))|\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67])|(?:\uD83D[\uDC68\uDC69])\u200D(?:\uD83D[\uDC66\uDC67])|[\u2695\u2696\u2708]\uFE0F|\uD83D[\uDC66\uDC67]|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|(?:\uD83C\uDFFB\u200D[\u2695\u2696\u2708]|\uD83C\uDFFF\u200D[\u2695\u2696\u2708]|\uD83C\uDFFE\u200D[\u2695\u2696\u2708]|\uD83C\uDFFD\u200D[\u2695\u2696\u2708]|\uD83C\uDFFC\u200D[\u2695\u2696\u2708])\uFE0F|\uD83C\uDFFB\u200D(?:\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C[\uDFFB-\uDFFF])|(?:\uD83E\uDDD1\uD83C\uDFFB\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFC\u200D\uD83E\uDD1D\u200D\uD83D\uDC69)\uD83C\uDFFB|\uD83E\uDDD1(?:\uD83C\uDFFF\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1(?:\uD83C[\uDFFB-\uDFFF])|\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1)|(?:\uD83E\uDDD1\uD83C\uDFFE\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFF\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB-\uDFFE])|(?:\uD83E\uDDD1\uD83C\uDFFC\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFD\u200D\uD83E\uDD1D\u200D\uD83D\uDC69)(?:\uD83C[\uDFFB\uDFFC])|\uD83D\uDC69(?:\uD83C\uDFFE\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFD\uDFFF])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFC\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB\uDFFD-\uDFFF])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFB\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFC-\uDFFF])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFD\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\u200D(?:\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D(?:\uD83D[\uDC68\uDC69])|\uD83D[\uDC68\uDC69])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFF\u200D(?:\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD]))|\uD83D\uDC69\u200D\uD83D\uDC69\u200D(?:\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67]))|(?:\uD83E\uDDD1\uD83C\uDFFD\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFE\u200D\uD83E\uDD1D\u200D\uD83D\uDC69)(?:\uD83C[\uDFFB-\uDFFD])|\uD83D\uDC69\u200D\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC69\u200D\uD83D\uDC69\u200D(?:\uD83D[\uDC66\uDC67])|(?:\uD83D\uDC41\uFE0F\u200D\uD83D\uDDE8|\uD83D\uDC69(?:\uD83C\uDFFF\u200D[\u2695\u2696\u2708]|\uD83C\uDFFE\u200D[\u2695\u2696\u2708]|\uD83C\uDFFC\u200D[\u2695\u2696\u2708]|\uD83C\uDFFB\u200D[\u2695\u2696\u2708]|\uD83C\uDFFD\u200D[\u2695\u2696\u2708]|\u200D[\u2695\u2696\u2708])|(?:(?:\u26F9|\uD83C[\uDFCB\uDFCC]|\uD83D\uDD75)\uFE0F|\uD83D\uDC6F|\uD83E[\uDD3C\uDDDE\uDDDF])\u200D[\u2640\u2642]|(?:\u26F9|\uD83C[\uDFCB\uDFCC]|\uD83D\uDD75)(?:\uD83C[\uDFFB-\uDFFF])\u200D[\u2640\u2642]|(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD6-\uDDDD])(?:(?:\uD83C[\uDFFB-\uDFFF])\u200D[\u2640\u2642]|\u200D[\u2640\u2642])|\uD83C\uDFF4\u200D\u2620)\uFE0F|\uD83D\uDC69\u200D\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67])|\uD83C\uDFF3\uFE0F\u200D\uD83C\uDF08|\uD83D\uDC15\u200D\uD83E\uDDBA|\uD83D\uDC69\u200D\uD83D\uDC66|\uD83D\uDC69\u200D\uD83D\uDC67|\uD83C\uDDFD\uD83C\uDDF0|\uD83C\uDDF4\uD83C\uDDF2|\uD83C\uDDF6\uD83C\uDDE6|[#\*0-9]\uFE0F\u20E3|\uD83C\uDDE7(?:\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEF\uDDF1-\uDDF4\uDDF6-\uDDF9\uDDFB\uDDFC\uDDFE\uDDFF])|\uD83C\uDDF9(?:\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDED\uDDEF-\uDDF4\uDDF7\uDDF9\uDDFB\uDDFC\uDDFF])|\uD83C\uDDEA(?:\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDED\uDDF7-\uDDFA])|\uD83E\uDDD1(?:\uD83C[\uDFFB-\uDFFF])|\uD83C\uDDF7(?:\uD83C[\uDDEA\uDDF4\uDDF8\uDDFA\uDDFC])|\uD83D\uDC69(?:\uD83C[\uDFFB-\uDFFF])|\uD83C\uDDF2(?:\uD83C[\uDDE6\uDDE8-\uDDED\uDDF0-\uDDFF])|\uD83C\uDDE6(?:\uD83C[\uDDE8-\uDDEC\uDDEE\uDDF1\uDDF2\uDDF4\uDDF6-\uDDFA\uDDFC\uDDFD\uDDFF])|\uD83C\uDDF0(?:\uD83C[\uDDEA\uDDEC-\uDDEE\uDDF2\uDDF3\uDDF5\uDDF7\uDDFC\uDDFE\uDDFF])|\uD83C\uDDED(?:\uD83C[\uDDF0\uDDF2\uDDF3\uDDF7\uDDF9\uDDFA])|\uD83C\uDDE9(?:\uD83C[\uDDEA\uDDEC\uDDEF\uDDF0\uDDF2\uDDF4\uDDFF])|\uD83C\uDDFE(?:\uD83C[\uDDEA\uDDF9])|\uD83C\uDDEC(?:\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEE\uDDF1-\uDDF3\uDDF5-\uDDFA\uDDFC\uDDFE])|\uD83C\uDDF8(?:\uD83C[\uDDE6-\uDDEA\uDDEC-\uDDF4\uDDF7-\uDDF9\uDDFB\uDDFD-\uDDFF])|\uD83C\uDDEB(?:\uD83C[\uDDEE-\uDDF0\uDDF2\uDDF4\uDDF7])|\uD83C\uDDF5(?:\uD83C[\uDDE6\uDDEA-\uDDED\uDDF0-\uDDF3\uDDF7-\uDDF9\uDDFC\uDDFE])|\uD83C\uDDFB(?:\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDEE\uDDF3\uDDFA])|\uD83C\uDDF3(?:\uD83C[\uDDE6\uDDE8\uDDEA-\uDDEC\uDDEE\uDDF1\uDDF4\uDDF5\uDDF7\uDDFA\uDDFF])|\uD83C\uDDE8(?:\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDEE\uDDF0-\uDDF5\uDDF7\uDDFA-\uDDFF])|\uD83C\uDDF1(?:\uD83C[\uDDE6-\uDDE8\uDDEE\uDDF0\uDDF7-\uDDFB\uDDFE])|\uD83C\uDDFF(?:\uD83C[\uDDE6\uDDF2\uDDFC])|\uD83C\uDDFC(?:\uD83C[\uDDEB\uDDF8])|\uD83C\uDDFA(?:\uD83C[\uDDE6\uDDEC\uDDF2\uDDF3\uDDF8\uDDFE\uDDFF])|\uD83C\uDDEE(?:\uD83C[\uDDE8-\uDDEA\uDDF1-\uDDF4\uDDF6-\uDDF9])|\uD83C\uDDEF(?:\uD83C[\uDDEA\uDDF2\uDDF4\uDDF5])|(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD6-\uDDDD])(?:\uD83C[\uDFFB-\uDFFF])|(?:\u26F9|\uD83C[\uDFCB\uDFCC]|\uD83D\uDD75)(?:\uD83C[\uDFFB-\uDFFF])|(?:[\u261D\u270A-\u270D]|\uD83C[\uDF85\uDFC2\uDFC7]|\uD83D[\uDC42\uDC43\uDC46-\uDC50\uDC66\uDC67\uDC6B-\uDC6D\uDC70\uDC72\uDC74-\uDC76\uDC78\uDC7C\uDC83\uDC85\uDCAA\uDD74\uDD7A\uDD90\uDD95\uDD96\uDE4C\uDE4F\uDEC0\uDECC]|\uD83E[\uDD0F\uDD18-\uDD1C\uDD1E\uDD1F\uDD30-\uDD36\uDDB5\uDDB6\uDDBB\uDDD2-\uDDD5])(?:\uD83C[\uDFFB-\uDFFF])|(?:[\u231A\u231B\u23E9-\u23EC\u23F0\u23F3\u25FD\u25FE\u2614\u2615\u2648-\u2653\u267F\u2693\u26A1\u26AA\u26AB\u26BD\u26BE\u26C4\u26C5\u26CE\u26D4\u26EA\u26F2\u26F3\u26F5\u26FA\u26FD\u2705\u270A\u270B\u2728\u274C\u274E\u2753-\u2755\u2757\u2795-\u2797\u27B0\u27BF\u2B1B\u2B1C\u2B50\u2B55]|\uD83C[\uDC04\uDCCF\uDD8E\uDD91-\uDD9A\uDDE6-\uDDFF\uDE01\uDE1A\uDE2F\uDE32-\uDE36\uDE38-\uDE3A\uDE50\uDE51\uDF00-\uDF20\uDF2D-\uDF35\uDF37-\uDF7C\uDF7E-\uDF93\uDFA0-\uDFCA\uDFCF-\uDFD3\uDFE0-\uDFF0\uDFF4\uDFF8-\uDFFF]|\uD83D[\uDC00-\uDC3E\uDC40\uDC42-\uDCFC\uDCFF-\uDD3D\uDD4B-\uDD4E\uDD50-\uDD67\uDD7A\uDD95\uDD96\uDDA4\uDDFB-\uDE4F\uDE80-\uDEC5\uDECC\uDED0-\uDED2\uDED5\uDEEB\uDEEC\uDEF4-\uDEFA\uDFE0-\uDFEB]|\uD83E[\uDD0D-\uDD3A\uDD3C-\uDD45\uDD47-\uDD71\uDD73-\uDD76\uDD7A-\uDDA2\uDDA5-\uDDAA\uDDAE-\uDDCA\uDDCD-\uDDFF\uDE70-\uDE73\uDE78-\uDE7A\uDE80-\uDE82\uDE90-\uDE95])|(?:[#\*0-9\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u231A\u231B\u2328\u23CF\u23E9-\u23F3\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB-\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618\u261D\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642\u2648-\u2653\u265F\u2660\u2663\u2665\u2666\u2668\u267B\u267E\u267F\u2692-\u2697\u2699\u269B\u269C\u26A0\u26A1\u26AA\u26AB\u26B0\u26B1\u26BD\u26BE\u26C4\u26C5\u26C8\u26CE\u26CF\u26D1\u26D3\u26D4\u26E9\u26EA\u26F0-\u26F5\u26F7-\u26FA\u26FD\u2702\u2705\u2708-\u270D\u270F\u2712\u2714\u2716\u271D\u2721\u2728\u2733\u2734\u2744\u2747\u274C\u274E\u2753-\u2755\u2757\u2763\u2764\u2795-\u2797\u27A1\u27B0\u27BF\u2934\u2935\u2B05-\u2B07\u2B1B\u2B1C\u2B50\u2B55\u3030\u303D\u3297\u3299]|\uD83C[\uDC04\uDCCF\uDD70\uDD71\uDD7E\uDD7F\uDD8E\uDD91-\uDD9A\uDDE6-\uDDFF\uDE01\uDE02\uDE1A\uDE2F\uDE32-\uDE3A\uDE50\uDE51\uDF00-\uDF21\uDF24-\uDF93\uDF96\uDF97\uDF99-\uDF9B\uDF9E-\uDFF0\uDFF3-\uDFF5\uDFF7-\uDFFF]|\uD83D[\uDC00-\uDCFD\uDCFF-\uDD3D\uDD49-\uDD4E\uDD50-\uDD67\uDD6F\uDD70\uDD73-\uDD7A\uDD87\uDD8A-\uDD8D\uDD90\uDD95\uDD96\uDDA4\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDE8\uDDEF\uDDF3\uDDFA-\uDE4F\uDE80-\uDEC5\uDECB-\uDED2\uDED5\uDEE0-\uDEE5\uDEE9\uDEEB\uDEEC\uDEF0\uDEF3-\uDEFA\uDFE0-\uDFEB]|\uD83E[\uDD0D-\uDD3A\uDD3C-\uDD45\uDD47-\uDD71\uDD73-\uDD76\uDD7A-\uDDA2\uDDA5-\uDDAA\uDDAE-\uDDCA\uDDCD-\uDDFF\uDE70-\uDE73\uDE78-\uDE7A\uDE80-\uDE82\uDE90-\uDE95])\uFE0F|(?:[\u261D\u26F9\u270A-\u270D]|\uD83C[\uDF85\uDFC2-\uDFC4\uDFC7\uDFCA-\uDFCC]|\uD83D[\uDC42\uDC43\uDC46-\uDC50\uDC66-\uDC78\uDC7C\uDC81-\uDC83\uDC85-\uDC87\uDC8F\uDC91\uDCAA\uDD74\uDD75\uDD7A\uDD90\uDD95\uDD96\uDE45-\uDE47\uDE4B-\uDE4F\uDEA3\uDEB4-\uDEB6\uDEC0\uDECC]|\uD83E[\uDD0F\uDD18-\uDD1F\uDD26\uDD30-\uDD39\uDD3C-\uDD3E\uDDB5\uDDB6\uDDB8\uDDB9\uDDBB\uDDCD-\uDDCF\uDDD1-\uDDDD])/g;
304 };
305
306 const stringWidth = string => {
307 string = string.replace(emojiRegex(), ' ');
308
309 if (typeof string !== 'string' || string.length === 0) {
310 return 0;
311 }
312
313 string = stripAnsi(string);
314 let width = 0;
315
316 for (let i = 0; i < string.length; i++) {
317 const code = string.codePointAt(i); // Ignore control characters
318
319 if (code <= 0x1F || code >= 0x7F && code <= 0x9F) {
320 continue;
321 } // Ignore combining characters
322
323
324 if (code >= 0x300 && code <= 0x36F) {
325 continue;
326 } // Surrogates
327
328
329 if (code > 0xFFFF) {
330 i++;
331 }
332
333 width += isFullwidthCodePoint_1(code) ? 2 : 1;
334 }
335
336 return width;
337 };
338
339 var stringWidth_1 = stringWidth; // TODO: remove this in the next major version
340
341 var default_1$1 = stringWidth;
342 stringWidth_1.default = default_1$1;
343
344 const matchOperatorsRegex = /[|\\{}()[\]^$+*?.-]/g;
345
346 var escapeStringRegexp = string => {
347 if (typeof string !== 'string') {
348 throw new TypeError('Expected a string');
349 }
350
351 return string.replace(matchOperatorsRegex, '\\$&');
352 };
353
354 var getLast = arr => arr[arr.length - 1];
355
356 const notAsciiRegex = /[^\x20-\x7F]/;
357
358 function getPenultimate(arr) {
359 if (arr.length > 1) {
360 return arr[arr.length - 2];
361 }
362
363 return null;
364 }
365 /**
366 * @typedef {{backwards?: boolean}} SkipOptions
367 */
368
369 /**
370 * @param {string | RegExp} chars
371 * @returns {(text: string, index: number | false, opts?: SkipOptions) => number | false}
372 */
373
374
375 function skip(chars) {
376 return (text, index, opts) => {
377 const backwards = opts && opts.backwards; // Allow `skip` functions to be threaded together without having
378 // to check for failures (did someone say monads?).
379
380 if (index === false) {
381 return false;
382 }
383
384 const {
385 length
386 } = text;
387 let cursor = index;
388
389 while (cursor >= 0 && cursor < length) {
390 const c = text.charAt(cursor);
391
392 if (chars instanceof RegExp) {
393 if (!chars.test(c)) {
394 return cursor;
395 }
396 } else if (!chars.includes(c)) {
397 return cursor;
398 }
399
400 backwards ? cursor-- : cursor++;
401 }
402
403 if (cursor === -1 || cursor === length) {
404 // If we reached the beginning or end of the file, return the
405 // out-of-bounds cursor. It's up to the caller to handle this
406 // correctly. We don't want to indicate `false` though if it
407 // actually skipped valid characters.
408 return cursor;
409 }
410
411 return false;
412 };
413 }
414 /**
415 * @type {(text: string, index: number | false, opts?: SkipOptions) => number | false}
416 */
417
418
419 const skipWhitespace = skip(/\s/);
420 /**
421 * @type {(text: string, index: number | false, opts?: SkipOptions) => number | false}
422 */
423
424 const skipSpaces = skip(" \t");
425 /**
426 * @type {(text: string, index: number | false, opts?: SkipOptions) => number | false}
427 */
428
429 const skipToLineEnd = skip(",; \t");
430 /**
431 * @type {(text: string, index: number | false, opts?: SkipOptions) => number | false}
432 */
433
434 const skipEverythingButNewLine = skip(/[^\r\n]/);
435 /**
436 * @param {string} text
437 * @param {number | false} index
438 * @returns {number | false}
439 */
440
441 function skipInlineComment(text, index) {
442 if (index === false) {
443 return false;
444 }
445
446 if (text.charAt(index) === "/" && text.charAt(index + 1) === "*") {
447 for (let i = index + 2; i < text.length; ++i) {
448 if (text.charAt(i) === "*" && text.charAt(i + 1) === "/") {
449 return i + 2;
450 }
451 }
452 }
453
454 return index;
455 }
456 /**
457 * @param {string} text
458 * @param {number | false} index
459 * @returns {number | false}
460 */
461
462
463 function skipTrailingComment(text, index) {
464 if (index === false) {
465 return false;
466 }
467
468 if (text.charAt(index) === "/" && text.charAt(index + 1) === "/") {
469 return skipEverythingButNewLine(text, index);
470 }
471
472 return index;
473 } // This one doesn't use the above helper function because it wants to
474 // test \r\n in order and `skip` doesn't support ordering and we only
475 // want to skip one newline. It's simple to implement.
476
477 /**
478 * @param {string} text
479 * @param {number | false} index
480 * @param {SkipOptions=} opts
481 * @returns {number | false}
482 */
483
484
485 function skipNewline(text, index, opts) {
486 const backwards = opts && opts.backwards;
487
488 if (index === false) {
489 return false;
490 }
491
492 const atIndex = text.charAt(index);
493
494 if (backwards) {
495 if (text.charAt(index - 1) === "\r" && atIndex === "\n") {
496 return index - 2;
497 }
498
499 if (atIndex === "\n" || atIndex === "\r" || atIndex === "\u2028" || atIndex === "\u2029") {
500 return index - 1;
501 }
502 } else {
503 if (atIndex === "\r" && text.charAt(index + 1) === "\n") {
504 return index + 2;
505 }
506
507 if (atIndex === "\n" || atIndex === "\r" || atIndex === "\u2028" || atIndex === "\u2029") {
508 return index + 1;
509 }
510 }
511
512 return index;
513 }
514 /**
515 * @param {string} text
516 * @param {number} index
517 * @param {SkipOptions=} opts
518 * @returns {boolean}
519 */
520
521
522 function hasNewline(text, index, opts) {
523 opts = opts || {};
524 const idx = skipSpaces(text, opts.backwards ? index - 1 : index, opts);
525 const idx2 = skipNewline(text, idx, opts);
526 return idx !== idx2;
527 }
528 /**
529 * @param {string} text
530 * @param {number} start
531 * @param {number} end
532 * @returns {boolean}
533 */
534
535
536 function hasNewlineInRange(text, start, end) {
537 for (let i = start; i < end; ++i) {
538 if (text.charAt(i) === "\n") {
539 return true;
540 }
541 }
542
543 return false;
544 } // Note: this function doesn't ignore leading comments unlike isNextLineEmpty
545
546 /**
547 * @template N
548 * @param {string} text
549 * @param {N} node
550 * @param {(node: N) => number} locStart
551 */
552
553
554 function isPreviousLineEmpty(text, node, locStart) {
555 /** @type {number | false} */
556 let idx = locStart(node) - 1;
557 idx = skipSpaces(text, idx, {
558 backwards: true
559 });
560 idx = skipNewline(text, idx, {
561 backwards: true
562 });
563 idx = skipSpaces(text, idx, {
564 backwards: true
565 });
566 const idx2 = skipNewline(text, idx, {
567 backwards: true
568 });
569 return idx !== idx2;
570 }
571 /**
572 * @param {string} text
573 * @param {number} index
574 * @returns {boolean}
575 */
576
577
578 function isNextLineEmptyAfterIndex(text, index) {
579 /** @type {number | false} */
580 let oldIdx = null;
581 /** @type {number | false} */
582
583 let idx = index;
584
585 while (idx !== oldIdx) {
586 // We need to skip all the potential trailing inline comments
587 oldIdx = idx;
588 idx = skipToLineEnd(text, idx);
589 idx = skipInlineComment(text, idx);
590 idx = skipSpaces(text, idx);
591 }
592
593 idx = skipTrailingComment(text, idx);
594 idx = skipNewline(text, idx);
595 return idx !== false && hasNewline(text, idx);
596 }
597 /**
598 * @template N
599 * @param {string} text
600 * @param {N} node
601 * @param {(node: N) => number} locEnd
602 * @returns {boolean}
603 */
604
605
606 function isNextLineEmpty(text, node, locEnd) {
607 return isNextLineEmptyAfterIndex(text, locEnd(node));
608 }
609 /**
610 * @param {string} text
611 * @param {number} idx
612 * @returns {number | false}
613 */
614
615
616 function getNextNonSpaceNonCommentCharacterIndexWithStartIndex(text, idx) {
617 /** @type {number | false} */
618 let oldIdx = null;
619 /** @type {number | false} */
620
621 let nextIdx = idx;
622
623 while (nextIdx !== oldIdx) {
624 oldIdx = nextIdx;
625 nextIdx = skipSpaces(text, nextIdx);
626 nextIdx = skipInlineComment(text, nextIdx);
627 nextIdx = skipTrailingComment(text, nextIdx);
628 nextIdx = skipNewline(text, nextIdx);
629 }
630
631 return nextIdx;
632 }
633 /**
634 * @template N
635 * @param {string} text
636 * @param {N} node
637 * @param {(node: N) => number} locEnd
638 * @returns {number | false}
639 */
640
641
642 function getNextNonSpaceNonCommentCharacterIndex(text, node, locEnd) {
643 return getNextNonSpaceNonCommentCharacterIndexWithStartIndex(text, locEnd(node));
644 }
645 /**
646 * @template N
647 * @param {string} text
648 * @param {N} node
649 * @param {(node: N) => number} locEnd
650 * @returns {string}
651 */
652
653
654 function getNextNonSpaceNonCommentCharacter(text, node, locEnd) {
655 return text.charAt( // @ts-ignore => TBD: can return false, should we define a fallback?
656 getNextNonSpaceNonCommentCharacterIndex(text, node, locEnd));
657 }
658 /**
659 * @param {string} text
660 * @param {number} index
661 * @param {SkipOptions=} opts
662 * @returns {boolean}
663 */
664
665
666 function hasSpaces(text, index, opts) {
667 opts = opts || {};
668 const idx = skipSpaces(text, opts.backwards ? index - 1 : index, opts);
669 return idx !== index;
670 }
671 /**
672 * @param {{range?: [number, number], start?: number}} node
673 * @param {number} index
674 */
675
676
677 function setLocStart(node, index) {
678 if (node.range) {
679 node.range[0] = index;
680 } else {
681 node.start = index;
682 }
683 }
684 /**
685 * @param {{range?: [number, number], end?: number}} node
686 * @param {number} index
687 */
688
689
690 function setLocEnd(node, index) {
691 if (node.range) {
692 node.range[1] = index;
693 } else {
694 node.end = index;
695 }
696 }
697
698 const PRECEDENCE = {};
699 [["|>"], ["??"], ["||"], ["&&"], ["|"], ["^"], ["&"], ["==", "===", "!=", "!=="], ["<", ">", "<=", ">=", "in", "instanceof"], [">>", "<<", ">>>"], ["+", "-"], ["*", "/", "%"], ["**"]].forEach((tier, i) => {
700 tier.forEach(op => {
701 PRECEDENCE[op] = i;
702 });
703 });
704
705 function getPrecedence(op) {
706 return PRECEDENCE[op];
707 }
708
709 const equalityOperators = {
710 "==": true,
711 "!=": true,
712 "===": true,
713 "!==": true
714 };
715 const multiplicativeOperators = {
716 "*": true,
717 "/": true,
718 "%": true
719 };
720 const bitshiftOperators = {
721 ">>": true,
722 ">>>": true,
723 "<<": true
724 };
725
726 function shouldFlatten(parentOp, nodeOp) {
727 if (getPrecedence(nodeOp) !== getPrecedence(parentOp)) {
728 return false;
729 } // ** is right-associative
730 // x ** y ** z --> x ** (y ** z)
731
732
733 if (parentOp === "**") {
734 return false;
735 } // x == y == z --> (x == y) == z
736
737
738 if (equalityOperators[parentOp] && equalityOperators[nodeOp]) {
739 return false;
740 } // x * y % z --> (x * y) % z
741
742
743 if (nodeOp === "%" && multiplicativeOperators[parentOp] || parentOp === "%" && multiplicativeOperators[nodeOp]) {
744 return false;
745 } // x * y / z --> (x * y) / z
746 // x / y * z --> (x / y) * z
747
748
749 if (nodeOp !== parentOp && multiplicativeOperators[nodeOp] && multiplicativeOperators[parentOp]) {
750 return false;
751 } // x << y << z --> (x << y) << z
752
753
754 if (bitshiftOperators[parentOp] && bitshiftOperators[nodeOp]) {
755 return false;
756 }
757
758 return true;
759 }
760
761 function isBitwiseOperator(operator) {
762 return !!bitshiftOperators[operator] || operator === "|" || operator === "^" || operator === "&";
763 } // Tests if an expression starts with `{`, or (if forbidFunctionClassAndDoExpr
764 // holds) `function`, `class`, or `do {}`. Will be overzealous if there's
765 // already necessary grouping parentheses.
766
767
768 function startsWithNoLookaheadToken(node, forbidFunctionClassAndDoExpr) {
769 node = getLeftMost(node);
770
771 switch (node.type) {
772 case "FunctionExpression":
773 case "ClassExpression":
774 case "DoExpression":
775 return forbidFunctionClassAndDoExpr;
776
777 case "ObjectExpression":
778 return true;
779
780 case "MemberExpression":
781 case "OptionalMemberExpression":
782 return startsWithNoLookaheadToken(node.object, forbidFunctionClassAndDoExpr);
783
784 case "TaggedTemplateExpression":
785 if (node.tag.type === "FunctionExpression") {
786 // IIFEs are always already parenthesized
787 return false;
788 }
789
790 return startsWithNoLookaheadToken(node.tag, forbidFunctionClassAndDoExpr);
791
792 case "CallExpression":
793 case "OptionalCallExpression":
794 if (node.callee.type === "FunctionExpression") {
795 // IIFEs are always already parenthesized
796 return false;
797 }
798
799 return startsWithNoLookaheadToken(node.callee, forbidFunctionClassAndDoExpr);
800
801 case "ConditionalExpression":
802 return startsWithNoLookaheadToken(node.test, forbidFunctionClassAndDoExpr);
803
804 case "UpdateExpression":
805 return !node.prefix && startsWithNoLookaheadToken(node.argument, forbidFunctionClassAndDoExpr);
806
807 case "BindExpression":
808 return node.object && startsWithNoLookaheadToken(node.object, forbidFunctionClassAndDoExpr);
809
810 case "SequenceExpression":
811 return startsWithNoLookaheadToken(node.expressions[0], forbidFunctionClassAndDoExpr);
812
813 case "TSAsExpression":
814 return startsWithNoLookaheadToken(node.expression, forbidFunctionClassAndDoExpr);
815
816 default:
817 return false;
818 }
819 }
820
821 function getLeftMost(node) {
822 if (node.left) {
823 return getLeftMost(node.left);
824 }
825
826 return node;
827 }
828 /**
829 * @param {string} value
830 * @param {number} tabWidth
831 * @param {number=} startIndex
832 * @returns {number}
833 */
834
835
836 function getAlignmentSize(value, tabWidth, startIndex) {
837 startIndex = startIndex || 0;
838 let size = 0;
839
840 for (let i = startIndex; i < value.length; ++i) {
841 if (value[i] === "\t") {
842 // Tabs behave in a way that they are aligned to the nearest
843 // multiple of tabWidth:
844 // 0 -> 4, 1 -> 4, 2 -> 4, 3 -> 4
845 // 4 -> 8, 5 -> 8, 6 -> 8, 7 -> 8 ...
846 size = size + tabWidth - size % tabWidth;
847 } else {
848 size++;
849 }
850 }
851
852 return size;
853 }
854 /**
855 * @param {string} value
856 * @param {number} tabWidth
857 * @returns {number}
858 */
859
860
861 function getIndentSize(value, tabWidth) {
862 const lastNewlineIndex = value.lastIndexOf("\n");
863
864 if (lastNewlineIndex === -1) {
865 return 0;
866 }
867
868 return getAlignmentSize( // All the leading whitespaces
869 value.slice(lastNewlineIndex + 1).match(/^[ \t]*/)[0], tabWidth);
870 }
871 /**
872 * @typedef {'"' | "'"} Quote
873 */
874
875 /**
876 *
877 * @param {string} raw
878 * @param {Quote} preferredQuote
879 * @returns {Quote}
880 */
881
882
883 function getPreferredQuote(raw, preferredQuote) {
884 // `rawContent` is the string exactly like it appeared in the input source
885 // code, without its enclosing quotes.
886 const rawContent = raw.slice(1, -1);
887 /** @type {{ quote: '"', regex: RegExp }} */
888
889 const double = {
890 quote: '"',
891 regex: /"/g
892 };
893 /** @type {{ quote: "'", regex: RegExp }} */
894
895 const single = {
896 quote: "'",
897 regex: /'/g
898 };
899 const preferred = preferredQuote === "'" ? single : double;
900 const alternate = preferred === single ? double : single;
901 let result = preferred.quote; // If `rawContent` contains at least one of the quote preferred for enclosing
902 // the string, we might want to enclose with the alternate quote instead, to
903 // minimize the number of escaped quotes.
904
905 if (rawContent.includes(preferred.quote) || rawContent.includes(alternate.quote)) {
906 const numPreferredQuotes = (rawContent.match(preferred.regex) || []).length;
907 const numAlternateQuotes = (rawContent.match(alternate.regex) || []).length;
908 result = numPreferredQuotes > numAlternateQuotes ? alternate.quote : preferred.quote;
909 }
910
911 return result;
912 }
913
914 function printString(raw, options, isDirectiveLiteral) {
915 // `rawContent` is the string exactly like it appeared in the input source
916 // code, without its enclosing quotes.
917 const rawContent = raw.slice(1, -1); // Check for the alternate quote, to determine if we're allowed to swap
918 // the quotes on a DirectiveLiteral.
919
920 const canChangeDirectiveQuotes = !rawContent.includes('"') && !rawContent.includes("'");
921 /** @type {Quote} */
922
923 const enclosingQuote = options.parser === "json" ? '"' : options.__isInHtmlAttribute ? "'" : getPreferredQuote(raw, options.singleQuote ? "'" : '"'); // Directives are exact code unit sequences, which means that you can't
924 // change the escape sequences they use.
925 // See https://github.com/prettier/prettier/issues/1555
926 // and https://tc39.github.io/ecma262/#directive-prologue
927
928 if (isDirectiveLiteral) {
929 if (canChangeDirectiveQuotes) {
930 return enclosingQuote + rawContent + enclosingQuote;
931 }
932
933 return raw;
934 } // It might sound unnecessary to use `makeString` even if the string already
935 // is enclosed with `enclosingQuote`, but it isn't. The string could contain
936 // unnecessary escapes (such as in `"\'"`). Always using `makeString` makes
937 // sure that we consistently output the minimum amount of escaped quotes.
938
939
940 return makeString(rawContent, enclosingQuote, !(options.parser === "css" || options.parser === "less" || options.parser === "scss" || options.embeddedInHtml));
941 }
942 /**
943 * @param {string} rawContent
944 * @param {Quote} enclosingQuote
945 * @param {boolean=} unescapeUnnecessaryEscapes
946 * @returns {string}
947 */
948
949
950 function makeString(rawContent, enclosingQuote, unescapeUnnecessaryEscapes) {
951 const otherQuote = enclosingQuote === '"' ? "'" : '"'; // Matches _any_ escape and unescaped quotes (both single and double).
952
953 const regex = /\\([\s\S])|(['"])/g; // Escape and unescape single and double quotes as needed to be able to
954 // enclose `rawContent` with `enclosingQuote`.
955
956 const newContent = rawContent.replace(regex, (match, escaped, quote) => {
957 // If we matched an escape, and the escaped character is a quote of the
958 // other type than we intend to enclose the string with, there's no need for
959 // it to be escaped, so return it _without_ the backslash.
960 if (escaped === otherQuote) {
961 return escaped;
962 } // If we matched an unescaped quote and it is of the _same_ type as we
963 // intend to enclose the string with, it must be escaped, so return it with
964 // a backslash.
965
966
967 if (quote === enclosingQuote) {
968 return "\\" + quote;
969 }
970
971 if (quote) {
972 return quote;
973 } // Unescape any unnecessarily escaped character.
974 // Adapted from https://github.com/eslint/eslint/blob/de0b4ad7bd820ade41b1f606008bea68683dc11a/lib/rules/no-useless-escape.js#L27
975
976
977 return unescapeUnnecessaryEscapes && /^[^\\nrvtbfux\r\n\u2028\u2029"'0-7]$/.test(escaped) ? escaped : "\\" + escaped;
978 });
979 return enclosingQuote + newContent + enclosingQuote;
980 }
981
982 function printNumber(rawNumber) {
983 return rawNumber.toLowerCase() // Remove unnecessary plus and zeroes from scientific notation.
984 .replace(/^([+-]?[\d.]+e)(?:\+|(-))?0*(\d)/, "$1$2$3") // Remove unnecessary scientific notation (1e0).
985 .replace(/^([+-]?[\d.]+)e[+-]?0+$/, "$1") // Make sure numbers always start with a digit.
986 .replace(/^([+-])?\./, "$10.") // Remove extraneous trailing decimal zeroes.
987 .replace(/(\.\d+?)0+(?=e|$)/, "$1") // Remove trailing dot.
988 .replace(/\.(?=e|$)/, "");
989 }
990 /**
991 * @param {string} str
992 * @param {string} target
993 * @returns {number}
994 */
995
996
997 function getMaxContinuousCount(str, target) {
998 const results = str.match(new RegExp("(".concat(escapeStringRegexp(target), ")+"), "g"));
999
1000 if (results === null) {
1001 return 0;
1002 }
1003
1004 return results.reduce((maxCount, result) => Math.max(maxCount, result.length / target.length), 0);
1005 }
1006
1007 function getMinNotPresentContinuousCount(str, target) {
1008 const matches = str.match(new RegExp("(".concat(escapeStringRegexp(target), ")+"), "g"));
1009
1010 if (matches === null) {
1011 return 0;
1012 }
1013
1014 const countPresent = new Map();
1015 let max = 0;
1016
1017 for (const match of matches) {
1018 const count = match.length / target.length;
1019 countPresent.set(count, true);
1020
1021 if (count > max) {
1022 max = count;
1023 }
1024 }
1025
1026 for (let i = 1; i < max; i++) {
1027 if (!countPresent.get(i)) {
1028 return i;
1029 }
1030 }
1031
1032 return max + 1;
1033 }
1034 /**
1035 * @param {string} text
1036 * @returns {number}
1037 */
1038
1039
1040 function getStringWidth(text) {
1041 if (!text) {
1042 return 0;
1043 } // shortcut to avoid needless string `RegExp`s, replacements, and allocations within `string-width`
1044
1045
1046 if (!notAsciiRegex.test(text)) {
1047 return text.length;
1048 }
1049
1050 return stringWidth_1(text);
1051 }
1052
1053 function hasIgnoreComment(path) {
1054 const node = path.getValue();
1055 return hasNodeIgnoreComment(node);
1056 }
1057
1058 function hasNodeIgnoreComment(node) {
1059 return node && (node.comments && node.comments.length > 0 && node.comments.some(comment => isNodeIgnoreComment(comment) && !comment.unignore) || node.prettierIgnore);
1060 }
1061
1062 function isNodeIgnoreComment(comment) {
1063 return comment.value.trim() === "prettier-ignore";
1064 }
1065
1066 function addCommentHelper(node, comment) {
1067 const comments = node.comments || (node.comments = []);
1068 comments.push(comment);
1069 comment.printed = false; // For some reason, TypeScript parses `// x` inside of JSXText as a comment
1070 // We already "print" it via the raw text, we don't need to re-print it as a
1071 // comment
1072
1073 if (node.type === "JSXText") {
1074 comment.printed = true;
1075 }
1076 }
1077
1078 function addLeadingComment(node, comment) {
1079 comment.leading = true;
1080 comment.trailing = false;
1081 addCommentHelper(node, comment);
1082 }
1083
1084 function addDanglingComment(node, comment) {
1085 comment.leading = false;
1086 comment.trailing = false;
1087 addCommentHelper(node, comment);
1088 }
1089
1090 function addTrailingComment(node, comment) {
1091 comment.leading = false;
1092 comment.trailing = true;
1093 addCommentHelper(node, comment);
1094 }
1095
1096 function isWithinParentArrayProperty(path, propertyName) {
1097 const node = path.getValue();
1098 const parent = path.getParentNode();
1099
1100 if (parent == null) {
1101 return false;
1102 }
1103
1104 if (!Array.isArray(parent[propertyName])) {
1105 return false;
1106 }
1107
1108 const key = path.getName();
1109 return parent[propertyName][key] === node;
1110 }
1111
1112 function replaceEndOfLineWith(text, replacement) {
1113 const parts = [];
1114
1115 for (const part of text.split("\n")) {
1116 if (parts.length !== 0) {
1117 parts.push(replacement);
1118 }
1119
1120 parts.push(part);
1121 }
1122
1123 return parts;
1124 }
1125
1126 var util = {
1127 replaceEndOfLineWith,
1128 getStringWidth,
1129 getMaxContinuousCount,
1130 getMinNotPresentContinuousCount,
1131 getPrecedence,
1132 shouldFlatten,
1133 isBitwiseOperator,
1134 getPenultimate,
1135 getLast,
1136 getNextNonSpaceNonCommentCharacterIndexWithStartIndex,
1137 getNextNonSpaceNonCommentCharacterIndex,
1138 getNextNonSpaceNonCommentCharacter,
1139 skip,
1140 skipWhitespace,
1141 skipSpaces,
1142 skipToLineEnd,
1143 skipEverythingButNewLine,
1144 skipInlineComment,
1145 skipTrailingComment,
1146 skipNewline,
1147 isNextLineEmptyAfterIndex,
1148 isNextLineEmpty,
1149 isPreviousLineEmpty,
1150 hasNewline,
1151 hasNewlineInRange,
1152 hasSpaces,
1153 setLocStart,
1154 setLocEnd,
1155 startsWithNoLookaheadToken,
1156 getAlignmentSize,
1157 getIndentSize,
1158 getPreferredQuote,
1159 printString,
1160 printNumber,
1161 hasIgnoreComment,
1162 hasNodeIgnoreComment,
1163 isNodeIgnoreComment,
1164 makeString,
1165 addLeadingComment,
1166 addDanglingComment,
1167 addTrailingComment,
1168 isWithinParentArrayProperty
1169 };
1170
1171 function guessEndOfLine(text) {
1172 const index = text.indexOf("\r");
1173
1174 if (index >= 0) {
1175 return text.charAt(index + 1) === "\n" ? "crlf" : "cr";
1176 }
1177
1178 return "lf";
1179 }
1180
1181 function convertEndOfLineToChars(value) {
1182 switch (value) {
1183 case "cr":
1184 return "\r";
1185
1186 case "crlf":
1187 return "\r\n";
1188
1189 default:
1190 return "\n";
1191 }
1192 }
1193
1194 var endOfLine = {
1195 guessEndOfLine,
1196 convertEndOfLineToChars
1197 };
1198
1199 const {
1200 getStringWidth: getStringWidth$1
1201 } = util;
1202 const {
1203 convertEndOfLineToChars: convertEndOfLineToChars$1
1204 } = endOfLine;
1205 const {
1206 concat: concat$1,
1207 fill: fill$1,
1208 cursor: cursor$1
1209 } = docBuilders;
1210 /** @type {Record<symbol, typeof MODE_BREAK | typeof MODE_FLAT>} */
1211
1212 let groupModeMap;
1213 const MODE_BREAK = 1;
1214 const MODE_FLAT = 2;
1215
1216 function rootIndent() {
1217 return {
1218 value: "",
1219 length: 0,
1220 queue: []
1221 };
1222 }
1223
1224 function makeIndent(ind, options) {
1225 return generateInd(ind, {
1226 type: "indent"
1227 }, options);
1228 }
1229
1230 function makeAlign(ind, n, options) {
1231 return n === -Infinity ? ind.root || rootIndent() : n < 0 ? generateInd(ind, {
1232 type: "dedent"
1233 }, options) : !n ? ind : n.type === "root" ? Object.assign({}, ind, {
1234 root: ind
1235 }) : typeof n === "string" ? generateInd(ind, {
1236 type: "stringAlign",
1237 n
1238 }, options) : generateInd(ind, {
1239 type: "numberAlign",
1240 n
1241 }, options);
1242 }
1243
1244 function generateInd(ind, newPart, options) {
1245 const queue = newPart.type === "dedent" ? ind.queue.slice(0, -1) : ind.queue.concat(newPart);
1246 let value = "";
1247 let length = 0;
1248 let lastTabs = 0;
1249 let lastSpaces = 0;
1250
1251 for (const part of queue) {
1252 switch (part.type) {
1253 case "indent":
1254 flush();
1255
1256 if (options.useTabs) {
1257 addTabs(1);
1258 } else {
1259 addSpaces(options.tabWidth);
1260 }
1261
1262 break;
1263
1264 case "stringAlign":
1265 flush();
1266 value += part.n;
1267 length += part.n.length;
1268 break;
1269
1270 case "numberAlign":
1271 lastTabs += 1;
1272 lastSpaces += part.n;
1273 break;
1274
1275 /* istanbul ignore next */
1276
1277 default:
1278 throw new Error("Unexpected type '".concat(part.type, "'"));
1279 }
1280 }
1281
1282 flushSpaces();
1283 return Object.assign({}, ind, {
1284 value,
1285 length,
1286 queue
1287 });
1288
1289 function addTabs(count) {
1290 value += "\t".repeat(count);
1291 length += options.tabWidth * count;
1292 }
1293
1294 function addSpaces(count) {
1295 value += " ".repeat(count);
1296 length += count;
1297 }
1298
1299 function flush() {
1300 if (options.useTabs) {
1301 flushTabs();
1302 } else {
1303 flushSpaces();
1304 }
1305 }
1306
1307 function flushTabs() {
1308 if (lastTabs > 0) {
1309 addTabs(lastTabs);
1310 }
1311
1312 resetLast();
1313 }
1314
1315 function flushSpaces() {
1316 if (lastSpaces > 0) {
1317 addSpaces(lastSpaces);
1318 }
1319
1320 resetLast();
1321 }
1322
1323 function resetLast() {
1324 lastTabs = 0;
1325 lastSpaces = 0;
1326 }
1327 }
1328
1329 function trim$1(out) {
1330 if (out.length === 0) {
1331 return 0;
1332 }
1333
1334 let trimCount = 0; // Trim whitespace at the end of line
1335
1336 while (out.length > 0 && typeof out[out.length - 1] === "string" && out[out.length - 1].match(/^[ \t]*$/)) {
1337 trimCount += out.pop().length;
1338 }
1339
1340 if (out.length && typeof out[out.length - 1] === "string") {
1341 const trimmed = out[out.length - 1].replace(/[ \t]*$/, "");
1342 trimCount += out[out.length - 1].length - trimmed.length;
1343 out[out.length - 1] = trimmed;
1344 }
1345
1346 return trimCount;
1347 }
1348
1349 function fits(next, restCommands, width, options, mustBeFlat) {
1350 let restIdx = restCommands.length;
1351 const cmds = [next]; // `out` is only used for width counting because `trim` requires to look
1352 // backwards for space characters.
1353
1354 const out = [];
1355
1356 while (width >= 0) {
1357 if (cmds.length === 0) {
1358 if (restIdx === 0) {
1359 return true;
1360 }
1361
1362 cmds.push(restCommands[restIdx - 1]);
1363 restIdx--;
1364 continue;
1365 }
1366
1367 const [ind, mode, doc] = cmds.pop();
1368
1369 if (typeof doc === "string") {
1370 out.push(doc);
1371 width -= getStringWidth$1(doc);
1372 } else {
1373 switch (doc.type) {
1374 case "concat":
1375 for (let i = doc.parts.length - 1; i >= 0; i--) {
1376 cmds.push([ind, mode, doc.parts[i]]);
1377 }
1378
1379 break;
1380
1381 case "indent":
1382 cmds.push([makeIndent(ind, options), mode, doc.contents]);
1383 break;
1384
1385 case "align":
1386 cmds.push([makeAlign(ind, doc.n, options), mode, doc.contents]);
1387 break;
1388
1389 case "trim":
1390 width += trim$1(out);
1391 break;
1392
1393 case "group":
1394 if (mustBeFlat && doc.break) {
1395 return false;
1396 }
1397
1398 cmds.push([ind, doc.break ? MODE_BREAK : mode, doc.contents]);
1399
1400 if (doc.id) {
1401 groupModeMap[doc.id] = cmds[cmds.length - 1][1];
1402 }
1403
1404 break;
1405
1406 case "fill":
1407 for (let i = doc.parts.length - 1; i >= 0; i--) {
1408 cmds.push([ind, mode, doc.parts[i]]);
1409 }
1410
1411 break;
1412
1413 case "if-break":
1414 {
1415 const groupMode = doc.groupId ? groupModeMap[doc.groupId] : mode;
1416
1417 if (groupMode === MODE_BREAK) {
1418 if (doc.breakContents) {
1419 cmds.push([ind, mode, doc.breakContents]);
1420 }
1421 }
1422
1423 if (groupMode === MODE_FLAT) {
1424 if (doc.flatContents) {
1425 cmds.push([ind, mode, doc.flatContents]);
1426 }
1427 }
1428
1429 break;
1430 }
1431
1432 case "line":
1433 switch (mode) {
1434 // fallthrough
1435 case MODE_FLAT:
1436 if (!doc.hard) {
1437 if (!doc.soft) {
1438 out.push(" ");
1439 width -= 1;
1440 }
1441
1442 break;
1443 }
1444
1445 return true;
1446
1447 case MODE_BREAK:
1448 return true;
1449 }
1450
1451 break;
1452 }
1453 }
1454 }
1455
1456 return false;
1457 }
1458
1459 function printDocToString(doc, options) {
1460 groupModeMap = {};
1461 const width = options.printWidth;
1462 const newLine = convertEndOfLineToChars$1(options.endOfLine);
1463 let pos = 0; // cmds is basically a stack. We've turned a recursive call into a
1464 // while loop which is much faster. The while loop below adds new
1465 // cmds to the array instead of recursively calling `print`.
1466
1467 const cmds = [[rootIndent(), MODE_BREAK, doc]];
1468 const out = [];
1469 let shouldRemeasure = false;
1470 let lineSuffix = [];
1471
1472 while (cmds.length !== 0) {
1473 const [ind, mode, doc] = cmds.pop();
1474
1475 if (typeof doc === "string") {
1476 const formatted = newLine !== "\n" && doc.includes("\n") ? doc.replace(/\n/g, newLine) : doc;
1477 out.push(formatted);
1478 pos += getStringWidth$1(formatted);
1479 } else {
1480 switch (doc.type) {
1481 case "cursor":
1482 out.push(cursor$1.placeholder);
1483 break;
1484
1485 case "concat":
1486 for (let i = doc.parts.length - 1; i >= 0; i--) {
1487 cmds.push([ind, mode, doc.parts[i]]);
1488 }
1489
1490 break;
1491
1492 case "indent":
1493 cmds.push([makeIndent(ind, options), mode, doc.contents]);
1494 break;
1495
1496 case "align":
1497 cmds.push([makeAlign(ind, doc.n, options), mode, doc.contents]);
1498 break;
1499
1500 case "trim":
1501 pos -= trim$1(out);
1502 break;
1503
1504 case "group":
1505 switch (mode) {
1506 case MODE_FLAT:
1507 if (!shouldRemeasure) {
1508 cmds.push([ind, doc.break ? MODE_BREAK : MODE_FLAT, doc.contents]);
1509 break;
1510 }
1511
1512 // fallthrough
1513
1514 case MODE_BREAK:
1515 {
1516 shouldRemeasure = false;
1517 const next = [ind, MODE_FLAT, doc.contents];
1518 const rem = width - pos;
1519
1520 if (!doc.break && fits(next, cmds, rem, options)) {
1521 cmds.push(next);
1522 } else {
1523 // Expanded states are a rare case where a document
1524 // can manually provide multiple representations of
1525 // itself. It provides an array of documents
1526 // going from the least expanded (most flattened)
1527 // representation first to the most expanded. If a
1528 // group has these, we need to manually go through
1529 // these states and find the first one that fits.
1530 if (doc.expandedStates) {
1531 const mostExpanded = doc.expandedStates[doc.expandedStates.length - 1];
1532
1533 if (doc.break) {
1534 cmds.push([ind, MODE_BREAK, mostExpanded]);
1535 break;
1536 } else {
1537 for (let i = 1; i < doc.expandedStates.length + 1; i++) {
1538 if (i >= doc.expandedStates.length) {
1539 cmds.push([ind, MODE_BREAK, mostExpanded]);
1540 break;
1541 } else {
1542 const state = doc.expandedStates[i];
1543 const cmd = [ind, MODE_FLAT, state];
1544
1545 if (fits(cmd, cmds, rem, options)) {
1546 cmds.push(cmd);
1547 break;
1548 }
1549 }
1550 }
1551 }
1552 } else {
1553 cmds.push([ind, MODE_BREAK, doc.contents]);
1554 }
1555 }
1556
1557 break;
1558 }
1559 }
1560
1561 if (doc.id) {
1562 groupModeMap[doc.id] = cmds[cmds.length - 1][1];
1563 }
1564
1565 break;
1566 // Fills each line with as much code as possible before moving to a new
1567 // line with the same indentation.
1568 //
1569 // Expects doc.parts to be an array of alternating content and
1570 // whitespace. The whitespace contains the linebreaks.
1571 //
1572 // For example:
1573 // ["I", line, "love", line, "monkeys"]
1574 // or
1575 // [{ type: group, ... }, softline, { type: group, ... }]
1576 //
1577 // It uses this parts structure to handle three main layout cases:
1578 // * The first two content items fit on the same line without
1579 // breaking
1580 // -> output the first content item and the whitespace "flat".
1581 // * Only the first content item fits on the line without breaking
1582 // -> output the first content item "flat" and the whitespace with
1583 // "break".
1584 // * Neither content item fits on the line without breaking
1585 // -> output the first content item and the whitespace with "break".
1586
1587 case "fill":
1588 {
1589 const rem = width - pos;
1590 const {
1591 parts
1592 } = doc;
1593
1594 if (parts.length === 0) {
1595 break;
1596 }
1597
1598 const [content, whitespace] = parts;
1599 const contentFlatCmd = [ind, MODE_FLAT, content];
1600 const contentBreakCmd = [ind, MODE_BREAK, content];
1601 const contentFits = fits(contentFlatCmd, [], rem, options, true);
1602
1603 if (parts.length === 1) {
1604 if (contentFits) {
1605 cmds.push(contentFlatCmd);
1606 } else {
1607 cmds.push(contentBreakCmd);
1608 }
1609
1610 break;
1611 }
1612
1613 const whitespaceFlatCmd = [ind, MODE_FLAT, whitespace];
1614 const whitespaceBreakCmd = [ind, MODE_BREAK, whitespace];
1615
1616 if (parts.length === 2) {
1617 if (contentFits) {
1618 cmds.push(whitespaceFlatCmd);
1619 cmds.push(contentFlatCmd);
1620 } else {
1621 cmds.push(whitespaceBreakCmd);
1622 cmds.push(contentBreakCmd);
1623 }
1624
1625 break;
1626 } // At this point we've handled the first pair (context, separator)
1627 // and will create a new fill doc for the rest of the content.
1628 // Ideally we wouldn't mutate the array here but copying all the
1629 // elements to a new array would make this algorithm quadratic,
1630 // which is unusable for large arrays (e.g. large texts in JSX).
1631
1632
1633 parts.splice(0, 2);
1634 const remainingCmd = [ind, mode, fill$1(parts)];
1635 const secondContent = parts[0];
1636 const firstAndSecondContentFlatCmd = [ind, MODE_FLAT, concat$1([content, whitespace, secondContent])];
1637 const firstAndSecondContentFits = fits(firstAndSecondContentFlatCmd, [], rem, options, true);
1638
1639 if (firstAndSecondContentFits) {
1640 cmds.push(remainingCmd);
1641 cmds.push(whitespaceFlatCmd);
1642 cmds.push(contentFlatCmd);
1643 } else if (contentFits) {
1644 cmds.push(remainingCmd);
1645 cmds.push(whitespaceBreakCmd);
1646 cmds.push(contentFlatCmd);
1647 } else {
1648 cmds.push(remainingCmd);
1649 cmds.push(whitespaceBreakCmd);
1650 cmds.push(contentBreakCmd);
1651 }
1652
1653 break;
1654 }
1655
1656 case "if-break":
1657 {
1658 const groupMode = doc.groupId ? groupModeMap[doc.groupId] : mode;
1659
1660 if (groupMode === MODE_BREAK) {
1661 if (doc.breakContents) {
1662 cmds.push([ind, mode, doc.breakContents]);
1663 }
1664 }
1665
1666 if (groupMode === MODE_FLAT) {
1667 if (doc.flatContents) {
1668 cmds.push([ind, mode, doc.flatContents]);
1669 }
1670 }
1671
1672 break;
1673 }
1674
1675 case "line-suffix":
1676 lineSuffix.push([ind, mode, doc.contents]);
1677 break;
1678
1679 case "line-suffix-boundary":
1680 if (lineSuffix.length > 0) {
1681 cmds.push([ind, mode, {
1682 type: "line",
1683 hard: true
1684 }]);
1685 }
1686
1687 break;
1688
1689 case "line":
1690 switch (mode) {
1691 case MODE_FLAT:
1692 if (!doc.hard) {
1693 if (!doc.soft) {
1694 out.push(" ");
1695 pos += 1;
1696 }
1697
1698 break;
1699 } else {
1700 // This line was forced into the output even if we
1701 // were in flattened mode, so we need to tell the next
1702 // group that no matter what, it needs to remeasure
1703 // because the previous measurement didn't accurately
1704 // capture the entire expression (this is necessary
1705 // for nested groups)
1706 shouldRemeasure = true;
1707 }
1708
1709 // fallthrough
1710
1711 case MODE_BREAK:
1712 if (lineSuffix.length) {
1713 cmds.push([ind, mode, doc]);
1714 cmds.push(...lineSuffix.reverse());
1715 lineSuffix = [];
1716 break;
1717 }
1718
1719 if (doc.literal) {
1720 if (ind.root) {
1721 out.push(newLine, ind.root.value);
1722 pos = ind.root.length;
1723 } else {
1724 out.push(newLine);
1725 pos = 0;
1726 }
1727 } else {
1728 pos -= trim$1(out);
1729 out.push(newLine + ind.value);
1730 pos = ind.length;
1731 }
1732
1733 break;
1734 }
1735
1736 break;
1737 }
1738 }
1739 }
1740
1741 const cursorPlaceholderIndex = out.indexOf(cursor$1.placeholder);
1742
1743 if (cursorPlaceholderIndex !== -1) {
1744 const otherCursorPlaceholderIndex = out.indexOf(cursor$1.placeholder, cursorPlaceholderIndex + 1);
1745 const beforeCursor = out.slice(0, cursorPlaceholderIndex).join("");
1746 const aroundCursor = out.slice(cursorPlaceholderIndex + 1, otherCursorPlaceholderIndex).join("");
1747 const afterCursor = out.slice(otherCursorPlaceholderIndex + 1).join("");
1748 return {
1749 formatted: beforeCursor + aroundCursor + afterCursor,
1750 cursorNodeStart: beforeCursor.length,
1751 cursorNodeText: aroundCursor
1752 };
1753 }
1754
1755 return {
1756 formatted: out.join("")
1757 };
1758 }
1759
1760 var docPrinter = {
1761 printDocToString
1762 };
1763
1764 const traverseDocOnExitStackMarker = {};
1765
1766 function traverseDoc(doc, onEnter, onExit, shouldTraverseConditionalGroups) {
1767 const docsStack = [doc];
1768
1769 while (docsStack.length !== 0) {
1770 const doc = docsStack.pop();
1771
1772 if (doc === traverseDocOnExitStackMarker) {
1773 onExit(docsStack.pop());
1774 continue;
1775 }
1776
1777 let shouldRecurse = true;
1778
1779 if (onEnter) {
1780 if (onEnter(doc) === false) {
1781 shouldRecurse = false;
1782 }
1783 }
1784
1785 if (onExit) {
1786 docsStack.push(doc);
1787 docsStack.push(traverseDocOnExitStackMarker);
1788 }
1789
1790 if (shouldRecurse) {
1791 // When there are multiple parts to process,
1792 // the parts need to be pushed onto the stack in reverse order,
1793 // so that they are processed in the original order
1794 // when the stack is popped.
1795 if (doc.type === "concat" || doc.type === "fill") {
1796 for (let ic = doc.parts.length, i = ic - 1; i >= 0; --i) {
1797 docsStack.push(doc.parts[i]);
1798 }
1799 } else if (doc.type === "if-break") {
1800 if (doc.flatContents) {
1801 docsStack.push(doc.flatContents);
1802 }
1803
1804 if (doc.breakContents) {
1805 docsStack.push(doc.breakContents);
1806 }
1807 } else if (doc.type === "group" && doc.expandedStates) {
1808 if (shouldTraverseConditionalGroups) {
1809 for (let ic = doc.expandedStates.length, i = ic - 1; i >= 0; --i) {
1810 docsStack.push(doc.expandedStates[i]);
1811 }
1812 } else {
1813 docsStack.push(doc.contents);
1814 }
1815 } else if (doc.contents) {
1816 docsStack.push(doc.contents);
1817 }
1818 }
1819 }
1820 }
1821
1822 function mapDoc(doc, cb) {
1823 if (doc.type === "concat" || doc.type === "fill") {
1824 const parts = doc.parts.map(part => mapDoc(part, cb));
1825 return cb(Object.assign({}, doc, {
1826 parts
1827 }));
1828 } else if (doc.type === "if-break") {
1829 const breakContents = doc.breakContents && mapDoc(doc.breakContents, cb);
1830 const flatContents = doc.flatContents && mapDoc(doc.flatContents, cb);
1831 return cb(Object.assign({}, doc, {
1832 breakContents,
1833 flatContents
1834 }));
1835 } else if (doc.contents) {
1836 const contents = mapDoc(doc.contents, cb);
1837 return cb(Object.assign({}, doc, {
1838 contents
1839 }));
1840 }
1841
1842 return cb(doc);
1843 }
1844
1845 function findInDoc(doc, fn, defaultValue) {
1846 let result = defaultValue;
1847 let hasStopped = false;
1848
1849 function findInDocOnEnterFn(doc) {
1850 const maybeResult = fn(doc);
1851
1852 if (maybeResult !== undefined) {
1853 hasStopped = true;
1854 result = maybeResult;
1855 }
1856
1857 if (hasStopped) {
1858 return false;
1859 }
1860 }
1861
1862 traverseDoc(doc, findInDocOnEnterFn);
1863 return result;
1864 }
1865
1866 function isEmpty(n) {
1867 return typeof n === "string" && n.length === 0;
1868 }
1869
1870 function isLineNextFn(doc) {
1871 if (typeof doc === "string") {
1872 return false;
1873 }
1874
1875 if (doc.type === "line") {
1876 return true;
1877 }
1878 }
1879
1880 function isLineNext(doc) {
1881 return findInDoc(doc, isLineNextFn, false);
1882 }
1883
1884 function willBreakFn(doc) {
1885 if (doc.type === "group" && doc.break) {
1886 return true;
1887 }
1888
1889 if (doc.type === "line" && doc.hard) {
1890 return true;
1891 }
1892
1893 if (doc.type === "break-parent") {
1894 return true;
1895 }
1896 }
1897
1898 function willBreak(doc) {
1899 return findInDoc(doc, willBreakFn, false);
1900 }
1901
1902 function breakParentGroup(groupStack) {
1903 if (groupStack.length > 0) {
1904 const parentGroup = groupStack[groupStack.length - 1]; // Breaks are not propagated through conditional groups because
1905 // the user is expected to manually handle what breaks.
1906
1907 if (!parentGroup.expandedStates) {
1908 parentGroup.break = true;
1909 }
1910 }
1911
1912 return null;
1913 }
1914
1915 function propagateBreaks(doc) {
1916 const alreadyVisitedSet = new Set();
1917 const groupStack = [];
1918
1919 function propagateBreaksOnEnterFn(doc) {
1920 if (doc.type === "break-parent") {
1921 breakParentGroup(groupStack);
1922 }
1923
1924 if (doc.type === "group") {
1925 groupStack.push(doc);
1926
1927 if (alreadyVisitedSet.has(doc)) {
1928 return false;
1929 }
1930
1931 alreadyVisitedSet.add(doc);
1932 }
1933 }
1934
1935 function propagateBreaksOnExitFn(doc) {
1936 if (doc.type === "group") {
1937 const group = groupStack.pop();
1938
1939 if (group.break) {
1940 breakParentGroup(groupStack);
1941 }
1942 }
1943 }
1944
1945 traverseDoc(doc, propagateBreaksOnEnterFn, propagateBreaksOnExitFn,
1946 /* shouldTraverseConditionalGroups */
1947 true);
1948 }
1949
1950 function removeLinesFn(doc) {
1951 // Force this doc into flat mode by statically converting all
1952 // lines into spaces (or soft lines into nothing). Hard lines
1953 // should still output because there's too great of a chance
1954 // of breaking existing assumptions otherwise.
1955 if (doc.type === "line" && !doc.hard) {
1956 return doc.soft ? "" : " ";
1957 } else if (doc.type === "if-break") {
1958 return doc.flatContents || "";
1959 }
1960
1961 return doc;
1962 }
1963
1964 function removeLines(doc) {
1965 return mapDoc(doc, removeLinesFn);
1966 }
1967
1968 function stripTrailingHardline(doc) {
1969 // HACK remove ending hardline, original PR: #1984
1970 if (doc.type === "concat" && doc.parts.length !== 0) {
1971 const lastPart = doc.parts[doc.parts.length - 1];
1972
1973 if (lastPart.type === "concat") {
1974 if (lastPart.parts.length === 2 && lastPart.parts[0].hard && lastPart.parts[1].type === "break-parent") {
1975 return {
1976 type: "concat",
1977 parts: doc.parts.slice(0, -1)
1978 };
1979 }
1980
1981 return {
1982 type: "concat",
1983 parts: doc.parts.slice(0, -1).concat(stripTrailingHardline(lastPart))
1984 };
1985 }
1986 }
1987
1988 return doc;
1989 }
1990
1991 var docUtils = {
1992 isEmpty,
1993 willBreak,
1994 isLineNext,
1995 traverseDoc,
1996 findInDoc,
1997 mapDoc,
1998 propagateBreaks,
1999 removeLines,
2000 stripTrailingHardline
2001 };
2002
2003 function flattenDoc(doc) {
2004 if (doc.type === "concat") {
2005 const res = [];
2006
2007 for (let i = 0; i < doc.parts.length; ++i) {
2008 const doc2 = doc.parts[i];
2009
2010 if (typeof doc2 !== "string" && doc2.type === "concat") {
2011 res.push(...flattenDoc(doc2).parts);
2012 } else {
2013 const flattened = flattenDoc(doc2);
2014
2015 if (flattened !== "") {
2016 res.push(flattened);
2017 }
2018 }
2019 }
2020
2021 return Object.assign({}, doc, {
2022 parts: res
2023 });
2024 } else if (doc.type === "if-break") {
2025 return Object.assign({}, doc, {
2026 breakContents: doc.breakContents != null ? flattenDoc(doc.breakContents) : null,
2027 flatContents: doc.flatContents != null ? flattenDoc(doc.flatContents) : null
2028 });
2029 } else if (doc.type === "group") {
2030 return Object.assign({}, doc, {
2031 contents: flattenDoc(doc.contents),
2032 expandedStates: doc.expandedStates ? doc.expandedStates.map(flattenDoc) : doc.expandedStates
2033 });
2034 } else if (doc.contents) {
2035 return Object.assign({}, doc, {
2036 contents: flattenDoc(doc.contents)
2037 });
2038 }
2039
2040 return doc;
2041 }
2042
2043 function printDoc(doc) {
2044 if (typeof doc === "string") {
2045 return JSON.stringify(doc);
2046 }
2047
2048 if (doc.type === "line") {
2049 if (doc.literal) {
2050 return "literalline";
2051 }
2052
2053 if (doc.hard) {
2054 return "hardline";
2055 }
2056
2057 if (doc.soft) {
2058 return "softline";
2059 }
2060
2061 return "line";
2062 }
2063
2064 if (doc.type === "break-parent") {
2065 return "breakParent";
2066 }
2067
2068 if (doc.type === "trim") {
2069 return "trim";
2070 }
2071
2072 if (doc.type === "concat") {
2073 return "[" + doc.parts.map(printDoc).join(", ") + "]";
2074 }
2075
2076 if (doc.type === "indent") {
2077 return "indent(" + printDoc(doc.contents) + ")";
2078 }
2079
2080 if (doc.type === "align") {
2081 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) + ")";
2082 }
2083
2084 if (doc.type === "if-break") {
2085 return "ifBreak(" + printDoc(doc.breakContents) + (doc.flatContents ? ", " + printDoc(doc.flatContents) : "") + ")";
2086 }
2087
2088 if (doc.type === "group") {
2089 if (doc.expandedStates) {
2090 return "conditionalGroup(" + "[" + doc.expandedStates.map(printDoc).join(",") + "])";
2091 }
2092
2093 return (doc.break ? "wrappedGroup" : "group") + "(" + printDoc(doc.contents) + ")";
2094 }
2095
2096 if (doc.type === "fill") {
2097 return "fill" + "(" + doc.parts.map(printDoc).join(", ") + ")";
2098 }
2099
2100 if (doc.type === "line-suffix") {
2101 return "lineSuffix(" + printDoc(doc.contents) + ")";
2102 }
2103
2104 if (doc.type === "line-suffix-boundary") {
2105 return "lineSuffixBoundary";
2106 }
2107
2108 throw new Error("Unknown doc type " + doc.type);
2109 }
2110
2111 var docDebug = {
2112 printDocToDebug(doc) {
2113 return printDoc(flattenDoc(doc));
2114 }
2115
2116 };
2117
2118 var document = {
2119 builders: docBuilders,
2120 printer: docPrinter,
2121 utils: docUtils,
2122 debug: docDebug
2123 };
2124 var document_1 = document.builders;
2125 var document_2 = document.printer;
2126 var document_3 = document.utils;
2127 var document_4 = document.debug;
2128
2129 exports.builders = document_1;
2130 exports.debug = document_4;
2131 exports.default = document;
2132 exports.printer = document_2;
2133 exports.utils = document_3;
2134
2135 Object.defineProperty(exports, '__esModule', { value: true });
2136
2137})));