@ripple-ts/prettier-plugin 0.2.208 → 0.2.211
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/package.json +4 -2
- package/src/index.js +1514 -443
- package/src/index.test.js +512 -0
package/src/index.js
CHANGED
|
@@ -1,11 +1,121 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* @import { Doc, AstPath, ParserOptions } from 'prettier'
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/// <reference types="@types/estree" />
|
|
6
|
+
/// <reference types="@types/estree-jsx" />
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Re-export estree types for use in JSDoc. The Ripple compiler augments these
|
|
10
|
+
* with additional node types like Component, Element, etc.
|
|
11
|
+
* @typedef {import('estree').Node} Node
|
|
12
|
+
* @typedef {import('estree').Program} Program
|
|
13
|
+
* @typedef {import('estree').Comment} Comment
|
|
14
|
+
* @typedef {import('estree').Expression} Expression
|
|
15
|
+
* @typedef {import('estree').Pattern} Pattern
|
|
16
|
+
* @typedef {import('estree').Statement} Statement
|
|
17
|
+
* @typedef {import('estree').Identifier} Identifier
|
|
18
|
+
* @typedef {import('estree').Literal} Literal
|
|
19
|
+
* @typedef {import('estree').FunctionDeclaration} FunctionDeclaration
|
|
20
|
+
* @typedef {import('estree').FunctionExpression} FunctionExpression
|
|
21
|
+
* @typedef {import('estree').ArrowFunctionExpression} ArrowFunctionExpression
|
|
22
|
+
* @typedef {import('estree').ImportDeclaration} ImportDeclaration
|
|
23
|
+
* @typedef {import('estree').ExportNamedDeclaration} ExportNamedDeclaration
|
|
24
|
+
* @typedef {import('estree').ObjectExpression} ObjectExpression
|
|
25
|
+
* @typedef {import('estree').Property} Property
|
|
26
|
+
* @typedef {import('estree').MethodDefinition} MethodDefinition
|
|
27
|
+
* @typedef {import('estree').CallExpression} CallExpression
|
|
28
|
+
* @typedef {import('estree').NewExpression} NewExpression
|
|
29
|
+
* @typedef {import('estree').BinaryExpression} BinaryExpression
|
|
30
|
+
* @typedef {import('estree').LogicalExpression} LogicalExpression
|
|
31
|
+
* @typedef {import('estree').SourceLocation} SourceLocation
|
|
32
|
+
* @typedef {import('estree').SpreadElement} SpreadElement
|
|
33
|
+
* @typedef {import('estree').ImportSpecifier} ImportSpecifier
|
|
34
|
+
* @typedef {import('estree').ExportSpecifier} ExportSpecifier
|
|
35
|
+
* @typedef {import('estree').BlockStatement} BlockStatement
|
|
36
|
+
* @typedef {import('estree').VariableDeclaration} VariableDeclaration
|
|
37
|
+
* @typedef {import('estree').VariableDeclarator} VariableDeclarator
|
|
38
|
+
*/
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* JSX types from estree-jsx
|
|
42
|
+
* @typedef {import('estree-jsx').JSXElement} JSXElement
|
|
43
|
+
* @typedef {import('estree-jsx').JSXFragment} JSXFragment
|
|
44
|
+
* @typedef {import('estree-jsx').JSXAttribute} JSXAttribute
|
|
45
|
+
* @typedef {import('estree-jsx').JSXSpreadAttribute} JSXSpreadAttribute
|
|
46
|
+
* @typedef {import('estree-jsx').JSXIdentifier} JSXIdentifier
|
|
47
|
+
* @typedef {import('estree-jsx').JSXExpressionContainer} JSXExpressionContainer
|
|
48
|
+
* @typedef {import('estree-jsx').JSXEmptyExpression} JSXEmptyExpression
|
|
49
|
+
*/
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Ripple-specific AST node types. These are defined by the Ripple compiler
|
|
53
|
+
* and extend the standard ESTree AST. The node type is intentionally flexible
|
|
54
|
+
* to accommodate all ESTree, JSX, and Ripple-specific node types. The printer
|
|
55
|
+
* performs runtime type checking via node.type to determine how to format each node.
|
|
56
|
+
*
|
|
57
|
+
* We use `any` as the base type because the printer must handle:
|
|
58
|
+
* - Standard ESTree nodes (Program, FunctionDeclaration, etc.)
|
|
59
|
+
* - ESTree-JSX nodes (JSXElement, JSXAttribute, etc.)
|
|
60
|
+
* - TypeScript AST extensions (TSTypeAnnotation, TSParameterProperty, etc.)
|
|
61
|
+
* - Ripple-specific nodes (Component, Element, TrackedExpression, etc.)
|
|
62
|
+
* - Comment nodes which have a different structure
|
|
63
|
+
*
|
|
64
|
+
* Runtime type checking via node.type ensures safe property access.
|
|
65
|
+
*
|
|
66
|
+
* @typedef {any} RippleASTNode
|
|
67
|
+
*/
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Print function callback type.
|
|
71
|
+
* The actual print function accepts an optional args parameter, but for
|
|
72
|
+
* compatibility with Prettier's path.call/path.each types, we use `any`
|
|
73
|
+
* for the parameters.
|
|
74
|
+
* @typedef {(...args: any[]) => Doc} PrintFn
|
|
75
|
+
*/
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Prettier formatting options used by this plugin
|
|
79
|
+
* @typedef {Object} RippleFormatOptions
|
|
80
|
+
* @property {boolean} [singleQuote] - Use single quotes for strings
|
|
81
|
+
* @property {boolean} [jsxSingleQuote] - Use single quotes in JSX attributes
|
|
82
|
+
* @property {boolean} [semi] - Add semicolons at end of statements
|
|
83
|
+
* @property {'none' | 'es5' | 'all'} [trailingComma] - Trailing comma style
|
|
84
|
+
* @property {boolean} [useTabs] - Use tabs for indentation
|
|
85
|
+
* @property {number} [tabWidth] - Number of spaces per indentation level
|
|
86
|
+
* @property {boolean} [singleAttributePerLine] - Put each JSX attribute on its own line
|
|
87
|
+
* @property {boolean} [bracketSameLine] - Put closing bracket on same line as attributes
|
|
88
|
+
* @property {boolean} [bracketSpacing] - Print spaces between brackets in object literals
|
|
89
|
+
* @property {'always' | 'avoid'} [arrowParens] - Arrow function parentheses style
|
|
90
|
+
* @property {string} [originalText] - Original source text
|
|
91
|
+
* @property {(node: RippleASTNode) => number} [locEnd] - Function to get node end position
|
|
92
|
+
*/
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Context arguments passed through print function calls
|
|
96
|
+
* @typedef {Object} PrintArgs
|
|
97
|
+
* @property {boolean} [isInAttribute] - Node is inside an attribute value
|
|
98
|
+
* @property {boolean} [isInArray] - Node is inside an array
|
|
99
|
+
* @property {boolean} [allowInlineObject] - Allow single-line object formatting
|
|
100
|
+
* @property {boolean} [isConditionalTest] - Node is a conditional test expression
|
|
101
|
+
* @property {boolean} [isNestedConditional] - Node is a nested conditional
|
|
102
|
+
* @property {boolean} [suppressLeadingComments] - Skip printing leading comments
|
|
103
|
+
* @property {boolean} [suppressExpressionLeadingComments] - Skip expression leading comments
|
|
104
|
+
* @property {boolean} [isInlineContext] - Node is in an inline context
|
|
105
|
+
* @property {boolean} [isStatement] - Node is a statement
|
|
106
|
+
* @property {boolean} [isLogicalAndOr] - Node is logical AND/OR expression
|
|
107
|
+
* @property {boolean} [allowShorthandProperty] - Allow shorthand property syntax
|
|
108
|
+
* @property {boolean} [isFirstChild] - Node is first child of parent
|
|
109
|
+
* @property {boolean} [skipComponentLabel] - Skip component label in printing
|
|
110
|
+
* @property {boolean} [noBreakInside] - Don't break inside the expression
|
|
111
|
+
* @property {boolean} [expandLastArg] - Expand the last argument
|
|
112
|
+
*/
|
|
113
|
+
|
|
2
114
|
import { parse } from 'ripple/compiler';
|
|
3
|
-
import { obfuscate_identifier } from 'ripple/compiler/internal/identifier/utils';
|
|
4
115
|
import { doc } from 'prettier';
|
|
5
116
|
|
|
6
117
|
const { builders, utils } = doc;
|
|
7
118
|
const {
|
|
8
|
-
concat,
|
|
9
119
|
join,
|
|
10
120
|
line,
|
|
11
121
|
softline,
|
|
@@ -22,6 +132,7 @@ const {
|
|
|
22
132
|
} = builders;
|
|
23
133
|
const { willBreak } = utils;
|
|
24
134
|
|
|
135
|
+
/** @type {import('prettier').Plugin['languages']} */
|
|
25
136
|
export const languages = [
|
|
26
137
|
{
|
|
27
138
|
name: 'ripple',
|
|
@@ -31,25 +142,47 @@ export const languages = [
|
|
|
31
142
|
},
|
|
32
143
|
];
|
|
33
144
|
|
|
145
|
+
/** @type {import('prettier').Plugin['parsers']} */
|
|
34
146
|
export const parsers = {
|
|
35
147
|
ripple: {
|
|
36
148
|
astFormat: 'ripple-ast',
|
|
37
|
-
|
|
149
|
+
/**
|
|
150
|
+
* @param {string} text
|
|
151
|
+
* @param {ParserOptions<RippleASTNode>} _options
|
|
152
|
+
* @returns {Program}
|
|
153
|
+
*/
|
|
154
|
+
parse(text, _options) {
|
|
38
155
|
return parse(text);
|
|
39
156
|
},
|
|
40
157
|
|
|
158
|
+
/**
|
|
159
|
+
* @param {RippleASTNode} node
|
|
160
|
+
* @returns {number}
|
|
161
|
+
*/
|
|
41
162
|
locStart(node) {
|
|
42
163
|
return node.loc.start.index;
|
|
43
164
|
},
|
|
44
165
|
|
|
166
|
+
/**
|
|
167
|
+
* @param {RippleASTNode} node
|
|
168
|
+
* @returns {number}
|
|
169
|
+
*/
|
|
45
170
|
locEnd(node) {
|
|
46
171
|
return node.loc.end.index;
|
|
47
172
|
},
|
|
48
173
|
},
|
|
49
174
|
};
|
|
50
175
|
|
|
176
|
+
/** @type {import('prettier').Plugin['printers']} */
|
|
51
177
|
export const printers = {
|
|
52
178
|
'ripple-ast': {
|
|
179
|
+
/**
|
|
180
|
+
* @param {AstPath<RippleASTNode>} path
|
|
181
|
+
* @param {RippleFormatOptions} options
|
|
182
|
+
* @param {PrintFn} print
|
|
183
|
+
* @param {PrintArgs} [args]
|
|
184
|
+
* @returns {Doc}
|
|
185
|
+
*/
|
|
53
186
|
print(path, options, print, args) {
|
|
54
187
|
const node = path.getValue();
|
|
55
188
|
const parts = printRippleNode(node, path, options, print, args);
|
|
@@ -57,11 +190,15 @@ export const printers = {
|
|
|
57
190
|
// If it returns a string, wrap it for consistency
|
|
58
191
|
// If it returns an array, concatenate it
|
|
59
192
|
if (Array.isArray(parts)) {
|
|
60
|
-
return
|
|
193
|
+
return parts;
|
|
61
194
|
}
|
|
62
195
|
return typeof parts === 'string' ? parts : parts;
|
|
63
196
|
},
|
|
64
|
-
|
|
197
|
+
/**
|
|
198
|
+
* @param {AstPath<RippleASTNode>} path
|
|
199
|
+
* @returns {((textToDoc: (text: string, options: object) => Promise<Doc>) => Promise<Doc>) | null}
|
|
200
|
+
*/
|
|
201
|
+
embed(path) {
|
|
65
202
|
const node = path.getValue();
|
|
66
203
|
|
|
67
204
|
// Handle StyleSheet nodes inside style tags
|
|
@@ -107,6 +244,10 @@ export const printers = {
|
|
|
107
244
|
|
|
108
245
|
return null;
|
|
109
246
|
},
|
|
247
|
+
/**
|
|
248
|
+
* @param {RippleASTNode} node
|
|
249
|
+
* @returns {string[]}
|
|
250
|
+
*/
|
|
110
251
|
getVisitorKeys(node) {
|
|
111
252
|
// Exclude metadata and raw text properties that shouldn't be traversed
|
|
112
253
|
// The css property is specifically excluded so embed() can handle it
|
|
@@ -133,7 +274,12 @@ export const printers = {
|
|
|
133
274
|
},
|
|
134
275
|
};
|
|
135
276
|
|
|
136
|
-
|
|
277
|
+
/**
|
|
278
|
+
* Format a string literal according to Prettier options
|
|
279
|
+
* @param {string} value - The string value to format
|
|
280
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
281
|
+
* @returns {string} - The formatted string literal with quotes
|
|
282
|
+
*/
|
|
137
283
|
function formatStringLiteral(value, options) {
|
|
138
284
|
if (typeof value !== 'string') {
|
|
139
285
|
return JSON.stringify(value);
|
|
@@ -150,20 +296,20 @@ function formatStringLiteral(value, options) {
|
|
|
150
296
|
return quote + escapedValue + quote;
|
|
151
297
|
}
|
|
152
298
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
return ' '.repeat((options.tabWidth || 2) * level);
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
// Helper function to add semicolons based on options.semi setting
|
|
299
|
+
/**
|
|
300
|
+
* Add semicolon based on options.semi setting
|
|
301
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
302
|
+
* @returns {string} - Semicolon or empty string
|
|
303
|
+
*/
|
|
163
304
|
function semi(options) {
|
|
164
305
|
return options.semi !== false ? ';' : '';
|
|
165
306
|
}
|
|
166
307
|
|
|
308
|
+
/**
|
|
309
|
+
* Check if a node was originally on a single line in source
|
|
310
|
+
* @param {RippleASTNode} node - The AST node to check
|
|
311
|
+
* @returns {boolean} - True if the node was on a single line
|
|
312
|
+
*/
|
|
167
313
|
function wasOriginallySingleLine(node) {
|
|
168
314
|
if (!node || !node.loc || !node.loc.start || !node.loc.end) {
|
|
169
315
|
return false;
|
|
@@ -172,16 +318,32 @@ function wasOriginallySingleLine(node) {
|
|
|
172
318
|
return node.loc.start.line === node.loc.end.line;
|
|
173
319
|
}
|
|
174
320
|
|
|
321
|
+
/**
|
|
322
|
+
* Check if an object expression was originally single line
|
|
323
|
+
* @param {RippleASTNode} node - The object expression node
|
|
324
|
+
* @returns {boolean} - True if single line
|
|
325
|
+
*/
|
|
175
326
|
function isSingleLineObjectExpression(node) {
|
|
176
327
|
return wasOriginallySingleLine(node);
|
|
177
328
|
}
|
|
178
329
|
|
|
179
|
-
|
|
330
|
+
/**
|
|
331
|
+
* Check if a node has any comments (leading, trailing, or inner)
|
|
332
|
+
* @param {RippleASTNode} node - The AST node to check
|
|
333
|
+
* @returns {boolean} - True if the node has comments
|
|
334
|
+
*/
|
|
180
335
|
function hasComment(node) {
|
|
181
336
|
return !!(node.leadingComments || node.trailingComments || node.innerComments);
|
|
182
337
|
}
|
|
183
338
|
|
|
339
|
+
/**
|
|
340
|
+
* Get all function parameters including `this`, params, and rest.
|
|
341
|
+
* TypeScript/Ripple functions can have additional `this` and `rest` parameters.
|
|
342
|
+
* @param {RippleASTNode} node - The function node
|
|
343
|
+
* @returns {Array<RippleASTNode>} - Array of parameter patterns
|
|
344
|
+
*/
|
|
184
345
|
function getFunctionParameters(node) {
|
|
346
|
+
/** @type {Array<RippleASTNode>} */
|
|
185
347
|
const parameters = [];
|
|
186
348
|
if (node.this) {
|
|
187
349
|
parameters.push(node.this);
|
|
@@ -195,9 +357,17 @@ function getFunctionParameters(node) {
|
|
|
195
357
|
return parameters;
|
|
196
358
|
}
|
|
197
359
|
|
|
360
|
+
/**
|
|
361
|
+
* Iterate over function parameters with path callbacks.
|
|
362
|
+
* TypeScript/Ripple functions can have additional `this` and `rest` parameters.
|
|
363
|
+
* @param {AstPath<RippleASTNode>} path - The function path
|
|
364
|
+
* @param {(paramPath: AstPath<RippleASTNode>, index: number) => void} iteratee - Callback for each parameter
|
|
365
|
+
*/
|
|
198
366
|
function iterateFunctionParametersPath(path, iteratee) {
|
|
199
|
-
|
|
367
|
+
/** @type {RippleASTNode} */
|
|
368
|
+
const node = path.node;
|
|
200
369
|
let index = 0;
|
|
370
|
+
/** @type {(paramPath: AstPath<RippleASTNode>) => void} */
|
|
201
371
|
const callback = (paramPath) => iteratee(paramPath, index++);
|
|
202
372
|
|
|
203
373
|
if (node.this) {
|
|
@@ -212,6 +382,7 @@ function iterateFunctionParametersPath(path, iteratee) {
|
|
|
212
382
|
}
|
|
213
383
|
|
|
214
384
|
// Operator precedence (higher number = higher precedence)
|
|
385
|
+
/** @type {Record<string, number>} */
|
|
215
386
|
const PRECEDENCE = {
|
|
216
387
|
'||': 1,
|
|
217
388
|
'&&': 2,
|
|
@@ -239,11 +410,21 @@ const PRECEDENCE = {
|
|
|
239
410
|
'**': 11,
|
|
240
411
|
};
|
|
241
412
|
|
|
413
|
+
/**
|
|
414
|
+
* Get operator precedence for binary/logical expressions
|
|
415
|
+
* @param {string} operator - The operator string
|
|
416
|
+
* @returns {number} - Precedence level (higher = binds tighter)
|
|
417
|
+
*/
|
|
242
418
|
function getPrecedence(operator) {
|
|
243
419
|
return PRECEDENCE[operator] || 0;
|
|
244
420
|
}
|
|
245
421
|
|
|
246
|
-
|
|
422
|
+
/**
|
|
423
|
+
* Check if a BinaryExpression needs parentheses
|
|
424
|
+
* @param {RippleASTNode} node - The expression node
|
|
425
|
+
* @param {RippleASTNode} parent - The parent node
|
|
426
|
+
* @returns {boolean} - True if parentheses are needed
|
|
427
|
+
*/
|
|
247
428
|
function binaryExpressionNeedsParens(node, parent) {
|
|
248
429
|
if (!node.metadata?.parenthesized) {
|
|
249
430
|
return false;
|
|
@@ -284,6 +465,11 @@ function binaryExpressionNeedsParens(node, parent) {
|
|
|
284
465
|
return false;
|
|
285
466
|
}
|
|
286
467
|
|
|
468
|
+
/**
|
|
469
|
+
* Create a function that skips specified characters in text
|
|
470
|
+
* @param {string | RegExp} characters - Characters to skip
|
|
471
|
+
* @returns {(text: string, startIndex: number | false, options?: { backwards?: boolean }) => number | false}
|
|
472
|
+
*/
|
|
287
473
|
function createSkip(characters) {
|
|
288
474
|
return (text, startIndex, options) => {
|
|
289
475
|
const backwards = Boolean(options && options.backwards);
|
|
@@ -318,16 +504,32 @@ const skipSpaces = createSkip(' \t');
|
|
|
318
504
|
const skipToLineEnd = createSkip(',; \t');
|
|
319
505
|
const skipEverythingButNewLine = createSkip(/[^\n\r\u2028\u2029]/u);
|
|
320
506
|
|
|
507
|
+
/**
|
|
508
|
+
* Check if a character is a newline
|
|
509
|
+
* @param {string} character - Single character to check
|
|
510
|
+
* @returns {boolean}
|
|
511
|
+
*/
|
|
321
512
|
function isCharNewLine(character) {
|
|
322
513
|
return (
|
|
323
514
|
character === '\n' || character === '\r' || character === '\u2028' || character === '\u2029'
|
|
324
515
|
);
|
|
325
516
|
}
|
|
326
517
|
|
|
518
|
+
/**
|
|
519
|
+
* Check if a character is whitespace (space or tab)
|
|
520
|
+
* @param {string} character - Single character to check
|
|
521
|
+
* @returns {boolean}
|
|
522
|
+
*/
|
|
327
523
|
function isCharSpace(character) {
|
|
328
524
|
return character === ' ' || character === '\t';
|
|
329
525
|
}
|
|
330
526
|
|
|
527
|
+
/**
|
|
528
|
+
* Skip over an inline comment (/* ... * /)
|
|
529
|
+
* @param {string} text - Source text
|
|
530
|
+
* @param {number | false} startIndex - Starting position
|
|
531
|
+
* @returns {number | false} - Position after comment or original position
|
|
532
|
+
*/
|
|
331
533
|
function skipInlineComment(text, startIndex) {
|
|
332
534
|
if (startIndex === false) {
|
|
333
535
|
return false;
|
|
@@ -344,6 +546,13 @@ function skipInlineComment(text, startIndex) {
|
|
|
344
546
|
return startIndex;
|
|
345
547
|
}
|
|
346
548
|
|
|
549
|
+
/**
|
|
550
|
+
* Skip over a newline character
|
|
551
|
+
* @param {string} text - Source text
|
|
552
|
+
* @param {number | false} startIndex - Starting position
|
|
553
|
+
* @param {{ backwards?: boolean }} [options] - Direction options
|
|
554
|
+
* @returns {number | false} - Position after newline or original position
|
|
555
|
+
*/
|
|
347
556
|
function skipNewline(text, startIndex, options) {
|
|
348
557
|
const backwards = Boolean(options && options.backwards);
|
|
349
558
|
if (startIndex === false) {
|
|
@@ -370,6 +579,12 @@ function skipNewline(text, startIndex, options) {
|
|
|
370
579
|
return startIndex;
|
|
371
580
|
}
|
|
372
581
|
|
|
582
|
+
/**
|
|
583
|
+
* Skip over a trailing comment (// ...)
|
|
584
|
+
* @param {string} text - Source text
|
|
585
|
+
* @param {number | false} startIndex - Starting position
|
|
586
|
+
* @returns {number | false} - Position after comment or original position
|
|
587
|
+
*/
|
|
373
588
|
function skipTrailingComment(text, startIndex) {
|
|
374
589
|
if (startIndex === false) {
|
|
375
590
|
return false;
|
|
@@ -382,6 +597,11 @@ function skipTrailingComment(text, startIndex) {
|
|
|
382
597
|
return startIndex;
|
|
383
598
|
}
|
|
384
599
|
|
|
600
|
+
/**
|
|
601
|
+
* Get the end index of a node from various possible properties
|
|
602
|
+
* @param {RippleASTNode} node - The AST node
|
|
603
|
+
* @returns {number | null} - End position or null
|
|
604
|
+
*/
|
|
385
605
|
function getNodeEndIndex(node) {
|
|
386
606
|
if (node?.loc?.end && typeof node.loc.end.index === 'number') {
|
|
387
607
|
return node.loc.end.index;
|
|
@@ -395,6 +615,11 @@ function getNodeEndIndex(node) {
|
|
|
395
615
|
return null;
|
|
396
616
|
}
|
|
397
617
|
|
|
618
|
+
/**
|
|
619
|
+
* Check if a node is a RegExp literal
|
|
620
|
+
* @param {RippleASTNode} node - The AST node
|
|
621
|
+
* @returns {boolean}
|
|
622
|
+
*/
|
|
398
623
|
function isRegExpLiteral(node) {
|
|
399
624
|
return (
|
|
400
625
|
node &&
|
|
@@ -406,6 +631,12 @@ function isRegExpLiteral(node) {
|
|
|
406
631
|
);
|
|
407
632
|
}
|
|
408
633
|
|
|
634
|
+
/**
|
|
635
|
+
* Check if a comment is followed by a paren on the same line
|
|
636
|
+
* @param {Comment} comment - The comment node
|
|
637
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
638
|
+
* @returns {boolean}
|
|
639
|
+
*/
|
|
409
640
|
function isCommentFollowedBySameLineParen(comment, options) {
|
|
410
641
|
if (!comment || !options || typeof options.originalText !== 'string') {
|
|
411
642
|
return false;
|
|
@@ -432,12 +663,25 @@ function isCommentFollowedBySameLineParen(comment, options) {
|
|
|
432
663
|
return false;
|
|
433
664
|
}
|
|
434
665
|
|
|
666
|
+
/**
|
|
667
|
+
* Check if there is a newline at the given position
|
|
668
|
+
* @param {string} text - Source text
|
|
669
|
+
* @param {number} startIndex - Starting position
|
|
670
|
+
* @param {{ backwards?: boolean }} [options] - Direction options
|
|
671
|
+
* @returns {boolean}
|
|
672
|
+
*/
|
|
435
673
|
function hasNewline(text, startIndex, options) {
|
|
436
674
|
const idx = skipSpaces(text, options && options.backwards ? startIndex - 1 : startIndex, options);
|
|
437
675
|
const idx2 = skipNewline(text, idx, options);
|
|
438
676
|
return idx !== idx2;
|
|
439
677
|
}
|
|
440
678
|
|
|
679
|
+
/**
|
|
680
|
+
* Check if the next line after a node is empty
|
|
681
|
+
* @param {RippleASTNode} node - The AST node
|
|
682
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
683
|
+
* @returns {boolean}
|
|
684
|
+
*/
|
|
441
685
|
function isNextLineEmpty(node, options) {
|
|
442
686
|
if (!node || !options || !options.originalText) {
|
|
443
687
|
return false;
|
|
@@ -483,10 +727,21 @@ function isNextLineEmpty(node, options) {
|
|
|
483
727
|
return index !== false && hasNewline(text, index);
|
|
484
728
|
}
|
|
485
729
|
|
|
730
|
+
/**
|
|
731
|
+
* Check if a function has a rest parameter
|
|
732
|
+
* @param {RippleASTNode} node - The function node
|
|
733
|
+
* @returns {boolean}
|
|
734
|
+
*/
|
|
486
735
|
function hasRestParameter(node) {
|
|
487
736
|
return !!node.rest;
|
|
488
737
|
}
|
|
489
738
|
|
|
739
|
+
/**
|
|
740
|
+
* Determine if a trailing comma should be printed based on options
|
|
741
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
742
|
+
* @param {'es5' | 'all'} [level='all'] - Comma level to check
|
|
743
|
+
* @returns {boolean}
|
|
744
|
+
*/
|
|
490
745
|
function shouldPrintComma(options, level = 'all') {
|
|
491
746
|
switch (options.trailingComma) {
|
|
492
747
|
case 'none':
|
|
@@ -500,6 +755,13 @@ function shouldPrintComma(options, level = 'all') {
|
|
|
500
755
|
}
|
|
501
756
|
}
|
|
502
757
|
|
|
758
|
+
/**
|
|
759
|
+
* Check if a leading comment can be attached to the previous element
|
|
760
|
+
* @param {RippleASTNode} comment - The comment node
|
|
761
|
+
* @param {RippleASTNode} previousNode - Previous node
|
|
762
|
+
* @param {RippleASTNode} nextNode - Next node
|
|
763
|
+
* @returns {boolean}
|
|
764
|
+
*/
|
|
503
765
|
function canAttachLeadingCommentToPreviousElement(comment, previousNode, nextNode) {
|
|
504
766
|
if (!comment || !previousNode || !nextNode) {
|
|
505
767
|
return false;
|
|
@@ -525,6 +787,11 @@ function canAttachLeadingCommentToPreviousElement(comment, previousNode, nextNod
|
|
|
525
787
|
return true;
|
|
526
788
|
}
|
|
527
789
|
|
|
790
|
+
/**
|
|
791
|
+
* Build doc for inline array comments
|
|
792
|
+
* @param {RippleASTNode[]} comments - Array of comment nodes
|
|
793
|
+
* @returns {Doc | null}
|
|
794
|
+
*/
|
|
528
795
|
function buildInlineArrayCommentDoc(comments) {
|
|
529
796
|
if (!Array.isArray(comments) || comments.length === 0) {
|
|
530
797
|
return null;
|
|
@@ -547,11 +814,16 @@ function buildInlineArrayCommentDoc(comments) {
|
|
|
547
814
|
}
|
|
548
815
|
}
|
|
549
816
|
|
|
550
|
-
return docs.length > 0 ?
|
|
817
|
+
return docs.length > 0 ? docs : null;
|
|
551
818
|
}
|
|
552
819
|
|
|
553
820
|
/**
|
|
554
|
-
*
|
|
821
|
+
* Print an object or method key
|
|
822
|
+
* @param {Property | MethodDefinition} node - The property or method node
|
|
823
|
+
* @param {AstPath<RippleASTNode>} path - The AST path
|
|
824
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
825
|
+
* @param {PrintFn} print - Print callback
|
|
826
|
+
* @returns {Doc[]}
|
|
555
827
|
*/
|
|
556
828
|
function printKey(node, path, options, print) {
|
|
557
829
|
const parts = [];
|
|
@@ -580,6 +852,15 @@ function printKey(node, path, options, print) {
|
|
|
580
852
|
return parts;
|
|
581
853
|
}
|
|
582
854
|
|
|
855
|
+
/**
|
|
856
|
+
* Main print function for Ripple AST nodes
|
|
857
|
+
* @param {RippleASTNode} node - The AST node to print
|
|
858
|
+
* @param {AstPath<RippleASTNode>} path - The AST path
|
|
859
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
860
|
+
* @param {PrintFn} print - Print callback
|
|
861
|
+
* @param {PrintArgs} [args] - Additional context arguments
|
|
862
|
+
* @returns {Doc}
|
|
863
|
+
*/
|
|
583
864
|
function printRippleNode(node, path, options, print, args) {
|
|
584
865
|
if (!node || typeof node !== 'object') {
|
|
585
866
|
return String(node || '');
|
|
@@ -678,7 +959,7 @@ function printRippleNode(node, path, options, print, args) {
|
|
|
678
959
|
const statement = path.call(print, 'body', i);
|
|
679
960
|
// If statement is an array, flatten it
|
|
680
961
|
if (Array.isArray(statement)) {
|
|
681
|
-
statements.push(
|
|
962
|
+
statements.push(statement);
|
|
682
963
|
} else {
|
|
683
964
|
statements.push(statement);
|
|
684
965
|
}
|
|
@@ -690,7 +971,7 @@ function printRippleNode(node, path, options, print, args) {
|
|
|
690
971
|
|
|
691
972
|
// Only add spacing when explicitly needed
|
|
692
973
|
if (shouldAddBlankLine(currentStmt, nextStmt)) {
|
|
693
|
-
statements.push(
|
|
974
|
+
statements.push([line, line]); // blank line
|
|
694
975
|
} else {
|
|
695
976
|
statements.push(line); // single line break
|
|
696
977
|
}
|
|
@@ -700,9 +981,9 @@ function printRippleNode(node, path, options, print, args) {
|
|
|
700
981
|
// Prettier always adds a trailing newline to files
|
|
701
982
|
// Add it unless the code is completely empty
|
|
702
983
|
if (statements.length > 0) {
|
|
703
|
-
nodeContent =
|
|
984
|
+
nodeContent = [...statements, hardline];
|
|
704
985
|
} else {
|
|
705
|
-
nodeContent =
|
|
986
|
+
nodeContent = statements;
|
|
706
987
|
}
|
|
707
988
|
break;
|
|
708
989
|
}
|
|
@@ -727,6 +1008,10 @@ function printRippleNode(node, path, options, print, args) {
|
|
|
727
1008
|
nodeContent = printFunctionDeclaration(node, path, options, print);
|
|
728
1009
|
break;
|
|
729
1010
|
|
|
1011
|
+
case 'TSDeclareFunction':
|
|
1012
|
+
nodeContent = printTSDeclareFunction(node, path, options, print);
|
|
1013
|
+
break;
|
|
1014
|
+
|
|
730
1015
|
case 'IfStatement':
|
|
731
1016
|
nodeContent = printIfStatement(node, path, options, print);
|
|
732
1017
|
break;
|
|
@@ -796,8 +1081,9 @@ function printRippleNode(node, path, options, print, args) {
|
|
|
796
1081
|
continue;
|
|
797
1082
|
}
|
|
798
1083
|
|
|
799
|
-
const canTransferAllLeadingComments = nextElement.leadingComments.every(
|
|
800
|
-
|
|
1084
|
+
const canTransferAllLeadingComments = nextElement.leadingComments.every(
|
|
1085
|
+
(/** @type {RippleASTNode} */ comment) =>
|
|
1086
|
+
canAttachLeadingCommentToPreviousElement(comment, currentElement, nextElement),
|
|
801
1087
|
);
|
|
802
1088
|
|
|
803
1089
|
if (!canTransferAllLeadingComments) {
|
|
@@ -813,14 +1099,20 @@ function printRippleNode(node, path, options, print, args) {
|
|
|
813
1099
|
|
|
814
1100
|
// Check if all elements are objects with multiple properties
|
|
815
1101
|
// In that case, each object should be on its own line
|
|
816
|
-
const objectElements = node.elements.filter(
|
|
1102
|
+
const objectElements = node.elements.filter(
|
|
1103
|
+
(/** @type {RippleASTNode} */ el) => el && el.type === 'ObjectExpression',
|
|
1104
|
+
);
|
|
817
1105
|
const allElementsAreObjects =
|
|
818
1106
|
node.elements.length > 0 &&
|
|
819
|
-
node.elements.every(
|
|
1107
|
+
node.elements.every(
|
|
1108
|
+
(/** @type {RippleASTNode} */ el) => el && el.type === 'ObjectExpression',
|
|
1109
|
+
);
|
|
820
1110
|
const allObjectsHaveMultipleProperties =
|
|
821
1111
|
allElementsAreObjects &&
|
|
822
1112
|
objectElements.length > 0 &&
|
|
823
|
-
objectElements.every(
|
|
1113
|
+
objectElements.every(
|
|
1114
|
+
(/** @type {RippleASTNode} */ obj) => obj.properties && obj.properties.length > 1,
|
|
1115
|
+
);
|
|
824
1116
|
|
|
825
1117
|
// For arrays of simple objects with only a few properties, try to keep compact
|
|
826
1118
|
// But NOT if all objects have multiple properties
|
|
@@ -879,16 +1171,14 @@ function printRippleNode(node, path, options, print, args) {
|
|
|
879
1171
|
);
|
|
880
1172
|
|
|
881
1173
|
if (hasObjectElements && shouldInlineObjects && arrayWasSingleLine) {
|
|
882
|
-
const separator =
|
|
1174
|
+
const separator = [',', line];
|
|
883
1175
|
const trailing = shouldUseTrailingComma ? ifBreak(',', '') : '';
|
|
884
|
-
nodeContent = group(
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
]),
|
|
891
|
-
);
|
|
1176
|
+
nodeContent = group([
|
|
1177
|
+
prefix + '[',
|
|
1178
|
+
indent([softline, join(separator, elements), trailing]),
|
|
1179
|
+
softline,
|
|
1180
|
+
']',
|
|
1181
|
+
]);
|
|
892
1182
|
break;
|
|
893
1183
|
}
|
|
894
1184
|
|
|
@@ -962,7 +1252,7 @@ function printRippleNode(node, path, options, print, args) {
|
|
|
962
1252
|
// Check if any elements contain hard breaks (like multiline ternaries)
|
|
963
1253
|
// Don't check willBreak() as that includes soft breaks from groups
|
|
964
1254
|
// Only check for actual multiline content that forces breaking
|
|
965
|
-
const hasHardBreakingElements = node.elements.some((el) => {
|
|
1255
|
+
const hasHardBreakingElements = node.elements.some((/** @type {RippleASTNode} */ el) => {
|
|
966
1256
|
if (!el) return false;
|
|
967
1257
|
// Multiline ternaries are the main case that should force all elements on separate lines
|
|
968
1258
|
return el.type === 'ConditionalExpression';
|
|
@@ -981,16 +1271,14 @@ function printRippleNode(node, path, options, print, args) {
|
|
|
981
1271
|
!hasBlankLineBeforeClosing &&
|
|
982
1272
|
!hasInlineComments
|
|
983
1273
|
) {
|
|
984
|
-
const separator =
|
|
1274
|
+
const separator = [',', hardline];
|
|
985
1275
|
const trailingDoc = shouldUseTrailingComma ? ',' : '';
|
|
986
|
-
nodeContent = group(
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
]),
|
|
993
|
-
);
|
|
1276
|
+
nodeContent = group([
|
|
1277
|
+
prefix + '[',
|
|
1278
|
+
indent([hardline, join(separator, elements), trailingDoc]),
|
|
1279
|
+
hardline,
|
|
1280
|
+
']',
|
|
1281
|
+
]);
|
|
994
1282
|
break;
|
|
995
1283
|
}
|
|
996
1284
|
|
|
@@ -1025,20 +1313,20 @@ function printRippleNode(node, path, options, print, args) {
|
|
|
1025
1313
|
}
|
|
1026
1314
|
}
|
|
1027
1315
|
}
|
|
1028
|
-
const commentDocNoSpace = commentParts.length > 0 ?
|
|
1316
|
+
const commentDocNoSpace = commentParts.length > 0 ? commentParts : '';
|
|
1029
1317
|
|
|
1030
1318
|
// Provide conditional rendering: inline if it fits, otherwise on separate line
|
|
1031
1319
|
fillParts.push(
|
|
1032
1320
|
conditionalGroup([
|
|
1033
1321
|
// Try inline first (with space before comment)
|
|
1034
|
-
|
|
1322
|
+
[elements[index], ',', inlineCommentDoc, hardline],
|
|
1035
1323
|
// If doesn't fit, put comment on next line (without leading space)
|
|
1036
|
-
|
|
1324
|
+
[elements[index], ',', hardline, commentDocNoSpace, hardline],
|
|
1037
1325
|
]),
|
|
1038
1326
|
);
|
|
1039
1327
|
skipNextSeparator = true;
|
|
1040
1328
|
} else {
|
|
1041
|
-
fillParts.push(group(
|
|
1329
|
+
fillParts.push(group([elements[index], ',']));
|
|
1042
1330
|
skipNextSeparator = false;
|
|
1043
1331
|
}
|
|
1044
1332
|
} else {
|
|
@@ -1048,34 +1336,30 @@ function printRippleNode(node, path, options, print, args) {
|
|
|
1048
1336
|
}
|
|
1049
1337
|
|
|
1050
1338
|
const trailingDoc = shouldUseTrailingComma ? ifBreak(',', '') : '';
|
|
1051
|
-
nodeContent = group(
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
]),
|
|
1058
|
-
);
|
|
1339
|
+
nodeContent = group([
|
|
1340
|
+
prefix + '[',
|
|
1341
|
+
indent([softline, fill(fillParts), trailingDoc]),
|
|
1342
|
+
softline,
|
|
1343
|
+
']',
|
|
1344
|
+
]);
|
|
1059
1345
|
break;
|
|
1060
1346
|
}
|
|
1061
1347
|
|
|
1062
1348
|
// If array has breaking elements (multiline ternaries, functions, etc.)
|
|
1063
1349
|
// use join() to put each element on its own line, per Prettier spec
|
|
1064
1350
|
if (hasHardBreakingElements) {
|
|
1065
|
-
const separator =
|
|
1351
|
+
const separator = [',', line];
|
|
1066
1352
|
const parts = [];
|
|
1067
1353
|
for (let index = 0; index < elements.length; index++) {
|
|
1068
1354
|
parts.push(elements[index]);
|
|
1069
1355
|
}
|
|
1070
1356
|
const trailingDoc = shouldUseTrailingComma ? ifBreak(',', '') : '';
|
|
1071
|
-
nodeContent = group(
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
]),
|
|
1078
|
-
);
|
|
1357
|
+
nodeContent = group([
|
|
1358
|
+
prefix + '[',
|
|
1359
|
+
indent([softline, join(separator, parts), trailingDoc]),
|
|
1360
|
+
softline,
|
|
1361
|
+
']',
|
|
1362
|
+
]);
|
|
1079
1363
|
break;
|
|
1080
1364
|
}
|
|
1081
1365
|
|
|
@@ -1092,16 +1376,14 @@ function printRippleNode(node, path, options, print, args) {
|
|
|
1092
1376
|
allowInlineObject: wasObjSingleLine,
|
|
1093
1377
|
});
|
|
1094
1378
|
}, 'elements');
|
|
1095
|
-
const separator =
|
|
1379
|
+
const separator = [',', hardline];
|
|
1096
1380
|
const trailingDoc = shouldUseTrailingComma ? ifBreak(',', '') : '';
|
|
1097
|
-
nodeContent = group(
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
]),
|
|
1104
|
-
);
|
|
1381
|
+
nodeContent = group([
|
|
1382
|
+
prefix + '[',
|
|
1383
|
+
indent([hardline, join(separator, inlineElements), trailingDoc]),
|
|
1384
|
+
hardline,
|
|
1385
|
+
']',
|
|
1386
|
+
]);
|
|
1105
1387
|
break;
|
|
1106
1388
|
}
|
|
1107
1389
|
|
|
@@ -1110,7 +1392,9 @@ function printRippleNode(node, path, options, print, args) {
|
|
|
1110
1392
|
const contentParts = [];
|
|
1111
1393
|
|
|
1112
1394
|
// Split elements into groups separated by blank lines
|
|
1395
|
+
/** @type {number[][]} */
|
|
1113
1396
|
const groups = [];
|
|
1397
|
+
/** @type {number[]} */
|
|
1114
1398
|
let currentGroup = [];
|
|
1115
1399
|
|
|
1116
1400
|
for (let i = 0; i < elements.length; i++) {
|
|
@@ -1156,7 +1440,7 @@ function printRippleNode(node, path, options, print, args) {
|
|
|
1156
1440
|
if (isLastInArray && shouldUseTrailingComma) {
|
|
1157
1441
|
fillParts.push(group(elements[elemIdx]));
|
|
1158
1442
|
} else {
|
|
1159
|
-
fillParts.push(group(
|
|
1443
|
+
fillParts.push(group([elements[elemIdx], ',']));
|
|
1160
1444
|
}
|
|
1161
1445
|
}
|
|
1162
1446
|
|
|
@@ -1170,9 +1454,7 @@ function printRippleNode(node, path, options, print, args) {
|
|
|
1170
1454
|
|
|
1171
1455
|
// Array with blank lines - format as multi-line
|
|
1172
1456
|
// Use simple group that will break to fit within printWidth
|
|
1173
|
-
nodeContent = group(
|
|
1174
|
-
concat([prefix + '[', indent(concat([line, concat(contentParts)])), line, ']']),
|
|
1175
|
-
);
|
|
1457
|
+
nodeContent = group([prefix + '[', indent([line, contentParts]), line, ']']);
|
|
1176
1458
|
break;
|
|
1177
1459
|
}
|
|
1178
1460
|
|
|
@@ -1202,7 +1484,7 @@ function printRippleNode(node, path, options, print, args) {
|
|
|
1202
1484
|
let leftPart = path.call((p) => print(p, { noBreakInside: true }), 'left');
|
|
1203
1485
|
// Preserve parentheses around the left side when present
|
|
1204
1486
|
if (node.left.metadata?.parenthesized) {
|
|
1205
|
-
leftPart =
|
|
1487
|
+
leftPart = ['(', leftPart, ')'];
|
|
1206
1488
|
}
|
|
1207
1489
|
// For CallExpression on the right with JSDoc comments, use fluid layout strategy
|
|
1208
1490
|
const rightSide = path.call(print, 'right');
|
|
@@ -1254,7 +1536,7 @@ function printRippleNode(node, path, options, print, args) {
|
|
|
1254
1536
|
const argsDoc = printCallArguments(path, options, print);
|
|
1255
1537
|
parts.push(argsDoc);
|
|
1256
1538
|
|
|
1257
|
-
let callContent =
|
|
1539
|
+
let callContent = parts;
|
|
1258
1540
|
|
|
1259
1541
|
// Preserve parentheses for type-annotated call expressions
|
|
1260
1542
|
// When parenthesized with leading comments, use grouping to allow breaking
|
|
@@ -1262,11 +1544,11 @@ function printRippleNode(node, path, options, print, args) {
|
|
|
1262
1544
|
const hasLeadingComments = node.leadingComments && node.leadingComments.length > 0;
|
|
1263
1545
|
if (hasLeadingComments) {
|
|
1264
1546
|
// Group with softline to allow breaking after opening paren
|
|
1265
|
-
callContent =
|
|
1266
|
-
|
|
1267
|
-
);
|
|
1547
|
+
callContent = /** @type {Doc[]} */ ([
|
|
1548
|
+
group(['(', indent([softline, callContent]), softline, ')']),
|
|
1549
|
+
]);
|
|
1268
1550
|
} else {
|
|
1269
|
-
callContent =
|
|
1551
|
+
callContent = ['(', callContent, ')'];
|
|
1270
1552
|
}
|
|
1271
1553
|
}
|
|
1272
1554
|
nodeContent = callContent;
|
|
@@ -1275,13 +1557,13 @@ function printRippleNode(node, path, options, print, args) {
|
|
|
1275
1557
|
|
|
1276
1558
|
case 'AwaitExpression': {
|
|
1277
1559
|
const parts = ['await ', path.call(print, 'argument')];
|
|
1278
|
-
nodeContent =
|
|
1560
|
+
nodeContent = parts;
|
|
1279
1561
|
break;
|
|
1280
1562
|
}
|
|
1281
1563
|
|
|
1282
1564
|
case 'TrackedExpression': {
|
|
1283
1565
|
const parts = ['@(', path.call(print, 'argument'), ')'];
|
|
1284
|
-
nodeContent =
|
|
1566
|
+
nodeContent = parts;
|
|
1285
1567
|
break;
|
|
1286
1568
|
}
|
|
1287
1569
|
|
|
@@ -1292,7 +1574,7 @@ function printRippleNode(node, path, options, print, args) {
|
|
|
1292
1574
|
nodeContent = '#Map';
|
|
1293
1575
|
} else {
|
|
1294
1576
|
const args = path.map(print, 'arguments');
|
|
1295
|
-
nodeContent =
|
|
1577
|
+
nodeContent = ['#Map(', join([',', line], args), ')'];
|
|
1296
1578
|
}
|
|
1297
1579
|
break;
|
|
1298
1580
|
}
|
|
@@ -1304,7 +1586,7 @@ function printRippleNode(node, path, options, print, args) {
|
|
|
1304
1586
|
nodeContent = '#Set';
|
|
1305
1587
|
} else {
|
|
1306
1588
|
const args = path.map(print, 'arguments');
|
|
1307
|
-
nodeContent =
|
|
1589
|
+
nodeContent = ['#Set(', join([',', line], args), ')'];
|
|
1308
1590
|
}
|
|
1309
1591
|
break;
|
|
1310
1592
|
}
|
|
@@ -1328,27 +1610,23 @@ function printRippleNode(node, path, options, print, args) {
|
|
|
1328
1610
|
break;
|
|
1329
1611
|
|
|
1330
1612
|
case 'TSAsExpression': {
|
|
1331
|
-
nodeContent =
|
|
1332
|
-
path.call(print, 'expression'),
|
|
1333
|
-
' as ',
|
|
1334
|
-
path.call(print, 'typeAnnotation'),
|
|
1335
|
-
]);
|
|
1613
|
+
nodeContent = [path.call(print, 'expression'), ' as ', path.call(print, 'typeAnnotation')];
|
|
1336
1614
|
break;
|
|
1337
1615
|
}
|
|
1338
1616
|
|
|
1339
1617
|
case 'TSNonNullExpression': {
|
|
1340
|
-
nodeContent =
|
|
1618
|
+
nodeContent = [path.call(print, 'expression'), '!'];
|
|
1341
1619
|
break;
|
|
1342
1620
|
}
|
|
1343
1621
|
|
|
1344
1622
|
case 'TSInstantiationExpression': {
|
|
1345
1623
|
// Explicit type instantiation: foo<Type>, identity<string>
|
|
1346
|
-
nodeContent =
|
|
1624
|
+
nodeContent = [path.call(print, 'expression'), path.call(print, 'typeArguments')];
|
|
1347
1625
|
break;
|
|
1348
1626
|
}
|
|
1349
1627
|
|
|
1350
1628
|
case 'JSXExpressionContainer': {
|
|
1351
|
-
nodeContent =
|
|
1629
|
+
nodeContent = ['{', path.call(print, 'expression'), '}'];
|
|
1352
1630
|
break;
|
|
1353
1631
|
}
|
|
1354
1632
|
|
|
@@ -1464,7 +1742,7 @@ function printRippleNode(node, path, options, print, args) {
|
|
|
1464
1742
|
break;
|
|
1465
1743
|
|
|
1466
1744
|
case 'DebuggerStatement':
|
|
1467
|
-
nodeContent = printDebuggerStatement(node, path, options
|
|
1745
|
+
nodeContent = printDebuggerStatement(node, path, options);
|
|
1468
1746
|
break;
|
|
1469
1747
|
|
|
1470
1748
|
case 'SequenceExpression':
|
|
@@ -1478,15 +1756,15 @@ function printRippleNode(node, path, options, print, args) {
|
|
|
1478
1756
|
const needsParens =
|
|
1479
1757
|
node.argument.type === 'LogicalExpression' && node.argument.operator === '??';
|
|
1480
1758
|
if (needsParens) {
|
|
1481
|
-
nodeContent =
|
|
1759
|
+
nodeContent = ['...(', argumentDoc, ')'];
|
|
1482
1760
|
} else {
|
|
1483
|
-
nodeContent =
|
|
1761
|
+
nodeContent = ['...', argumentDoc];
|
|
1484
1762
|
}
|
|
1485
1763
|
break;
|
|
1486
1764
|
}
|
|
1487
1765
|
case 'RestElement': {
|
|
1488
1766
|
const parts = ['...', path.call(print, 'argument')];
|
|
1489
|
-
nodeContent =
|
|
1767
|
+
nodeContent = parts;
|
|
1490
1768
|
break;
|
|
1491
1769
|
}
|
|
1492
1770
|
case 'VariableDeclaration':
|
|
@@ -1499,19 +1777,19 @@ function printRippleNode(node, path, options, print, args) {
|
|
|
1499
1777
|
node.expression.type === 'ObjectExpression' ||
|
|
1500
1778
|
node.expression.type === 'TrackedObjectExpression';
|
|
1501
1779
|
if (needsParens) {
|
|
1502
|
-
nodeContent =
|
|
1780
|
+
nodeContent = ['(', path.call(print, 'expression'), ')', semi(options)];
|
|
1503
1781
|
} else {
|
|
1504
|
-
nodeContent =
|
|
1782
|
+
nodeContent = [path.call(print, 'expression'), semi(options)];
|
|
1505
1783
|
}
|
|
1506
1784
|
break;
|
|
1507
1785
|
}
|
|
1508
1786
|
case 'RefAttribute':
|
|
1509
|
-
nodeContent =
|
|
1787
|
+
nodeContent = ['{ref ', path.call(print, 'argument'), '}'];
|
|
1510
1788
|
break;
|
|
1511
1789
|
|
|
1512
1790
|
case 'SpreadAttribute': {
|
|
1513
1791
|
const parts = ['{...', path.call(print, 'argument'), '}'];
|
|
1514
|
-
nodeContent =
|
|
1792
|
+
nodeContent = parts;
|
|
1515
1793
|
break;
|
|
1516
1794
|
}
|
|
1517
1795
|
|
|
@@ -1521,12 +1799,12 @@ function printRippleNode(node, path, options, print, args) {
|
|
|
1521
1799
|
let identifierContent;
|
|
1522
1800
|
if (node.typeAnnotation) {
|
|
1523
1801
|
const optionalMarker = node.optional ? '?' : '';
|
|
1524
|
-
identifierContent =
|
|
1802
|
+
identifierContent = [
|
|
1525
1803
|
trackedPrefix + node.name,
|
|
1526
1804
|
optionalMarker,
|
|
1527
1805
|
': ',
|
|
1528
1806
|
path.call(print, 'typeAnnotation'),
|
|
1529
|
-
]
|
|
1807
|
+
];
|
|
1530
1808
|
} else {
|
|
1531
1809
|
identifierContent = trackedPrefix + node.name;
|
|
1532
1810
|
}
|
|
@@ -1540,7 +1818,7 @@ function printRippleNode(node, path, options, print, args) {
|
|
|
1540
1818
|
(parent.type === 'AssignmentExpression' && parent.left === node));
|
|
1541
1819
|
const shouldAddParens = node.metadata?.parenthesized && !parentHandlesParens;
|
|
1542
1820
|
if (shouldAddParens) {
|
|
1543
|
-
nodeContent =
|
|
1821
|
+
nodeContent = ['(', identifierContent, ')'];
|
|
1544
1822
|
} else {
|
|
1545
1823
|
nodeContent = identifierContent;
|
|
1546
1824
|
}
|
|
@@ -1583,6 +1861,7 @@ function printRippleNode(node, path, options, print, args) {
|
|
|
1583
1861
|
const hasBlankLineBefore =
|
|
1584
1862
|
prevComment && getBlankLinesBetweenNodes(prevComment, comment) > 0;
|
|
1585
1863
|
|
|
1864
|
+
/** @type {Doc | undefined} */
|
|
1586
1865
|
let commentDoc;
|
|
1587
1866
|
if (comment.type === 'Line') {
|
|
1588
1867
|
commentDoc = '//' + comment.value;
|
|
@@ -1590,7 +1869,9 @@ function printRippleNode(node, path, options, print, args) {
|
|
|
1590
1869
|
commentDoc = '/*' + comment.value + '*/';
|
|
1591
1870
|
}
|
|
1592
1871
|
|
|
1593
|
-
|
|
1872
|
+
if (commentDoc !== undefined) {
|
|
1873
|
+
commentDocs.push({ doc: commentDoc, hasBlankLineBefore });
|
|
1874
|
+
}
|
|
1594
1875
|
}
|
|
1595
1876
|
|
|
1596
1877
|
// Build the content with proper spacing
|
|
@@ -1611,7 +1892,7 @@ function printRippleNode(node, path, options, print, args) {
|
|
|
1611
1892
|
contentParts.push(doc);
|
|
1612
1893
|
}
|
|
1613
1894
|
|
|
1614
|
-
nodeContent = group(['{', indent([hardline,
|
|
1895
|
+
nodeContent = group(['{', indent([hardline, contentParts]), hardline, '}']);
|
|
1615
1896
|
break;
|
|
1616
1897
|
} else {
|
|
1617
1898
|
// Fallback to simple join
|
|
@@ -1629,6 +1910,7 @@ function printRippleNode(node, path, options, print, args) {
|
|
|
1629
1910
|
}
|
|
1630
1911
|
|
|
1631
1912
|
// Process statements and handle spacing using shouldAddBlankLine
|
|
1913
|
+
/** @type {Doc[]} */
|
|
1632
1914
|
const statements = [];
|
|
1633
1915
|
for (let i = 0; i < node.body.length; i++) {
|
|
1634
1916
|
const statement = path.call(print, 'body', i);
|
|
@@ -1648,24 +1930,25 @@ function printRippleNode(node, path, options, print, args) {
|
|
|
1648
1930
|
}
|
|
1649
1931
|
|
|
1650
1932
|
// Use proper block statement pattern
|
|
1651
|
-
nodeContent = group(['{', indent([hardline,
|
|
1933
|
+
nodeContent = group(['{', indent([hardline, statements]), hardline, '}']);
|
|
1652
1934
|
break;
|
|
1653
1935
|
}
|
|
1654
1936
|
|
|
1655
1937
|
case 'ServerBlock': {
|
|
1656
1938
|
const blockContent = path.call(print, 'body');
|
|
1657
|
-
nodeContent =
|
|
1939
|
+
nodeContent = ['#server ', blockContent];
|
|
1658
1940
|
break;
|
|
1659
1941
|
}
|
|
1660
1942
|
|
|
1661
1943
|
case 'ReturnStatement': {
|
|
1944
|
+
/** @type {Doc[]} */
|
|
1662
1945
|
const parts = ['return'];
|
|
1663
1946
|
if (node.argument) {
|
|
1664
1947
|
parts.push(' ');
|
|
1665
1948
|
parts.push(path.call(print, 'argument'));
|
|
1666
1949
|
}
|
|
1667
1950
|
parts.push(semi(options));
|
|
1668
|
-
nodeContent =
|
|
1951
|
+
nodeContent = parts;
|
|
1669
1952
|
break;
|
|
1670
1953
|
}
|
|
1671
1954
|
|
|
@@ -1681,41 +1964,32 @@ function printRippleNode(node, path, options, print, args) {
|
|
|
1681
1964
|
let result;
|
|
1682
1965
|
// Don't add indent if we're in a conditional test context
|
|
1683
1966
|
if (args?.isConditionalTest) {
|
|
1684
|
-
result = group(
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
line,
|
|
1691
|
-
path.call((childPath) => print(childPath, { isConditionalTest: true }), 'right'),
|
|
1692
|
-
]),
|
|
1693
|
-
]),
|
|
1694
|
-
);
|
|
1967
|
+
result = group([
|
|
1968
|
+
path.call((childPath) => print(childPath, { isConditionalTest: true }), 'left'),
|
|
1969
|
+
' ',
|
|
1970
|
+
node.operator,
|
|
1971
|
+
[line, path.call((childPath) => print(childPath, { isConditionalTest: true }), 'right')],
|
|
1972
|
+
]);
|
|
1695
1973
|
} else if (shouldNotIndent) {
|
|
1696
1974
|
// In assignment context, don't add indent - parent will handle it
|
|
1697
|
-
result = group(
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
]),
|
|
1704
|
-
);
|
|
1975
|
+
result = group([
|
|
1976
|
+
path.call(print, 'left'),
|
|
1977
|
+
' ',
|
|
1978
|
+
node.operator,
|
|
1979
|
+
[line, path.call(print, 'right')],
|
|
1980
|
+
]);
|
|
1705
1981
|
} else {
|
|
1706
|
-
result = group(
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
]),
|
|
1713
|
-
);
|
|
1982
|
+
result = group([
|
|
1983
|
+
path.call(print, 'left'),
|
|
1984
|
+
' ',
|
|
1985
|
+
node.operator,
|
|
1986
|
+
indent([line, path.call(print, 'right')]),
|
|
1987
|
+
]);
|
|
1714
1988
|
}
|
|
1715
1989
|
|
|
1716
1990
|
// Wrap in parentheses only if semantically necessary
|
|
1717
1991
|
if (binaryExpressionNeedsParens(node, parent)) {
|
|
1718
|
-
result =
|
|
1992
|
+
result = ['(', result, ')'];
|
|
1719
1993
|
}
|
|
1720
1994
|
|
|
1721
1995
|
nodeContent = result;
|
|
@@ -1724,26 +1998,19 @@ function printRippleNode(node, path, options, print, args) {
|
|
|
1724
1998
|
case 'LogicalExpression':
|
|
1725
1999
|
// Don't add indent if we're in a conditional test context
|
|
1726
2000
|
if (args?.isConditionalTest) {
|
|
1727
|
-
nodeContent = group(
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
line,
|
|
1734
|
-
path.call((childPath) => print(childPath, { isConditionalTest: true }), 'right'),
|
|
1735
|
-
]),
|
|
1736
|
-
]),
|
|
1737
|
-
);
|
|
2001
|
+
nodeContent = group([
|
|
2002
|
+
path.call((childPath) => print(childPath, { isConditionalTest: true }), 'left'),
|
|
2003
|
+
' ',
|
|
2004
|
+
node.operator,
|
|
2005
|
+
[line, path.call((childPath) => print(childPath, { isConditionalTest: true }), 'right')],
|
|
2006
|
+
]);
|
|
1738
2007
|
} else {
|
|
1739
|
-
nodeContent = group(
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
]),
|
|
1746
|
-
);
|
|
2008
|
+
nodeContent = group([
|
|
2009
|
+
path.call(print, 'left'),
|
|
2010
|
+
' ',
|
|
2011
|
+
node.operator,
|
|
2012
|
+
indent([line, path.call(print, 'right')]),
|
|
2013
|
+
]);
|
|
1747
2014
|
}
|
|
1748
2015
|
break;
|
|
1749
2016
|
|
|
@@ -1783,7 +2050,7 @@ function printRippleNode(node, path, options, print, args) {
|
|
|
1783
2050
|
const alternateBreaks = willBreak(alternateDoc);
|
|
1784
2051
|
|
|
1785
2052
|
// Helper to determine if a node type already handles its own indentation
|
|
1786
|
-
const hasOwnIndentation = (nodeType) => {
|
|
2053
|
+
const hasOwnIndentation = (/** @type {string} */ nodeType) => {
|
|
1787
2054
|
return nodeType === 'BinaryExpression' || nodeType === 'LogicalExpression';
|
|
1788
2055
|
};
|
|
1789
2056
|
|
|
@@ -1804,13 +2071,11 @@ function printRippleNode(node, path, options, print, args) {
|
|
|
1804
2071
|
!hasOwnIndentation(node.alternate.type) &&
|
|
1805
2072
|
node.alternate.type !== 'ConditionalExpression';
|
|
1806
2073
|
|
|
1807
|
-
result =
|
|
2074
|
+
result = [
|
|
1808
2075
|
testDoc,
|
|
1809
|
-
indent(
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
indent(concat([line, ': ', shouldIndentAlternate ? indent(alternateDoc) : alternateDoc])),
|
|
1813
|
-
]);
|
|
2076
|
+
indent([line, '? ', shouldIndentConsequent ? indent(consequentDoc) : consequentDoc]),
|
|
2077
|
+
indent([line, ': ', shouldIndentAlternate ? indent(alternateDoc) : alternateDoc]),
|
|
2078
|
+
];
|
|
1814
2079
|
} else {
|
|
1815
2080
|
// Otherwise try inline first, then multiline if it doesn't fit
|
|
1816
2081
|
const shouldIndentConsequent =
|
|
@@ -1822,23 +2087,19 @@ function printRippleNode(node, path, options, print, args) {
|
|
|
1822
2087
|
|
|
1823
2088
|
result = conditionalGroup([
|
|
1824
2089
|
// Try inline first
|
|
1825
|
-
|
|
2090
|
+
[testDoc, ' ? ', consequentDoc, ' : ', alternateDoc],
|
|
1826
2091
|
// If inline doesn't fit, use multiline
|
|
1827
|
-
|
|
2092
|
+
[
|
|
1828
2093
|
testDoc,
|
|
1829
|
-
indent(
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
indent(
|
|
1833
|
-
concat([line, ': ', shouldIndentAlternate ? indent(alternateDoc) : alternateDoc]),
|
|
1834
|
-
),
|
|
1835
|
-
]),
|
|
2094
|
+
indent([line, '? ', shouldIndentConsequent ? indent(consequentDoc) : consequentDoc]),
|
|
2095
|
+
indent([line, ': ', shouldIndentAlternate ? indent(alternateDoc) : alternateDoc]),
|
|
2096
|
+
],
|
|
1836
2097
|
]);
|
|
1837
2098
|
}
|
|
1838
2099
|
|
|
1839
2100
|
// Wrap in parentheses if metadata indicates they were present
|
|
1840
2101
|
if (node.metadata?.parenthesized) {
|
|
1841
|
-
result =
|
|
2102
|
+
result = ['(', result, ')'];
|
|
1842
2103
|
}
|
|
1843
2104
|
|
|
1844
2105
|
nodeContent = result;
|
|
@@ -1847,15 +2108,15 @@ function printRippleNode(node, path, options, print, args) {
|
|
|
1847
2108
|
|
|
1848
2109
|
case 'UpdateExpression':
|
|
1849
2110
|
if (node.prefix) {
|
|
1850
|
-
nodeContent =
|
|
2111
|
+
nodeContent = [node.operator, path.call(print, 'argument')];
|
|
1851
2112
|
} else {
|
|
1852
|
-
nodeContent =
|
|
2113
|
+
nodeContent = [path.call(print, 'argument'), node.operator];
|
|
1853
2114
|
}
|
|
1854
2115
|
break;
|
|
1855
2116
|
|
|
1856
2117
|
case 'TSArrayType': {
|
|
1857
2118
|
const parts = [path.call(print, 'elementType'), '[]'];
|
|
1858
|
-
nodeContent =
|
|
2119
|
+
nodeContent = parts;
|
|
1859
2120
|
break;
|
|
1860
2121
|
}
|
|
1861
2122
|
|
|
@@ -1926,13 +2187,13 @@ function printRippleNode(node, path, options, print, args) {
|
|
|
1926
2187
|
case 'TSTypeOperator': {
|
|
1927
2188
|
const operator = node.operator;
|
|
1928
2189
|
const type = path.call(print, 'typeAnnotation');
|
|
1929
|
-
nodeContent =
|
|
2190
|
+
nodeContent = [operator, ' ', type];
|
|
1930
2191
|
break;
|
|
1931
2192
|
}
|
|
1932
2193
|
|
|
1933
2194
|
case 'TSTypeQuery': {
|
|
1934
2195
|
const expr = path.call(print, 'exprName');
|
|
1935
|
-
nodeContent =
|
|
2196
|
+
nodeContent = ['typeof ', expr];
|
|
1936
2197
|
break;
|
|
1937
2198
|
}
|
|
1938
2199
|
|
|
@@ -1958,7 +2219,7 @@ function printRippleNode(node, path, options, print, args) {
|
|
|
1958
2219
|
parts.push(path.call(print, 'typeAnnotation'));
|
|
1959
2220
|
}
|
|
1960
2221
|
|
|
1961
|
-
nodeContent =
|
|
2222
|
+
nodeContent = parts;
|
|
1962
2223
|
break;
|
|
1963
2224
|
}
|
|
1964
2225
|
|
|
@@ -1991,7 +2252,7 @@ function printRippleNode(node, path, options, print, args) {
|
|
|
1991
2252
|
break;
|
|
1992
2253
|
|
|
1993
2254
|
case 'TSParenthesizedType': {
|
|
1994
|
-
nodeContent =
|
|
2255
|
+
nodeContent = ['(', path.call(print, 'typeAnnotation'), ')'];
|
|
1995
2256
|
break;
|
|
1996
2257
|
}
|
|
1997
2258
|
|
|
@@ -2003,7 +2264,7 @@ function printRippleNode(node, path, options, print, args) {
|
|
|
2003
2264
|
parts.push(path.call(print, 'typeParameters'));
|
|
2004
2265
|
}
|
|
2005
2266
|
|
|
2006
|
-
nodeContent =
|
|
2267
|
+
nodeContent = parts;
|
|
2007
2268
|
break;
|
|
2008
2269
|
}
|
|
2009
2270
|
|
|
@@ -2031,7 +2292,7 @@ function printRippleNode(node, path, options, print, args) {
|
|
|
2031
2292
|
// JSXEmptyExpression represents the empty expression in {/* comment */}
|
|
2032
2293
|
// The comments are attached as innerComments by the parser
|
|
2033
2294
|
if (innerCommentParts.length > 0) {
|
|
2034
|
-
nodeContent =
|
|
2295
|
+
nodeContent = innerCommentParts;
|
|
2035
2296
|
} else {
|
|
2036
2297
|
nodeContent = '';
|
|
2037
2298
|
}
|
|
@@ -2045,7 +2306,7 @@ function printRippleNode(node, path, options, print, args) {
|
|
|
2045
2306
|
const expressionDoc = suppressExpressionLeadingComments
|
|
2046
2307
|
? path.call((exprPath) => print(exprPath, { suppressLeadingComments: true }), 'expression')
|
|
2047
2308
|
: path.call(print, 'expression');
|
|
2048
|
-
nodeContent =
|
|
2309
|
+
nodeContent = ['{', expressionDoc, '}'];
|
|
2049
2310
|
break;
|
|
2050
2311
|
}
|
|
2051
2312
|
|
|
@@ -2053,7 +2314,7 @@ function printRippleNode(node, path, options, print, args) {
|
|
|
2053
2314
|
const expressionDoc = suppressExpressionLeadingComments
|
|
2054
2315
|
? path.call((exprPath) => print(exprPath, { suppressLeadingComments: true }), 'expression')
|
|
2055
2316
|
: path.call(print, 'expression');
|
|
2056
|
-
nodeContent =
|
|
2317
|
+
nodeContent = ['{html ', expressionDoc, '}'];
|
|
2057
2318
|
break;
|
|
2058
2319
|
}
|
|
2059
2320
|
|
|
@@ -2111,20 +2372,29 @@ function printRippleNode(node, path, options, print, args) {
|
|
|
2111
2372
|
if (trailingParts.length > 0) {
|
|
2112
2373
|
parts.push(nodeContent);
|
|
2113
2374
|
parts.push(...trailingParts);
|
|
2114
|
-
return
|
|
2375
|
+
return parts;
|
|
2115
2376
|
}
|
|
2116
2377
|
} // Return with or without leading comments
|
|
2117
2378
|
if (parts.length > 0) {
|
|
2118
2379
|
// Don't add blank line between leading comments and node
|
|
2119
2380
|
// because they're meant to be attached together
|
|
2120
2381
|
parts.push(nodeContent);
|
|
2121
|
-
return
|
|
2382
|
+
return parts;
|
|
2122
2383
|
}
|
|
2123
2384
|
|
|
2124
2385
|
return nodeContent;
|
|
2125
2386
|
}
|
|
2126
2387
|
|
|
2127
|
-
|
|
2388
|
+
/**
|
|
2389
|
+
* Print an import declaration
|
|
2390
|
+
* @param {RippleASTNode} node - The import declaration node
|
|
2391
|
+
* @param {AstPath<RippleASTNode>} path - The AST path
|
|
2392
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
2393
|
+
* @param {PrintFn} _print - Print callback (unused)
|
|
2394
|
+
* @returns {Doc}
|
|
2395
|
+
*/
|
|
2396
|
+
function printImportDeclaration(node, path, options, _print) {
|
|
2397
|
+
/** @type {Doc[]} */
|
|
2128
2398
|
const parts = ['import'];
|
|
2129
2399
|
|
|
2130
2400
|
// Handle type imports
|
|
@@ -2133,27 +2403,33 @@ function printImportDeclaration(node, path, options, print) {
|
|
|
2133
2403
|
}
|
|
2134
2404
|
|
|
2135
2405
|
if (node.specifiers && node.specifiers.length > 0) {
|
|
2406
|
+
/** @type {string[]} */
|
|
2136
2407
|
const defaultImports = [];
|
|
2408
|
+
/** @type {string[]} */
|
|
2137
2409
|
const namedImports = [];
|
|
2410
|
+
/** @type {string[]} */
|
|
2138
2411
|
const namespaceImports = [];
|
|
2139
2412
|
|
|
2140
|
-
node.specifiers.forEach((spec) => {
|
|
2413
|
+
node.specifiers.forEach((/** @type {RippleASTNode} */ spec) => {
|
|
2141
2414
|
if (spec.type === 'ImportDefaultSpecifier') {
|
|
2142
|
-
defaultImports.push(spec.local.name);
|
|
2415
|
+
defaultImports.push(/** @type {string} */ (spec.local.name));
|
|
2143
2416
|
} else if (spec.type === 'ImportSpecifier') {
|
|
2144
2417
|
// Handle inline type imports: import { type Component } from 'ripple'
|
|
2145
2418
|
const typePrefix = spec.importKind === 'type' ? 'type ' : '';
|
|
2419
|
+
const importedName = /** @type {string} */ (spec.imported.name);
|
|
2420
|
+
const localName = /** @type {string} */ (spec.local.name);
|
|
2146
2421
|
const importName =
|
|
2147
|
-
|
|
2148
|
-
? typePrefix +
|
|
2149
|
-
: typePrefix +
|
|
2422
|
+
importedName === localName
|
|
2423
|
+
? typePrefix + localName
|
|
2424
|
+
: typePrefix + importedName + ' as ' + localName;
|
|
2150
2425
|
namedImports.push(importName);
|
|
2151
2426
|
} else if (spec.type === 'ImportNamespaceSpecifier') {
|
|
2152
|
-
namespaceImports.push('* as ' + spec.local.name);
|
|
2427
|
+
namespaceImports.push('* as ' + /** @type {string} */ (spec.local.name));
|
|
2153
2428
|
}
|
|
2154
2429
|
});
|
|
2155
2430
|
|
|
2156
2431
|
// Build import clause with proper grouping and line breaking
|
|
2432
|
+
/** @type {Doc[]} */
|
|
2157
2433
|
const importClauseParts = [];
|
|
2158
2434
|
|
|
2159
2435
|
if (defaultImports.length > 0) {
|
|
@@ -2165,20 +2441,13 @@ function printImportDeclaration(node, path, options, print) {
|
|
|
2165
2441
|
if (namedImports.length > 0) {
|
|
2166
2442
|
// Use Prettier's group and conditionalGroup for named imports to handle line breaking
|
|
2167
2443
|
const namedImportsDocs = namedImports.map((name) => name);
|
|
2168
|
-
const namedImportsGroup = group(
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
]),
|
|
2176
|
-
),
|
|
2177
|
-
ifBreak(shouldPrintComma(options) ? ',' : ''),
|
|
2178
|
-
options.bracketSpacing ? line : softline,
|
|
2179
|
-
'}',
|
|
2180
|
-
]),
|
|
2181
|
-
);
|
|
2444
|
+
const namedImportsGroup = group([
|
|
2445
|
+
'{',
|
|
2446
|
+
indent([options.bracketSpacing ? line : softline, join([',', line], namedImportsDocs)]),
|
|
2447
|
+
ifBreak(shouldPrintComma(options) ? ',' : ''),
|
|
2448
|
+
options.bracketSpacing ? line : softline,
|
|
2449
|
+
'}',
|
|
2450
|
+
]);
|
|
2182
2451
|
importClauseParts.push(namedImportsGroup);
|
|
2183
2452
|
}
|
|
2184
2453
|
|
|
@@ -2186,16 +2455,28 @@ function printImportDeclaration(node, path, options, print) {
|
|
|
2186
2455
|
if (importClauseParts.length === 1 && typeof importClauseParts[0] === 'object') {
|
|
2187
2456
|
parts.push(importClauseParts[0]);
|
|
2188
2457
|
} else {
|
|
2189
|
-
parts.push(join(', ', importClauseParts));
|
|
2458
|
+
parts.push(/** @type {Doc} */ (join(', ', /** @type {string[]} */ (importClauseParts))));
|
|
2190
2459
|
}
|
|
2191
2460
|
parts.push(' from');
|
|
2192
2461
|
}
|
|
2193
2462
|
|
|
2194
|
-
parts.push(
|
|
2463
|
+
parts.push(
|
|
2464
|
+
' ',
|
|
2465
|
+
formatStringLiteral(/** @type {string} */ (node.source.value), options),
|
|
2466
|
+
semi(options),
|
|
2467
|
+
);
|
|
2195
2468
|
|
|
2196
|
-
return
|
|
2469
|
+
return parts;
|
|
2197
2470
|
}
|
|
2198
2471
|
|
|
2472
|
+
/**
|
|
2473
|
+
* Print an export named declaration
|
|
2474
|
+
* @param {RippleASTNode} node - The export declaration node
|
|
2475
|
+
* @param {AstPath<RippleASTNode>} path - The AST path
|
|
2476
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
2477
|
+
* @param {PrintFn} print - Print callback
|
|
2478
|
+
* @returns {Doc}
|
|
2479
|
+
*/
|
|
2199
2480
|
function printExportNamedDeclaration(node, path, options, print) {
|
|
2200
2481
|
if (node.declaration) {
|
|
2201
2482
|
const parts = [];
|
|
@@ -2203,11 +2484,13 @@ function printExportNamedDeclaration(node, path, options, print) {
|
|
|
2203
2484
|
parts.push(path.call(print, 'declaration'));
|
|
2204
2485
|
return parts;
|
|
2205
2486
|
} else if (node.specifiers && node.specifiers.length > 0) {
|
|
2206
|
-
const specifiers = node.specifiers.map((spec) => {
|
|
2207
|
-
|
|
2208
|
-
|
|
2487
|
+
const specifiers = node.specifiers.map((/** @type {RippleASTNode} */ spec) => {
|
|
2488
|
+
const exportedName = /** @type {string} */ (spec.exported.name);
|
|
2489
|
+
const localName = /** @type {string} */ (spec.local.name);
|
|
2490
|
+
if (exportedName === localName) {
|
|
2491
|
+
return localName;
|
|
2209
2492
|
} else {
|
|
2210
|
-
return
|
|
2493
|
+
return localName + ' as ' + exportedName;
|
|
2211
2494
|
}
|
|
2212
2495
|
});
|
|
2213
2496
|
|
|
@@ -2220,7 +2503,7 @@ function printExportNamedDeclaration(node, path, options, print) {
|
|
|
2220
2503
|
|
|
2221
2504
|
if (node.source) {
|
|
2222
2505
|
parts.push(' from ');
|
|
2223
|
-
parts.push(formatStringLiteral(node.source.value, options));
|
|
2506
|
+
parts.push(formatStringLiteral(/** @type {string} */ (node.source.value), options));
|
|
2224
2507
|
}
|
|
2225
2508
|
parts.push(semi(options));
|
|
2226
2509
|
|
|
@@ -2230,6 +2513,16 @@ function printExportNamedDeclaration(node, path, options, print) {
|
|
|
2230
2513
|
return 'export';
|
|
2231
2514
|
}
|
|
2232
2515
|
|
|
2516
|
+
/**
|
|
2517
|
+
* Print a Ripple component declaration
|
|
2518
|
+
* @param {RippleASTNode} node - The component node
|
|
2519
|
+
* @param {AstPath<RippleASTNode>} path - The AST path
|
|
2520
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
2521
|
+
* @param {PrintFn} print - Print callback
|
|
2522
|
+
* @param {Doc[]} [innerCommentParts=[]] - Inner comment docs
|
|
2523
|
+
* @param {{ skipComponentLabel?: boolean }} [args] - Additional args
|
|
2524
|
+
* @returns {Doc}
|
|
2525
|
+
*/
|
|
2233
2526
|
function printComponent(
|
|
2234
2527
|
node,
|
|
2235
2528
|
path,
|
|
@@ -2258,6 +2551,7 @@ function printComponent(
|
|
|
2258
2551
|
// Print parameters using shared function
|
|
2259
2552
|
const paramsPart = printFunctionParameters(path, options, print);
|
|
2260
2553
|
signatureParts.push(group(paramsPart)); // Build body content using the same pattern as BlockStatement
|
|
2554
|
+
/** @type {Doc[]} */
|
|
2261
2555
|
const statements = [];
|
|
2262
2556
|
|
|
2263
2557
|
for (let i = 0; i < node.body.length; i++) {
|
|
@@ -2281,7 +2575,7 @@ function printComponent(
|
|
|
2281
2575
|
// Process statements to add them to contentParts
|
|
2282
2576
|
const contentParts = [];
|
|
2283
2577
|
if (statements.length > 0) {
|
|
2284
|
-
contentParts.push(
|
|
2578
|
+
contentParts.push(statements);
|
|
2285
2579
|
}
|
|
2286
2580
|
|
|
2287
2581
|
// Build script content using Prettier document builders
|
|
@@ -2306,7 +2600,8 @@ function printComponent(
|
|
|
2306
2600
|
}
|
|
2307
2601
|
|
|
2308
2602
|
// Use Prettier's standard block statement pattern
|
|
2309
|
-
|
|
2603
|
+
/** @type {Doc[]} */
|
|
2604
|
+
const parts = [signatureParts, ' {'];
|
|
2310
2605
|
|
|
2311
2606
|
if (statements.length > 0 || scriptContent) {
|
|
2312
2607
|
// Build all content that goes inside the component body
|
|
@@ -2319,7 +2614,7 @@ function printComponent(
|
|
|
2319
2614
|
if (statements.length > 0) {
|
|
2320
2615
|
// The statements array contains statements separated by line breaks
|
|
2321
2616
|
// We need to use join to properly handle the line breaks
|
|
2322
|
-
contentParts.push(
|
|
2617
|
+
contentParts.push(statements);
|
|
2323
2618
|
}
|
|
2324
2619
|
|
|
2325
2620
|
// Add script content
|
|
@@ -2333,7 +2628,7 @@ function printComponent(
|
|
|
2333
2628
|
}
|
|
2334
2629
|
|
|
2335
2630
|
// Join content parts
|
|
2336
|
-
const joinedContent = contentParts.length > 0 ?
|
|
2631
|
+
const joinedContent = contentParts.length > 0 ? contentParts : '';
|
|
2337
2632
|
|
|
2338
2633
|
// Apply component-level indentation
|
|
2339
2634
|
const indentedContent = joinedContent ? indent([hardline, joinedContent]) : indent([hardline]);
|
|
@@ -2366,6 +2661,7 @@ function printComponent(
|
|
|
2366
2661
|
const hasBlankLineBefore =
|
|
2367
2662
|
prevComment && getBlankLinesBetweenNodes(prevComment, comment) > 0;
|
|
2368
2663
|
|
|
2664
|
+
/** @type {Doc | undefined} */
|
|
2369
2665
|
let commentDoc;
|
|
2370
2666
|
if (comment.type === 'Line') {
|
|
2371
2667
|
commentDoc = '//' + comment.value;
|
|
@@ -2373,7 +2669,9 @@ function printComponent(
|
|
|
2373
2669
|
commentDoc = '/*' + comment.value + '*/';
|
|
2374
2670
|
}
|
|
2375
2671
|
|
|
2376
|
-
|
|
2672
|
+
if (commentDoc !== undefined) {
|
|
2673
|
+
commentDocs.push({ doc: commentDoc, hasBlankLineBefore });
|
|
2674
|
+
}
|
|
2377
2675
|
}
|
|
2378
2676
|
}
|
|
2379
2677
|
|
|
@@ -2396,18 +2694,22 @@ function printComponent(
|
|
|
2396
2694
|
contentParts.push(doc);
|
|
2397
2695
|
}
|
|
2398
2696
|
|
|
2399
|
-
return
|
|
2400
|
-
concat(signatureParts),
|
|
2401
|
-
' ',
|
|
2402
|
-
group(['{', indent([hardline, concat(contentParts)]), hardline, '}']),
|
|
2403
|
-
]);
|
|
2697
|
+
return [signatureParts, ' ', group(['{', indent([hardline, contentParts]), hardline, '}'])];
|
|
2404
2698
|
}
|
|
2405
2699
|
|
|
2406
2700
|
parts[1] = ' {}';
|
|
2407
2701
|
}
|
|
2408
|
-
return
|
|
2702
|
+
return parts;
|
|
2409
2703
|
}
|
|
2410
2704
|
|
|
2705
|
+
/**
|
|
2706
|
+
* Print a variable declaration
|
|
2707
|
+
* @param {RippleASTNode} node - The variable declaration node
|
|
2708
|
+
* @param {AstPath<RippleASTNode>} path - The AST path
|
|
2709
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
2710
|
+
* @param {PrintFn} print - Print callback
|
|
2711
|
+
* @returns {Doc}
|
|
2712
|
+
*/
|
|
2411
2713
|
function printVariableDeclaration(node, path, options, print) {
|
|
2412
2714
|
const kind = node.kind || 'let';
|
|
2413
2715
|
|
|
@@ -2424,12 +2726,20 @@ function printVariableDeclaration(node, path, options, print) {
|
|
|
2424
2726
|
const declarationParts = join(', ', declarations);
|
|
2425
2727
|
|
|
2426
2728
|
if (!isForLoopInit) {
|
|
2427
|
-
return
|
|
2729
|
+
return [kind, ' ', declarationParts, semi(options)];
|
|
2428
2730
|
}
|
|
2429
2731
|
|
|
2430
|
-
return
|
|
2732
|
+
return [kind, ' ', declarationParts];
|
|
2431
2733
|
}
|
|
2432
2734
|
|
|
2735
|
+
/**
|
|
2736
|
+
* Print a function expression
|
|
2737
|
+
* @param {RippleASTNode} node - The function expression node
|
|
2738
|
+
* @param {AstPath<RippleASTNode>} path - The AST path
|
|
2739
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
2740
|
+
* @param {PrintFn} print - Print callback
|
|
2741
|
+
* @returns {Doc}
|
|
2742
|
+
*/
|
|
2433
2743
|
function printFunctionExpression(node, path, options, print) {
|
|
2434
2744
|
const parts = [];
|
|
2435
2745
|
|
|
@@ -2478,9 +2788,17 @@ function printFunctionExpression(node, path, options, print) {
|
|
|
2478
2788
|
parts.push(' ');
|
|
2479
2789
|
parts.push(path.call(print, 'body'));
|
|
2480
2790
|
|
|
2481
|
-
return
|
|
2791
|
+
return parts;
|
|
2482
2792
|
}
|
|
2483
2793
|
|
|
2794
|
+
/**
|
|
2795
|
+
* Print an arrow function expression
|
|
2796
|
+
* @param {RippleASTNode} node - The arrow function node
|
|
2797
|
+
* @param {AstPath<RippleASTNode>} path - The AST path
|
|
2798
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
2799
|
+
* @param {PrintFn} print - Print callback
|
|
2800
|
+
* @returns {Doc}
|
|
2801
|
+
*/
|
|
2484
2802
|
function printArrowFunction(node, path, options, print) {
|
|
2485
2803
|
const parts = [];
|
|
2486
2804
|
|
|
@@ -2541,9 +2859,17 @@ function printArrowFunction(node, path, options, print) {
|
|
|
2541
2859
|
}
|
|
2542
2860
|
}
|
|
2543
2861
|
|
|
2544
|
-
return
|
|
2862
|
+
return parts;
|
|
2545
2863
|
}
|
|
2546
2864
|
|
|
2865
|
+
/**
|
|
2866
|
+
* Print an export default declaration
|
|
2867
|
+
* @param {RippleASTNode} node - The export default node
|
|
2868
|
+
* @param {AstPath<RippleASTNode>} path - The AST path
|
|
2869
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
2870
|
+
* @param {PrintFn} print - Print callback
|
|
2871
|
+
* @returns {Doc[]}
|
|
2872
|
+
*/
|
|
2547
2873
|
function printExportDefaultDeclaration(node, path, options, print) {
|
|
2548
2874
|
const parts = [];
|
|
2549
2875
|
parts.push('export default ');
|
|
@@ -2551,6 +2877,11 @@ function printExportDefaultDeclaration(node, path, options, print) {
|
|
|
2551
2877
|
return parts;
|
|
2552
2878
|
}
|
|
2553
2879
|
|
|
2880
|
+
/**
|
|
2881
|
+
* Check if the only function parameter should be hugged (no extra parens)
|
|
2882
|
+
* @param {RippleASTNode} node - The function node
|
|
2883
|
+
* @returns {boolean}
|
|
2884
|
+
*/
|
|
2554
2885
|
function shouldHugTheOnlyFunctionParameter(node) {
|
|
2555
2886
|
if (!node) {
|
|
2556
2887
|
return false;
|
|
@@ -2571,6 +2902,13 @@ function shouldHugTheOnlyFunctionParameter(node) {
|
|
|
2571
2902
|
);
|
|
2572
2903
|
}
|
|
2573
2904
|
|
|
2905
|
+
/**
|
|
2906
|
+
* Print function parameters with proper formatting
|
|
2907
|
+
* @param {AstPath<RippleASTNode>} path - The function path
|
|
2908
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
2909
|
+
* @param {PrintFn} print - Print callback
|
|
2910
|
+
* @returns {Doc[]}
|
|
2911
|
+
*/
|
|
2574
2912
|
function printFunctionParameters(path, options, print) {
|
|
2575
2913
|
const functionNode = path.node;
|
|
2576
2914
|
const parameters = getFunctionParameters(functionNode);
|
|
@@ -2580,6 +2918,7 @@ function printFunctionParameters(path, options, print) {
|
|
|
2580
2918
|
}
|
|
2581
2919
|
|
|
2582
2920
|
const shouldHugParameters = shouldHugTheOnlyFunctionParameter(functionNode);
|
|
2921
|
+
/** @type {Doc[]} */
|
|
2583
2922
|
const printed = [];
|
|
2584
2923
|
|
|
2585
2924
|
iterateFunctionParametersPath(path, (parameterPath, index) => {
|
|
@@ -2620,10 +2959,20 @@ function printFunctionParameters(path, options, print) {
|
|
|
2620
2959
|
];
|
|
2621
2960
|
}
|
|
2622
2961
|
|
|
2962
|
+
/**
|
|
2963
|
+
* Check if a node is spread-like (SpreadElement or RestElement)
|
|
2964
|
+
* @param {RippleASTNode} node - The AST node
|
|
2965
|
+
* @returns {boolean}
|
|
2966
|
+
*/
|
|
2623
2967
|
function isSpreadLike(node) {
|
|
2624
2968
|
return node && (node.type === 'SpreadElement' || node.type === 'RestElement');
|
|
2625
2969
|
}
|
|
2626
2970
|
|
|
2971
|
+
/**
|
|
2972
|
+
* Check if a node is a block-like function (function expression or arrow with block body)
|
|
2973
|
+
* @param {RippleASTNode} node - The AST node
|
|
2974
|
+
* @returns {boolean}
|
|
2975
|
+
*/
|
|
2627
2976
|
function isBlockLikeFunction(node) {
|
|
2628
2977
|
if (!node) {
|
|
2629
2978
|
return false;
|
|
@@ -2637,6 +2986,12 @@ function isBlockLikeFunction(node) {
|
|
|
2637
2986
|
return false;
|
|
2638
2987
|
}
|
|
2639
2988
|
|
|
2989
|
+
/**
|
|
2990
|
+
* Determine if the last argument should be hugged (no line break before it)
|
|
2991
|
+
* @param {RippleASTNode[]} args - Array of arguments
|
|
2992
|
+
* @param {boolean[]} argumentBreakFlags - Flags indicating which args break
|
|
2993
|
+
* @returns {boolean}
|
|
2994
|
+
*/
|
|
2640
2995
|
function shouldHugLastArgument(args, argumentBreakFlags) {
|
|
2641
2996
|
if (!args || args.length === 0) {
|
|
2642
2997
|
return false;
|
|
@@ -2673,7 +3028,11 @@ function shouldHugLastArgument(args, argumentBreakFlags) {
|
|
|
2673
3028
|
return true;
|
|
2674
3029
|
}
|
|
2675
3030
|
|
|
2676
|
-
|
|
3031
|
+
/**
|
|
3032
|
+
* Check if arguments contain arrow functions with block bodies that should be hugged
|
|
3033
|
+
* @param {RippleASTNode[]} args - Array of arguments
|
|
3034
|
+
* @returns {boolean}
|
|
3035
|
+
*/
|
|
2677
3036
|
function shouldHugArrowFunctions(args) {
|
|
2678
3037
|
if (!args || args.length === 0) {
|
|
2679
3038
|
return false;
|
|
@@ -2697,6 +3056,13 @@ function shouldHugArrowFunctions(args) {
|
|
|
2697
3056
|
return firstBlockIndex === 0;
|
|
2698
3057
|
}
|
|
2699
3058
|
|
|
3059
|
+
/**
|
|
3060
|
+
* Print call expression arguments
|
|
3061
|
+
* @param {AstPath<RippleASTNode>} path - The call path
|
|
3062
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
3063
|
+
* @param {PrintFn} print - Print callback
|
|
3064
|
+
* @returns {Doc}
|
|
3065
|
+
*/
|
|
2700
3066
|
function printCallArguments(path, options, print) {
|
|
2701
3067
|
const { node } = path;
|
|
2702
3068
|
const args = node.arguments || [];
|
|
@@ -2715,8 +3081,11 @@ function printCallArguments(path, options, print) {
|
|
|
2715
3081
|
finalArg.type === 'TrackedArrayExpression') &&
|
|
2716
3082
|
!hasComment(finalArg);
|
|
2717
3083
|
|
|
3084
|
+
/** @type {Doc[]} */
|
|
2718
3085
|
const printedArguments = [];
|
|
3086
|
+
/** @type {Doc[]} */
|
|
2719
3087
|
const argumentDocs = [];
|
|
3088
|
+
/** @type {boolean[]} */
|
|
2720
3089
|
const argumentBreakFlags = [];
|
|
2721
3090
|
let anyArgumentHasEmptyLine = false;
|
|
2722
3091
|
|
|
@@ -2737,9 +3106,9 @@ function printCallArguments(path, options, print) {
|
|
|
2737
3106
|
if (!isLast) {
|
|
2738
3107
|
if (isNextLineEmpty(argumentNode, options)) {
|
|
2739
3108
|
anyArgumentHasEmptyLine = true;
|
|
2740
|
-
printedArguments.push(
|
|
3109
|
+
printedArguments.push([argumentDoc, ',', hardline, hardline]);
|
|
2741
3110
|
} else {
|
|
2742
|
-
printedArguments.push(
|
|
3111
|
+
printedArguments.push([argumentDoc, ',', line]);
|
|
2743
3112
|
}
|
|
2744
3113
|
} else {
|
|
2745
3114
|
printedArguments.push(argumentDoc);
|
|
@@ -2756,7 +3125,7 @@ function printCallArguments(path, options, print) {
|
|
|
2756
3125
|
if (isSingleArrayArgument) {
|
|
2757
3126
|
// Don't use group() - just concat to allow array to control its own breaking
|
|
2758
3127
|
// For single argument, no trailing comma needed
|
|
2759
|
-
return
|
|
3128
|
+
return ['(', argumentDocs[0], ')'];
|
|
2760
3129
|
} // Check if we should hug arrow functions (keep params inline even when body breaks)
|
|
2761
3130
|
const shouldHugArrows = shouldHugArrowFunctions(args);
|
|
2762
3131
|
let huggedArrowDoc = null;
|
|
@@ -2765,6 +3134,7 @@ function printCallArguments(path, options, print) {
|
|
|
2765
3134
|
// but allow the block body to break naturally
|
|
2766
3135
|
if (shouldHugArrows && !anyArgumentHasEmptyLine) {
|
|
2767
3136
|
// Build a version that keeps arguments inline with opening paren
|
|
3137
|
+
/** @type {Doc[]} */
|
|
2768
3138
|
const huggedParts = ['('];
|
|
2769
3139
|
|
|
2770
3140
|
for (let index = 0; index < args.length; index++) {
|
|
@@ -2775,7 +3145,7 @@ function printCallArguments(path, options, print) {
|
|
|
2775
3145
|
}
|
|
2776
3146
|
|
|
2777
3147
|
huggedParts.push(')');
|
|
2778
|
-
huggedArrowDoc =
|
|
3148
|
+
huggedArrowDoc = huggedParts;
|
|
2779
3149
|
}
|
|
2780
3150
|
|
|
2781
3151
|
// Build standard breaking version with indentation
|
|
@@ -2826,6 +3196,7 @@ function printCallArguments(path, options, print) {
|
|
|
2826
3196
|
);
|
|
2827
3197
|
|
|
2828
3198
|
// Build the inline version: head args inline + expanded last arg
|
|
3199
|
+
/** @type {Doc[]} */
|
|
2829
3200
|
const inlinePartsWithExpanded = ['('];
|
|
2830
3201
|
for (let index = 0; index < headArgs.length; index++) {
|
|
2831
3202
|
if (index > 0) {
|
|
@@ -2841,9 +3212,9 @@ function printCallArguments(path, options, print) {
|
|
|
2841
3212
|
|
|
2842
3213
|
return conditionalGroup([
|
|
2843
3214
|
// Try with normal formatting first
|
|
2844
|
-
|
|
3215
|
+
['(', ...argumentDocs.flatMap((doc, i) => (i > 0 ? [', ', doc] : [doc])), ')'],
|
|
2845
3216
|
// Then try with expanded last arg
|
|
2846
|
-
|
|
3217
|
+
inlinePartsWithExpanded,
|
|
2847
3218
|
// Finally fall back to all args broken out
|
|
2848
3219
|
groupedContents,
|
|
2849
3220
|
]);
|
|
@@ -2858,6 +3229,7 @@ function printCallArguments(path, options, print) {
|
|
|
2858
3229
|
!hasComment(lastArg);
|
|
2859
3230
|
|
|
2860
3231
|
if (canInlineLastArg) {
|
|
3232
|
+
/** @type {Doc[]} */
|
|
2861
3233
|
const inlineParts = ['('];
|
|
2862
3234
|
for (let index = 0; index < argumentDocs.length; index++) {
|
|
2863
3235
|
if (index > 0) {
|
|
@@ -2867,11 +3239,12 @@ function printCallArguments(path, options, print) {
|
|
|
2867
3239
|
}
|
|
2868
3240
|
inlineParts.push(')');
|
|
2869
3241
|
|
|
2870
|
-
return conditionalGroup([
|
|
3242
|
+
return conditionalGroup([inlineParts, groupedContents]);
|
|
2871
3243
|
}
|
|
2872
3244
|
|
|
2873
3245
|
if (!anyArgumentHasEmptyLine && shouldHugLastArgument(args, argumentBreakFlags)) {
|
|
2874
3246
|
const lastIndex = args.length - 1;
|
|
3247
|
+
/** @type {Doc[]} */
|
|
2875
3248
|
const inlineParts = ['('];
|
|
2876
3249
|
|
|
2877
3250
|
for (let index = 0; index < lastIndex; index++) {
|
|
@@ -2894,6 +3267,74 @@ function printCallArguments(path, options, print) {
|
|
|
2894
3267
|
return groupedContents;
|
|
2895
3268
|
}
|
|
2896
3269
|
|
|
3270
|
+
/**
|
|
3271
|
+
* Print TSDeclareFunction (TypeScript function overload declaration)
|
|
3272
|
+
* These are function signatures without bodies, ending with semicolon
|
|
3273
|
+
* @param {RippleASTNode} node - The TS function declaration node
|
|
3274
|
+
* @param {AstPath<RippleASTNode>} path - The AST path
|
|
3275
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
3276
|
+
* @param {PrintFn} print - Print callback
|
|
3277
|
+
* @returns {Doc[]}
|
|
3278
|
+
*/
|
|
3279
|
+
function printTSDeclareFunction(node, path, options, print) {
|
|
3280
|
+
const parts = [];
|
|
3281
|
+
|
|
3282
|
+
// Handle declare modifier for ambient declarations
|
|
3283
|
+
if (node.declare) {
|
|
3284
|
+
parts.push('declare ');
|
|
3285
|
+
}
|
|
3286
|
+
|
|
3287
|
+
// Handle async functions
|
|
3288
|
+
if (node.async) {
|
|
3289
|
+
parts.push('async ');
|
|
3290
|
+
}
|
|
3291
|
+
|
|
3292
|
+
parts.push('function');
|
|
3293
|
+
|
|
3294
|
+
// Handle generator functions
|
|
3295
|
+
if (node.generator) {
|
|
3296
|
+
parts.push('*');
|
|
3297
|
+
}
|
|
3298
|
+
|
|
3299
|
+
// Handle function name (may be null for anonymous default exports)
|
|
3300
|
+
if (node.id) {
|
|
3301
|
+
parts.push(' ');
|
|
3302
|
+
parts.push(node.id.name);
|
|
3303
|
+
}
|
|
3304
|
+
|
|
3305
|
+
// Add TypeScript generics if present
|
|
3306
|
+
if (node.typeParameters) {
|
|
3307
|
+
const typeParams = path.call(print, 'typeParameters');
|
|
3308
|
+
if (Array.isArray(typeParams)) {
|
|
3309
|
+
parts.push(...typeParams);
|
|
3310
|
+
} else {
|
|
3311
|
+
parts.push(typeParams);
|
|
3312
|
+
}
|
|
3313
|
+
}
|
|
3314
|
+
|
|
3315
|
+
// Print parameters using shared function
|
|
3316
|
+
const paramsPart = printFunctionParameters(path, options, print);
|
|
3317
|
+
parts.push(group(paramsPart));
|
|
3318
|
+
|
|
3319
|
+
// Handle return type annotation
|
|
3320
|
+
if (node.returnType) {
|
|
3321
|
+
parts.push(': ', path.call(print, 'returnType'));
|
|
3322
|
+
}
|
|
3323
|
+
|
|
3324
|
+
// TSDeclareFunction ends with semicolon, no body
|
|
3325
|
+
parts.push(';');
|
|
3326
|
+
|
|
3327
|
+
return parts;
|
|
3328
|
+
}
|
|
3329
|
+
|
|
3330
|
+
/**
|
|
3331
|
+
* Print a function declaration
|
|
3332
|
+
* @param {RippleASTNode} node - The function declaration node
|
|
3333
|
+
* @param {AstPath<RippleASTNode>} path - The AST path
|
|
3334
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
3335
|
+
* @param {PrintFn} print - Print callback
|
|
3336
|
+
* @returns {Doc[]}
|
|
3337
|
+
*/
|
|
2897
3338
|
function printFunctionDeclaration(node, path, options, print) {
|
|
2898
3339
|
const parts = [];
|
|
2899
3340
|
|
|
@@ -2937,22 +3378,115 @@ function printFunctionDeclaration(node, path, options, print) {
|
|
|
2937
3378
|
return parts;
|
|
2938
3379
|
}
|
|
2939
3380
|
|
|
3381
|
+
/**
|
|
3382
|
+
* Extract and print leading comments from a node before a control flow statement keyword
|
|
3383
|
+
* @param {Node} node - The node that may have leading comments
|
|
3384
|
+
* @returns {Doc[]} - Array of doc parts for the comments
|
|
3385
|
+
*/
|
|
3386
|
+
function extractAndPrintLeadingComments(node) {
|
|
3387
|
+
const leadingComments = node && node.leadingComments;
|
|
3388
|
+
const parts = [];
|
|
3389
|
+
|
|
3390
|
+
if (leadingComments && leadingComments.length > 0) {
|
|
3391
|
+
for (let i = 0; i < leadingComments.length; i++) {
|
|
3392
|
+
const comment = leadingComments[i];
|
|
3393
|
+
const nextComment = leadingComments[i + 1];
|
|
3394
|
+
|
|
3395
|
+
if (comment.type === 'Line') {
|
|
3396
|
+
parts.push('//' + comment.value);
|
|
3397
|
+
parts.push(hardline);
|
|
3398
|
+
|
|
3399
|
+
// Check if there should be blank lines between comments
|
|
3400
|
+
if (nextComment) {
|
|
3401
|
+
const blankLinesBetween = getBlankLinesBetweenNodes(comment, nextComment);
|
|
3402
|
+
if (blankLinesBetween > 0) {
|
|
3403
|
+
parts.push(hardline);
|
|
3404
|
+
}
|
|
3405
|
+
}
|
|
3406
|
+
} else if (comment.type === 'Block') {
|
|
3407
|
+
parts.push('/*' + comment.value + '*/');
|
|
3408
|
+
parts.push(hardline);
|
|
3409
|
+
|
|
3410
|
+
// Check if there should be blank lines between comments
|
|
3411
|
+
if (nextComment) {
|
|
3412
|
+
const blankLinesBetween = getBlankLinesBetweenNodes(comment, nextComment);
|
|
3413
|
+
if (blankLinesBetween > 0) {
|
|
3414
|
+
parts.push(hardline);
|
|
3415
|
+
}
|
|
3416
|
+
}
|
|
3417
|
+
}
|
|
3418
|
+
}
|
|
3419
|
+
}
|
|
3420
|
+
|
|
3421
|
+
return parts;
|
|
3422
|
+
}
|
|
3423
|
+
|
|
3424
|
+
/**
|
|
3425
|
+
* Print an if statement
|
|
3426
|
+
* @param {RippleASTNode} node - The if statement node
|
|
3427
|
+
* @param {AstPath<RippleASTNode>} path - The AST path
|
|
3428
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
3429
|
+
* @param {PrintFn} print - Print callback
|
|
3430
|
+
* @returns {Doc}
|
|
3431
|
+
*/
|
|
2940
3432
|
function printIfStatement(node, path, options, print) {
|
|
2941
|
-
|
|
3433
|
+
// Extract leading comments from test node to print them before 'if' keyword
|
|
3434
|
+
const testNode = node.test;
|
|
3435
|
+
|
|
3436
|
+
// Print test without its leading comments (they'll be printed before 'if')
|
|
3437
|
+
const test = path.call((testPath) => print(testPath, { suppressLeadingComments: true }), 'test');
|
|
2942
3438
|
const consequent = path.call(print, 'consequent');
|
|
2943
3439
|
|
|
2944
3440
|
// Use group to allow breaking the test when it doesn't fit
|
|
2945
|
-
const testDoc = group(
|
|
3441
|
+
const testDoc = group(['if (', indent([softline, test]), softline, ')']);
|
|
3442
|
+
|
|
3443
|
+
// Check if consequent is a block statement or another if statement
|
|
3444
|
+
const consequentIsBlock = node.consequent.type === 'BlockStatement';
|
|
3445
|
+
const consequentIsIf = node.consequent.type === 'IfStatement';
|
|
2946
3446
|
|
|
2947
|
-
const parts = [
|
|
3447
|
+
const parts = [];
|
|
3448
|
+
|
|
3449
|
+
// Print leading comments from test node before 'if' keyword
|
|
3450
|
+
parts.push(...extractAndPrintLeadingComments(testNode));
|
|
3451
|
+
|
|
3452
|
+
parts.push(testDoc);
|
|
3453
|
+
|
|
3454
|
+
// Handle the consequent
|
|
3455
|
+
if (consequentIsBlock) {
|
|
3456
|
+
// For block statements, add a space before the block
|
|
3457
|
+
parts.push(' ', consequent);
|
|
3458
|
+
} else if (consequentIsIf) {
|
|
3459
|
+
// For nested if statements, add a line break and indent
|
|
3460
|
+
parts.push(indent([hardline, consequent]));
|
|
3461
|
+
} else {
|
|
3462
|
+
// For other non-block statements, add a space
|
|
3463
|
+
parts.push(' ', consequent);
|
|
3464
|
+
}
|
|
2948
3465
|
|
|
3466
|
+
// Handle the alternate
|
|
2949
3467
|
if (node.alternate) {
|
|
2950
|
-
|
|
3468
|
+
// If consequent is not a block, add a hardline before else
|
|
3469
|
+
if (!consequentIsBlock) {
|
|
3470
|
+
parts.push(hardline);
|
|
3471
|
+
} else {
|
|
3472
|
+
parts.push(' ');
|
|
3473
|
+
}
|
|
3474
|
+
|
|
3475
|
+
parts.push('else ');
|
|
3476
|
+
parts.push(path.call(print, 'alternate'));
|
|
2951
3477
|
}
|
|
2952
3478
|
|
|
2953
|
-
return
|
|
3479
|
+
return parts;
|
|
2954
3480
|
}
|
|
2955
3481
|
|
|
3482
|
+
/**
|
|
3483
|
+
* Print a for-in statement
|
|
3484
|
+
* @param {RippleASTNode} node - The for-in statement node
|
|
3485
|
+
* @param {AstPath<RippleASTNode>} path - The AST path
|
|
3486
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
3487
|
+
* @param {PrintFn} print - Print callback
|
|
3488
|
+
* @returns {Doc[]}
|
|
3489
|
+
*/
|
|
2956
3490
|
function printForInStatement(node, path, options, print) {
|
|
2957
3491
|
const parts = [];
|
|
2958
3492
|
parts.push('for (');
|
|
@@ -2966,6 +3500,14 @@ function printForInStatement(node, path, options, print) {
|
|
|
2966
3500
|
return parts;
|
|
2967
3501
|
}
|
|
2968
3502
|
|
|
3503
|
+
/**
|
|
3504
|
+
* Print a for-of statement (with Ripple index/key extensions)
|
|
3505
|
+
* @param {RippleASTNode} node - The for-of statement node
|
|
3506
|
+
* @param {AstPath<RippleASTNode>} path - The AST path
|
|
3507
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
3508
|
+
* @param {PrintFn} print - Print callback
|
|
3509
|
+
* @returns {Doc[]}
|
|
3510
|
+
*/
|
|
2969
3511
|
function printForOfStatement(node, path, options, print) {
|
|
2970
3512
|
const parts = [];
|
|
2971
3513
|
parts.push('for (');
|
|
@@ -2990,6 +3532,14 @@ function printForOfStatement(node, path, options, print) {
|
|
|
2990
3532
|
return parts;
|
|
2991
3533
|
}
|
|
2992
3534
|
|
|
3535
|
+
/**
|
|
3536
|
+
* Print a for statement
|
|
3537
|
+
* @param {RippleASTNode} node - The for statement node
|
|
3538
|
+
* @param {AstPath<RippleASTNode>} path - The AST path
|
|
3539
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
3540
|
+
* @param {PrintFn} print - Print callback
|
|
3541
|
+
* @returns {Doc[]}
|
|
3542
|
+
*/
|
|
2993
3543
|
function printForStatement(node, path, options, print) {
|
|
2994
3544
|
const parts = [];
|
|
2995
3545
|
parts.push('for (');
|
|
@@ -3019,28 +3569,78 @@ function printForStatement(node, path, options, print) {
|
|
|
3019
3569
|
return parts;
|
|
3020
3570
|
}
|
|
3021
3571
|
|
|
3022
|
-
|
|
3572
|
+
/**
|
|
3573
|
+
* Print a while statement
|
|
3574
|
+
* @param {RippleASTNode} node - The while statement node
|
|
3575
|
+
* @param {AstPath<RippleASTNode>} path - The AST path
|
|
3576
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
3577
|
+
* @param {PrintFn} print - Print callback
|
|
3578
|
+
* @returns {Doc[]}
|
|
3579
|
+
*/
|
|
3023
3580
|
function printWhileStatement(node, path, options, print) {
|
|
3581
|
+
// Extract leading comments from test node to print them before 'while' keyword
|
|
3582
|
+
const testNode = node.test;
|
|
3583
|
+
|
|
3584
|
+
// Print test without its leading comments (they'll be printed before 'while')
|
|
3585
|
+
const test = path.call((testPath) => print(testPath, { suppressLeadingComments: true }), 'test');
|
|
3586
|
+
|
|
3024
3587
|
const parts = [];
|
|
3588
|
+
|
|
3589
|
+
// Print leading comments from test node before 'while' keyword
|
|
3590
|
+
parts.push(...extractAndPrintLeadingComments(testNode));
|
|
3591
|
+
|
|
3025
3592
|
parts.push('while (');
|
|
3026
|
-
parts.push(
|
|
3593
|
+
parts.push(test);
|
|
3027
3594
|
parts.push(') ');
|
|
3028
3595
|
parts.push(path.call(print, 'body'));
|
|
3029
3596
|
|
|
3030
3597
|
return parts;
|
|
3031
3598
|
}
|
|
3032
3599
|
|
|
3600
|
+
/**
|
|
3601
|
+
* Print a do-while statement
|
|
3602
|
+
* @param {RippleASTNode} node - The do-while statement node
|
|
3603
|
+
* @param {AstPath<RippleASTNode>} path - The AST path
|
|
3604
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
3605
|
+
* @param {PrintFn} print - Print callback
|
|
3606
|
+
* @returns {Doc[]}
|
|
3607
|
+
*/
|
|
3033
3608
|
function printDoWhileStatement(node, path, options, print) {
|
|
3609
|
+
// Extract leading comments from test node to print them before 'while' keyword
|
|
3610
|
+
const testNode = node.test;
|
|
3611
|
+
|
|
3612
|
+
// Print test without its leading comments (they'll be printed before 'while')
|
|
3613
|
+
const test = path.call((testPath) => print(testPath, { suppressLeadingComments: true }), 'test');
|
|
3614
|
+
|
|
3034
3615
|
const parts = [];
|
|
3035
3616
|
parts.push('do ');
|
|
3036
3617
|
parts.push(path.call(print, 'body'));
|
|
3037
|
-
|
|
3038
|
-
|
|
3618
|
+
|
|
3619
|
+
// Print leading comments from test node before 'while' keyword
|
|
3620
|
+
const commentParts = extractAndPrintLeadingComments(testNode);
|
|
3621
|
+
if (commentParts.length > 0) {
|
|
3622
|
+
parts.push(' ');
|
|
3623
|
+
parts.push(...commentParts);
|
|
3624
|
+
} else {
|
|
3625
|
+
parts.push(' ');
|
|
3626
|
+
}
|
|
3627
|
+
|
|
3628
|
+
parts.push('while (');
|
|
3629
|
+
parts.push(test);
|
|
3039
3630
|
parts.push(')');
|
|
3040
3631
|
|
|
3041
3632
|
return parts;
|
|
3042
3633
|
}
|
|
3043
3634
|
|
|
3635
|
+
/**
|
|
3636
|
+
* Print an object expression (or TrackedObjectExpression)
|
|
3637
|
+
* @param {RippleASTNode} node - The object expression node
|
|
3638
|
+
* @param {AstPath<RippleASTNode>} path - The AST path
|
|
3639
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
3640
|
+
* @param {PrintFn} print - Print callback
|
|
3641
|
+
* @param {PrintArgs} [args] - Additional context arguments
|
|
3642
|
+
* @returns {Doc}
|
|
3643
|
+
*/
|
|
3044
3644
|
function printObjectExpression(node, path, options, print, args) {
|
|
3045
3645
|
const skip_offset = node.type === 'TrackedObjectExpression' ? 2 : 1;
|
|
3046
3646
|
const open_brace = node.type === 'TrackedObjectExpression' ? '#{' : '{';
|
|
@@ -3074,18 +3674,14 @@ function printObjectExpression(node, path, options, print, args) {
|
|
|
3074
3674
|
|
|
3075
3675
|
// Check for blank line after opening brace (before first property)
|
|
3076
3676
|
if (firstProp && node.loc && node.loc.start) {
|
|
3077
|
-
hasAnyBlankLines =
|
|
3078
|
-
node.loc.start.offset(skip_offset),
|
|
3079
|
-
firstProp.loc.start,
|
|
3080
|
-
);
|
|
3677
|
+
hasAnyBlankLines =
|
|
3678
|
+
getBlankLinesBetweenPositions(node.loc.start.offset(skip_offset), firstProp.loc.start) > 0;
|
|
3081
3679
|
}
|
|
3082
3680
|
|
|
3083
3681
|
// Check for blank line before closing brace (after last property)
|
|
3084
3682
|
if (!hasAnyBlankLines && lastProp && node.loc && node.loc.end) {
|
|
3085
|
-
hasAnyBlankLines =
|
|
3086
|
-
lastProp.loc.end,
|
|
3087
|
-
node.loc.end.offset(-1), // -1 to skip the '}'
|
|
3088
|
-
);
|
|
3683
|
+
hasAnyBlankLines =
|
|
3684
|
+
getBlankLinesBetweenPositions(lastProp.loc.end, node.loc.end.offset(-1)) > 0; // -1 to skip the '}'
|
|
3089
3685
|
}
|
|
3090
3686
|
}
|
|
3091
3687
|
|
|
@@ -3107,20 +3703,18 @@ function printObjectExpression(node, path, options, print, args) {
|
|
|
3107
3703
|
if (isInArray) {
|
|
3108
3704
|
if (isVerySimple) {
|
|
3109
3705
|
// 1-property objects: force inline with spaces
|
|
3110
|
-
return
|
|
3706
|
+
return [open_brace, ' ', properties[0], ' ', '}'];
|
|
3111
3707
|
}
|
|
3112
3708
|
}
|
|
3113
3709
|
}
|
|
3114
3710
|
|
|
3115
3711
|
if (args && args.allowInlineObject) {
|
|
3116
|
-
const separator =
|
|
3712
|
+
const separator = [',', line];
|
|
3117
3713
|
const propertyDoc = join(separator, properties);
|
|
3118
3714
|
const spacing = options.bracketSpacing === false ? softline : line;
|
|
3119
3715
|
const trailingDoc = shouldUseTrailingComma ? ifBreak(',', '') : '';
|
|
3120
3716
|
|
|
3121
|
-
return group(
|
|
3122
|
-
concat([open_brace, indent(concat([spacing, propertyDoc, trailingDoc])), spacing, '}']),
|
|
3123
|
-
);
|
|
3717
|
+
return group([open_brace, indent([spacing, propertyDoc, trailingDoc]), spacing, '}']);
|
|
3124
3718
|
}
|
|
3125
3719
|
|
|
3126
3720
|
// For objects that were originally inline (single-line) and don't have blank lines,
|
|
@@ -3128,16 +3722,15 @@ function printObjectExpression(node, path, options, print, args) {
|
|
|
3128
3722
|
// This handles cases like `const T0: t17 = { x: 1 };` staying inline when it fits
|
|
3129
3723
|
// The group() will automatically break to multi-line if it doesn't fit
|
|
3130
3724
|
if (!hasAnyBlankLines && !isOriginallyMultiLine && !isInArray) {
|
|
3131
|
-
const separator =
|
|
3725
|
+
const separator = [',', line];
|
|
3132
3726
|
const propertyDoc = join(separator, properties);
|
|
3133
3727
|
const spacing = options.bracketSpacing === false ? softline : line;
|
|
3134
3728
|
const trailingDoc = shouldUseTrailingComma ? ifBreak(',', '') : '';
|
|
3135
3729
|
|
|
3136
|
-
return group(
|
|
3137
|
-
concat([open_brace, indent(concat([spacing, propertyDoc, trailingDoc])), spacing, '}']),
|
|
3138
|
-
);
|
|
3730
|
+
return group([open_brace, indent([spacing, propertyDoc, trailingDoc]), spacing, '}']);
|
|
3139
3731
|
}
|
|
3140
3732
|
|
|
3733
|
+
/** @type {Doc[]} */
|
|
3141
3734
|
let content = [hardline];
|
|
3142
3735
|
if (properties.length > 0) {
|
|
3143
3736
|
// Build properties with blank line preservation
|
|
@@ -3174,7 +3767,7 @@ function printObjectExpression(node, path, options, print, args) {
|
|
|
3174
3767
|
propertyParts.push(properties[i]);
|
|
3175
3768
|
}
|
|
3176
3769
|
|
|
3177
|
-
content.push(
|
|
3770
|
+
content.push(...propertyParts);
|
|
3178
3771
|
if (shouldUseTrailingComma) {
|
|
3179
3772
|
content.push(',');
|
|
3180
3773
|
}
|
|
@@ -3184,6 +3777,14 @@ function printObjectExpression(node, path, options, print, args) {
|
|
|
3184
3777
|
return group([open_brace, indent(content.slice(0, -1)), content[content.length - 1], '}']);
|
|
3185
3778
|
}
|
|
3186
3779
|
|
|
3780
|
+
/**
|
|
3781
|
+
* Print a class declaration
|
|
3782
|
+
* @param {RippleASTNode} node - The class node
|
|
3783
|
+
* @param {AstPath<RippleASTNode>} path - The AST path
|
|
3784
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
3785
|
+
* @param {PrintFn} print - Print callback
|
|
3786
|
+
* @returns {Doc[]}
|
|
3787
|
+
*/
|
|
3187
3788
|
function printClassDeclaration(node, path, options, print) {
|
|
3188
3789
|
const parts = [];
|
|
3189
3790
|
parts.push('class');
|
|
@@ -3215,10 +3816,31 @@ function printClassDeclaration(node, path, options, print) {
|
|
|
3215
3816
|
return parts;
|
|
3216
3817
|
}
|
|
3217
3818
|
|
|
3819
|
+
/**
|
|
3820
|
+
* Print a try statement (with Ripple pending block extension)
|
|
3821
|
+
* @param {RippleASTNode} node - The try statement node
|
|
3822
|
+
* @param {AstPath<RippleASTNode>} path - The AST path
|
|
3823
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
3824
|
+
* @param {PrintFn} print - Print callback
|
|
3825
|
+
* @returns {Doc[]}
|
|
3826
|
+
*/
|
|
3218
3827
|
function printTryStatement(node, path, options, print) {
|
|
3828
|
+
// Extract leading comments from block node to print them before 'try' keyword
|
|
3829
|
+
const blockNode = node.block;
|
|
3830
|
+
|
|
3831
|
+
// Print block without its leading comments (they'll be printed before 'try')
|
|
3832
|
+
const block = path.call(
|
|
3833
|
+
(blockPath) => print(blockPath, { suppressLeadingComments: true }),
|
|
3834
|
+
'block',
|
|
3835
|
+
);
|
|
3836
|
+
|
|
3219
3837
|
const parts = [];
|
|
3838
|
+
|
|
3839
|
+
// Print leading comments from block node before 'try' keyword
|
|
3840
|
+
parts.push(...extractAndPrintLeadingComments(blockNode));
|
|
3841
|
+
|
|
3220
3842
|
parts.push('try ');
|
|
3221
|
-
parts.push(
|
|
3843
|
+
parts.push(block);
|
|
3222
3844
|
|
|
3223
3845
|
if (node.pending) {
|
|
3224
3846
|
parts.push(' pending ');
|
|
@@ -3244,6 +3866,14 @@ function printTryStatement(node, path, options, print) {
|
|
|
3244
3866
|
return parts;
|
|
3245
3867
|
}
|
|
3246
3868
|
|
|
3869
|
+
/**
|
|
3870
|
+
* Print a class body
|
|
3871
|
+
* @param {RippleASTNode} node - The class body node
|
|
3872
|
+
* @param {AstPath<RippleASTNode>} path - The AST path
|
|
3873
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
3874
|
+
* @param {PrintFn} print - Print callback
|
|
3875
|
+
* @returns {Doc}
|
|
3876
|
+
*/
|
|
3247
3877
|
function printClassBody(node, path, options, print) {
|
|
3248
3878
|
if (!node.body || node.body.length === 0) {
|
|
3249
3879
|
return '{}';
|
|
@@ -3266,9 +3896,17 @@ function printClassBody(node, path, options, print) {
|
|
|
3266
3896
|
contentParts.push(members[i]);
|
|
3267
3897
|
}
|
|
3268
3898
|
|
|
3269
|
-
return group(['{', indent(
|
|
3899
|
+
return group(['{', indent(contentParts), line, '}']);
|
|
3270
3900
|
}
|
|
3271
3901
|
|
|
3902
|
+
/**
|
|
3903
|
+
* Print a class property definition
|
|
3904
|
+
* @param {RippleASTNode} node - The property definition node
|
|
3905
|
+
* @param {AstPath<RippleASTNode>} path - The AST path
|
|
3906
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
3907
|
+
* @param {PrintFn} print - Print callback
|
|
3908
|
+
* @returns {Doc}
|
|
3909
|
+
*/
|
|
3272
3910
|
function printPropertyDefinition(node, path, options, print) {
|
|
3273
3911
|
const parts = [];
|
|
3274
3912
|
|
|
@@ -3310,9 +3948,17 @@ function printPropertyDefinition(node, path, options, print) {
|
|
|
3310
3948
|
|
|
3311
3949
|
parts.push(semi(options));
|
|
3312
3950
|
|
|
3313
|
-
return
|
|
3951
|
+
return parts;
|
|
3314
3952
|
}
|
|
3315
3953
|
|
|
3954
|
+
/**
|
|
3955
|
+
* Print a method definition
|
|
3956
|
+
* @param {RippleASTNode} node - The method definition node
|
|
3957
|
+
* @param {AstPath<RippleASTNode>} path - The AST path
|
|
3958
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
3959
|
+
* @param {PrintFn} print - Print callback
|
|
3960
|
+
* @returns {Doc}
|
|
3961
|
+
*/
|
|
3316
3962
|
function printMethodDefinition(node, path, options, print) {
|
|
3317
3963
|
const parts = [];
|
|
3318
3964
|
const is_component = node.value?.type === 'Component';
|
|
@@ -3350,7 +3996,7 @@ function printMethodDefinition(node, path, options, print) {
|
|
|
3350
3996
|
if (node.value.id) {
|
|
3351
3997
|
// takes care of component methods
|
|
3352
3998
|
parts.push(path.call(print, 'value'));
|
|
3353
|
-
return
|
|
3999
|
+
return parts;
|
|
3354
4000
|
}
|
|
3355
4001
|
|
|
3356
4002
|
parts.push('component ');
|
|
@@ -3370,10 +4016,12 @@ function printMethodDefinition(node, path, options, print) {
|
|
|
3370
4016
|
}
|
|
3371
4017
|
|
|
3372
4018
|
if (is_component) {
|
|
3373
|
-
|
|
3374
|
-
|
|
4019
|
+
const componentDoc = path.call(
|
|
4020
|
+
(childPath) => print(childPath, { skipComponentLabel: true }),
|
|
4021
|
+
'value',
|
|
3375
4022
|
);
|
|
3376
|
-
|
|
4023
|
+
parts.push(componentDoc);
|
|
4024
|
+
return parts;
|
|
3377
4025
|
}
|
|
3378
4026
|
|
|
3379
4027
|
// Parameters - use proper path.map for TypeScript support
|
|
@@ -3400,14 +4048,22 @@ function printMethodDefinition(node, path, options, print) {
|
|
|
3400
4048
|
parts.push('{}');
|
|
3401
4049
|
}
|
|
3402
4050
|
|
|
3403
|
-
return
|
|
4051
|
+
return parts;
|
|
3404
4052
|
}
|
|
3405
4053
|
|
|
4054
|
+
/**
|
|
4055
|
+
* Print a member expression (object.property or object[property])
|
|
4056
|
+
* @param {RippleASTNode} node - The member expression node
|
|
4057
|
+
* @param {AstPath<RippleASTNode>} path - The AST path
|
|
4058
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
4059
|
+
* @param {PrintFn} print - Print callback
|
|
4060
|
+
* @returns {Doc}
|
|
4061
|
+
*/
|
|
3406
4062
|
function printMemberExpression(node, path, options, print) {
|
|
3407
4063
|
let objectPart = path.call(print, 'object');
|
|
3408
4064
|
// Preserve parentheses around the object when present
|
|
3409
4065
|
if (node.object.metadata?.parenthesized) {
|
|
3410
|
-
objectPart =
|
|
4066
|
+
objectPart = ['(', objectPart, ')'];
|
|
3411
4067
|
}
|
|
3412
4068
|
const propertyPart = path.call(print, 'property');
|
|
3413
4069
|
|
|
@@ -3420,10 +4076,10 @@ function printMemberExpression(node, path, options, print) {
|
|
|
3420
4076
|
: trackedPrefix
|
|
3421
4077
|
? '.' + trackedPrefix + '['
|
|
3422
4078
|
: '[';
|
|
3423
|
-
result =
|
|
4079
|
+
result = [objectPart, openBracket, propertyPart, ']'];
|
|
3424
4080
|
} else {
|
|
3425
4081
|
const separator = node.optional ? '?.' : '.';
|
|
3426
|
-
result =
|
|
4082
|
+
result = [objectPart, separator, propertyPart];
|
|
3427
4083
|
}
|
|
3428
4084
|
|
|
3429
4085
|
// Preserve parentheses around the entire member expression when present
|
|
@@ -3431,15 +4087,23 @@ function printMemberExpression(node, path, options, print) {
|
|
|
3431
4087
|
// Check if there are leading comments - if so, use group with softlines to allow breaking
|
|
3432
4088
|
const hasLeadingComments = node.leadingComments && node.leadingComments.length > 0;
|
|
3433
4089
|
if (hasLeadingComments) {
|
|
3434
|
-
result = group(
|
|
4090
|
+
result = group(['(', indent([softline, result]), softline, ')']);
|
|
3435
4091
|
} else {
|
|
3436
|
-
result =
|
|
4092
|
+
result = ['(', result, ')'];
|
|
3437
4093
|
}
|
|
3438
4094
|
}
|
|
3439
4095
|
|
|
3440
4096
|
return result;
|
|
3441
4097
|
}
|
|
3442
4098
|
|
|
4099
|
+
/**
|
|
4100
|
+
* Print a unary expression
|
|
4101
|
+
* @param {RippleASTNode} node - The unary expression node
|
|
4102
|
+
* @param {AstPath<RippleASTNode>} path - The AST path
|
|
4103
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
4104
|
+
* @param {PrintFn} print - Print callback
|
|
4105
|
+
* @returns {Doc}
|
|
4106
|
+
*/
|
|
3443
4107
|
function printUnaryExpression(node, path, options, print) {
|
|
3444
4108
|
const parts = [];
|
|
3445
4109
|
|
|
@@ -3468,9 +4132,17 @@ function printUnaryExpression(node, path, options, print) {
|
|
|
3468
4132
|
parts.push(node.operator);
|
|
3469
4133
|
}
|
|
3470
4134
|
|
|
3471
|
-
return
|
|
4135
|
+
return parts;
|
|
3472
4136
|
}
|
|
3473
4137
|
|
|
4138
|
+
/**
|
|
4139
|
+
* Print a yield expression
|
|
4140
|
+
* @param {RippleASTNode} node - The yield expression node
|
|
4141
|
+
* @param {AstPath<RippleASTNode>} path - The AST path
|
|
4142
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
4143
|
+
* @param {PrintFn} print - Print callback
|
|
4144
|
+
* @returns {Doc[]}
|
|
4145
|
+
*/
|
|
3474
4146
|
function printYieldExpression(node, path, options, print) {
|
|
3475
4147
|
const parts = [];
|
|
3476
4148
|
parts.push('yield');
|
|
@@ -3487,6 +4159,14 @@ function printYieldExpression(node, path, options, print) {
|
|
|
3487
4159
|
return parts;
|
|
3488
4160
|
}
|
|
3489
4161
|
|
|
4162
|
+
/**
|
|
4163
|
+
* Print a new expression
|
|
4164
|
+
* @param {RippleASTNode} node - The new expression node
|
|
4165
|
+
* @param {AstPath<RippleASTNode>} path - The AST path
|
|
4166
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
4167
|
+
* @param {PrintFn} print - Print callback
|
|
4168
|
+
* @returns {Doc[]}
|
|
4169
|
+
*/
|
|
3490
4170
|
function printNewExpression(node, path, options, print) {
|
|
3491
4171
|
const parts = [];
|
|
3492
4172
|
parts.push('new ');
|
|
@@ -3514,6 +4194,14 @@ function printNewExpression(node, path, options, print) {
|
|
|
3514
4194
|
return parts;
|
|
3515
4195
|
}
|
|
3516
4196
|
|
|
4197
|
+
/**
|
|
4198
|
+
* Print a template literal
|
|
4199
|
+
* @param {RippleASTNode} node - The template literal node
|
|
4200
|
+
* @param {AstPath<RippleASTNode>} path - The AST path
|
|
4201
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
4202
|
+
* @param {PrintFn} print - Print callback
|
|
4203
|
+
* @returns {Doc[]}
|
|
4204
|
+
*/
|
|
3517
4205
|
function printTemplateLiteral(node, path, options, print) {
|
|
3518
4206
|
const parts = [];
|
|
3519
4207
|
parts.push('`');
|
|
@@ -3533,7 +4221,7 @@ function printTemplateLiteral(node, path, options, print) {
|
|
|
3533
4221
|
|
|
3534
4222
|
if (needsBreaking) {
|
|
3535
4223
|
// For expressions that break, use group with indent to format nicely
|
|
3536
|
-
parts.push(group(
|
|
4224
|
+
parts.push(group(['${', indent([softline, expressionDoc]), softline, '}']));
|
|
3537
4225
|
} else {
|
|
3538
4226
|
// For simple expressions, keep them inline
|
|
3539
4227
|
parts.push('${');
|
|
@@ -3551,6 +4239,14 @@ function printTemplateLiteral(node, path, options, print) {
|
|
|
3551
4239
|
return parts;
|
|
3552
4240
|
}
|
|
3553
4241
|
|
|
4242
|
+
/**
|
|
4243
|
+
* Print a tagged template expression
|
|
4244
|
+
* @param {RippleASTNode} node - The tagged template node
|
|
4245
|
+
* @param {AstPath<RippleASTNode>} path - The AST path
|
|
4246
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
4247
|
+
* @param {PrintFn} print - Print callback
|
|
4248
|
+
* @returns {Doc[]}
|
|
4249
|
+
*/
|
|
3554
4250
|
function printTaggedTemplateExpression(node, path, options, print) {
|
|
3555
4251
|
const parts = [];
|
|
3556
4252
|
parts.push(path.call(print, 'tag'));
|
|
@@ -3558,6 +4254,14 @@ function printTaggedTemplateExpression(node, path, options, print) {
|
|
|
3558
4254
|
return parts;
|
|
3559
4255
|
}
|
|
3560
4256
|
|
|
4257
|
+
/**
|
|
4258
|
+
* Print a throw statement
|
|
4259
|
+
* @param {RippleASTNode} node - The throw statement node
|
|
4260
|
+
* @param {AstPath<RippleASTNode>} path - The AST path
|
|
4261
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
4262
|
+
* @param {PrintFn} print - Print callback
|
|
4263
|
+
* @returns {Doc[]}
|
|
4264
|
+
*/
|
|
3561
4265
|
function printThrowStatement(node, path, options, print) {
|
|
3562
4266
|
const parts = [];
|
|
3563
4267
|
parts.push('throw ');
|
|
@@ -3566,6 +4270,14 @@ function printThrowStatement(node, path, options, print) {
|
|
|
3566
4270
|
return parts;
|
|
3567
4271
|
}
|
|
3568
4272
|
|
|
4273
|
+
/**
|
|
4274
|
+
* Print a TypeScript interface declaration
|
|
4275
|
+
* @param {RippleASTNode} node - The interface declaration node
|
|
4276
|
+
* @param {AstPath<RippleASTNode>} path - The AST path
|
|
4277
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
4278
|
+
* @param {PrintFn} print - Print callback
|
|
4279
|
+
* @returns {Doc}
|
|
4280
|
+
*/
|
|
3569
4281
|
function printTSInterfaceDeclaration(node, path, options, print) {
|
|
3570
4282
|
const parts = [];
|
|
3571
4283
|
parts.push('interface ');
|
|
@@ -3585,9 +4297,17 @@ function printTSInterfaceDeclaration(node, path, options, print) {
|
|
|
3585
4297
|
parts.push(' ');
|
|
3586
4298
|
parts.push(path.call(print, 'body'));
|
|
3587
4299
|
|
|
3588
|
-
return
|
|
4300
|
+
return parts;
|
|
3589
4301
|
}
|
|
3590
4302
|
|
|
4303
|
+
/**
|
|
4304
|
+
* Print a TypeScript interface body
|
|
4305
|
+
* @param {RippleASTNode} node - The interface body node
|
|
4306
|
+
* @param {AstPath<RippleASTNode>} path - The AST path
|
|
4307
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
4308
|
+
* @param {PrintFn} print - Print callback
|
|
4309
|
+
* @returns {Doc}
|
|
4310
|
+
*/
|
|
3591
4311
|
function printTSInterfaceBody(node, path, options, print) {
|
|
3592
4312
|
if (!node.body || node.body.length === 0) {
|
|
3593
4313
|
return '{}';
|
|
@@ -3596,11 +4316,19 @@ function printTSInterfaceBody(node, path, options, print) {
|
|
|
3596
4316
|
const members = path.map(print, 'body');
|
|
3597
4317
|
|
|
3598
4318
|
// Add semicolons to all members
|
|
3599
|
-
const membersWithSemicolons = members.map((member) =>
|
|
4319
|
+
const membersWithSemicolons = members.map((member) => [member, semi(options)]);
|
|
3600
4320
|
|
|
3601
4321
|
return group(['{', indent([hardline, join(hardline, membersWithSemicolons)]), hardline, '}']);
|
|
3602
4322
|
}
|
|
3603
4323
|
|
|
4324
|
+
/**
|
|
4325
|
+
* Print a TypeScript type alias declaration
|
|
4326
|
+
* @param {RippleASTNode} node - The type alias node
|
|
4327
|
+
* @param {AstPath<RippleASTNode>} path - The AST path
|
|
4328
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
4329
|
+
* @param {PrintFn} print - Print callback
|
|
4330
|
+
* @returns {Doc[]}
|
|
4331
|
+
*/
|
|
3604
4332
|
function printTSTypeAliasDeclaration(node, path, options, print) {
|
|
3605
4333
|
const parts = [];
|
|
3606
4334
|
parts.push('type ');
|
|
@@ -3617,6 +4345,14 @@ function printTSTypeAliasDeclaration(node, path, options, print) {
|
|
|
3617
4345
|
return parts;
|
|
3618
4346
|
}
|
|
3619
4347
|
|
|
4348
|
+
/**
|
|
4349
|
+
* Print a TypeScript enum declaration
|
|
4350
|
+
* @param {RippleASTNode} node - The enum declaration node
|
|
4351
|
+
* @param {AstPath<RippleASTNode>} path - The AST path
|
|
4352
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
4353
|
+
* @param {PrintFn} print - Print callback
|
|
4354
|
+
* @returns {Doc[]}
|
|
4355
|
+
*/
|
|
3620
4356
|
function printTSEnumDeclaration(node, path, options, print) {
|
|
3621
4357
|
const parts = [];
|
|
3622
4358
|
|
|
@@ -3647,7 +4383,7 @@ function printTSEnumDeclaration(node, path, options, print) {
|
|
|
3647
4383
|
parts.push(
|
|
3648
4384
|
group([
|
|
3649
4385
|
'{',
|
|
3650
|
-
indent([hardline,
|
|
4386
|
+
indent([hardline, membersWithCommas]),
|
|
3651
4387
|
options.trailingComma !== 'none' ? ',' : '',
|
|
3652
4388
|
hardline,
|
|
3653
4389
|
'}',
|
|
@@ -3655,9 +4391,17 @@ function printTSEnumDeclaration(node, path, options, print) {
|
|
|
3655
4391
|
);
|
|
3656
4392
|
}
|
|
3657
4393
|
|
|
3658
|
-
return
|
|
4394
|
+
return parts;
|
|
3659
4395
|
}
|
|
3660
4396
|
|
|
4397
|
+
/**
|
|
4398
|
+
* Print a TypeScript enum member
|
|
4399
|
+
* @param {RippleASTNode} node - The enum member node
|
|
4400
|
+
* @param {AstPath<RippleASTNode>} path - The AST path
|
|
4401
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
4402
|
+
* @param {PrintFn} print - Print callback
|
|
4403
|
+
* @returns {Doc}
|
|
4404
|
+
*/
|
|
3661
4405
|
function printTSEnumMember(node, path, options, print) {
|
|
3662
4406
|
const parts = [];
|
|
3663
4407
|
|
|
@@ -3675,9 +4419,17 @@ function printTSEnumMember(node, path, options, print) {
|
|
|
3675
4419
|
parts.push(path.call(print, 'initializer'));
|
|
3676
4420
|
}
|
|
3677
4421
|
|
|
3678
|
-
return
|
|
4422
|
+
return parts;
|
|
3679
4423
|
}
|
|
3680
4424
|
|
|
4425
|
+
/**
|
|
4426
|
+
* Print TypeScript type parameter declaration (<T, U extends V>)
|
|
4427
|
+
* @param {RippleASTNode} node - The type parameter declaration node
|
|
4428
|
+
* @param {AstPath<RippleASTNode>} path - The AST path
|
|
4429
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
4430
|
+
* @param {PrintFn} print - Print callback
|
|
4431
|
+
* @returns {Doc}
|
|
4432
|
+
*/
|
|
3681
4433
|
function printTSTypeParameterDeclaration(node, path, options, print) {
|
|
3682
4434
|
if (!node.params || node.params.length === 0) {
|
|
3683
4435
|
return '';
|
|
@@ -3697,6 +4449,14 @@ function printTSTypeParameterDeclaration(node, path, options, print) {
|
|
|
3697
4449
|
return parts;
|
|
3698
4450
|
}
|
|
3699
4451
|
|
|
4452
|
+
/**
|
|
4453
|
+
* Print a single TypeScript type parameter
|
|
4454
|
+
* @param {RippleASTNode} node - The type parameter node
|
|
4455
|
+
* @param {AstPath<RippleASTNode>} path - The AST path
|
|
4456
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
4457
|
+
* @param {PrintFn} print - Print callback
|
|
4458
|
+
* @returns {Doc[]}
|
|
4459
|
+
*/
|
|
3700
4460
|
function printTSTypeParameter(node, path, options, print) {
|
|
3701
4461
|
const parts = [];
|
|
3702
4462
|
parts.push(node.name);
|
|
@@ -3714,6 +4474,14 @@ function printTSTypeParameter(node, path, options, print) {
|
|
|
3714
4474
|
return parts;
|
|
3715
4475
|
}
|
|
3716
4476
|
|
|
4477
|
+
/**
|
|
4478
|
+
* Print TypeScript type parameter instantiation (<string, number>)
|
|
4479
|
+
* @param {RippleASTNode} node - The type parameter instantiation node
|
|
4480
|
+
* @param {AstPath<RippleASTNode>} path - The AST path
|
|
4481
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
4482
|
+
* @param {PrintFn} print - Print callback
|
|
4483
|
+
* @returns {Doc}
|
|
4484
|
+
*/
|
|
3717
4485
|
function printTSTypeParameterInstantiation(node, path, options, print) {
|
|
3718
4486
|
if (!node.params || node.params.length === 0) {
|
|
3719
4487
|
return '';
|
|
@@ -3725,6 +4493,7 @@ function printTSTypeParameterInstantiation(node, path, options, print) {
|
|
|
3725
4493
|
const hasBreakingParam = paramList.some((param) => willBreak(param));
|
|
3726
4494
|
|
|
3727
4495
|
// Build inline version: <T, U>
|
|
4496
|
+
/** @type {Doc[]} */
|
|
3728
4497
|
const inlineParts = ['<'];
|
|
3729
4498
|
for (let i = 0; i < paramList.length; i++) {
|
|
3730
4499
|
if (i > 0) inlineParts.push(', ');
|
|
@@ -3740,7 +4509,7 @@ function printTSTypeParameterInstantiation(node, path, options, print) {
|
|
|
3740
4509
|
if (i > 0) breakingParts.push(',', hardline);
|
|
3741
4510
|
breakingParts.push(paramList[i]);
|
|
3742
4511
|
}
|
|
3743
|
-
return group(
|
|
4512
|
+
return group(['<', indent([hardline, ...breakingParts]), hardline, '>']);
|
|
3744
4513
|
}
|
|
3745
4514
|
|
|
3746
4515
|
// Otherwise use group to allow natural breaking
|
|
@@ -3750,31 +4519,63 @@ function printTSTypeParameterInstantiation(node, path, options, print) {
|
|
|
3750
4519
|
parts.push(paramList[i]);
|
|
3751
4520
|
}
|
|
3752
4521
|
|
|
3753
|
-
return group(
|
|
4522
|
+
return group(['<', indent([softline, ...parts]), softline, '>']);
|
|
3754
4523
|
}
|
|
3755
4524
|
|
|
4525
|
+
/**
|
|
4526
|
+
* Print a switch statement
|
|
4527
|
+
* @param {RippleASTNode} node - The switch statement node
|
|
4528
|
+
* @param {AstPath<RippleASTNode>} path - The AST path
|
|
4529
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
4530
|
+
* @param {PrintFn} print - Print callback
|
|
4531
|
+
* @returns {Doc}
|
|
4532
|
+
*/
|
|
3756
4533
|
function printSwitchStatement(node, path, options, print) {
|
|
3757
|
-
|
|
3758
|
-
|
|
4534
|
+
// Extract leading comments from discriminant node to print them before 'switch' keyword
|
|
4535
|
+
const discriminantNode = node.discriminant;
|
|
4536
|
+
|
|
4537
|
+
// Print discriminant without its leading comments (they'll be printed before 'switch')
|
|
4538
|
+
const discriminant = path.call(
|
|
4539
|
+
(discriminantPath) => print(discriminantPath, { suppressLeadingComments: true }),
|
|
4540
|
+
'discriminant',
|
|
3759
4541
|
);
|
|
3760
4542
|
|
|
4543
|
+
const parts = [];
|
|
4544
|
+
|
|
4545
|
+
// Print leading comments from discriminant node before 'switch' keyword
|
|
4546
|
+
parts.push(...extractAndPrintLeadingComments(discriminantNode));
|
|
4547
|
+
|
|
4548
|
+
const discriminantDoc = group(['switch (', indent([softline, discriminant]), softline, ')']);
|
|
4549
|
+
|
|
4550
|
+
parts.push(discriminantDoc);
|
|
4551
|
+
|
|
3761
4552
|
const cases = [];
|
|
3762
4553
|
for (let i = 0; i < node.cases.length; i++) {
|
|
3763
4554
|
const caseDoc = [path.call(print, 'cases', i)];
|
|
3764
4555
|
if (i < node.cases.length - 1 && isNextLineEmpty(node.cases[i], options)) {
|
|
3765
4556
|
caseDoc.push(hardline);
|
|
3766
4557
|
}
|
|
3767
|
-
cases.push(
|
|
4558
|
+
cases.push(caseDoc);
|
|
3768
4559
|
}
|
|
3769
4560
|
|
|
3770
4561
|
const bodyDoc =
|
|
3771
|
-
cases.length > 0 ?
|
|
4562
|
+
cases.length > 0 ? [indent([hardline, join(hardline, cases)]), hardline] : hardline;
|
|
3772
4563
|
|
|
3773
|
-
|
|
4564
|
+
parts.push(' {', bodyDoc, '}');
|
|
4565
|
+
|
|
4566
|
+
return parts;
|
|
3774
4567
|
}
|
|
3775
4568
|
|
|
4569
|
+
/**
|
|
4570
|
+
* Print a switch case
|
|
4571
|
+
* @param {RippleASTNode} node - The switch case node
|
|
4572
|
+
* @param {AstPath<RippleASTNode>} path - The AST path
|
|
4573
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
4574
|
+
* @param {PrintFn} print - Print callback
|
|
4575
|
+
* @returns {Doc}
|
|
4576
|
+
*/
|
|
3776
4577
|
function printSwitchCase(node, path, options, print) {
|
|
3777
|
-
const header = node.test ?
|
|
4578
|
+
const header = node.test ? ['case ', path.call(print, 'test'), ':'] : 'default:';
|
|
3778
4579
|
|
|
3779
4580
|
const consequents = node.consequent || [];
|
|
3780
4581
|
const printedConsequents = [];
|
|
@@ -3794,7 +4595,7 @@ function printSwitchCase(node, path, options, print) {
|
|
|
3794
4595
|
const singleBlock =
|
|
3795
4596
|
printedConsequents.length === 1 && referencedConsequents[0].type === 'BlockStatement';
|
|
3796
4597
|
if (singleBlock) {
|
|
3797
|
-
bodyDoc =
|
|
4598
|
+
bodyDoc = [' ', printedConsequents[0]];
|
|
3798
4599
|
} else {
|
|
3799
4600
|
bodyDoc = indent([hardline, join(hardline, printedConsequents)]);
|
|
3800
4601
|
}
|
|
@@ -3816,17 +4617,16 @@ function printSwitchCase(node, path, options, print) {
|
|
|
3816
4617
|
commentDocs.push(hardline);
|
|
3817
4618
|
}
|
|
3818
4619
|
const commentDoc =
|
|
3819
|
-
comment.type === 'Line'
|
|
3820
|
-
? concat(['//', comment.value])
|
|
3821
|
-
: concat(['/*', comment.value, '*/']);
|
|
4620
|
+
comment.type === 'Line' ? ['//', comment.value] : ['/*', comment.value, '*/'];
|
|
3822
4621
|
commentDocs.push(commentDoc);
|
|
3823
4622
|
previousNode = comment;
|
|
3824
4623
|
}
|
|
3825
4624
|
|
|
3826
|
-
trailingDoc =
|
|
4625
|
+
trailingDoc = commentDocs;
|
|
3827
4626
|
delete node.trailingComments;
|
|
3828
4627
|
}
|
|
3829
4628
|
|
|
4629
|
+
/** @type {Doc[]} */
|
|
3830
4630
|
const parts = [header];
|
|
3831
4631
|
if (bodyDoc) {
|
|
3832
4632
|
parts.push(bodyDoc);
|
|
@@ -3835,9 +4635,17 @@ function printSwitchCase(node, path, options, print) {
|
|
|
3835
4635
|
parts.push(trailingDoc);
|
|
3836
4636
|
}
|
|
3837
4637
|
|
|
3838
|
-
return
|
|
4638
|
+
return parts;
|
|
3839
4639
|
}
|
|
3840
4640
|
|
|
4641
|
+
/**
|
|
4642
|
+
* Print a break statement
|
|
4643
|
+
* @param {RippleASTNode} node - The break statement node
|
|
4644
|
+
* @param {AstPath<RippleASTNode>} path - The AST path
|
|
4645
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
4646
|
+
* @param {PrintFn} print - Print callback
|
|
4647
|
+
* @returns {Doc[]}
|
|
4648
|
+
*/
|
|
3841
4649
|
function printBreakStatement(node, path, options, print) {
|
|
3842
4650
|
const parts = [];
|
|
3843
4651
|
parts.push('break');
|
|
@@ -3849,6 +4657,14 @@ function printBreakStatement(node, path, options, print) {
|
|
|
3849
4657
|
return parts;
|
|
3850
4658
|
}
|
|
3851
4659
|
|
|
4660
|
+
/**
|
|
4661
|
+
* Print a continue statement
|
|
4662
|
+
* @param {RippleASTNode} node - The continue statement node
|
|
4663
|
+
* @param {AstPath<RippleASTNode>} path - The AST path
|
|
4664
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
4665
|
+
* @param {PrintFn} print - Print callback
|
|
4666
|
+
* @returns {Doc[]}
|
|
4667
|
+
*/
|
|
3852
4668
|
function printContinueStatement(node, path, options, print) {
|
|
3853
4669
|
const parts = [];
|
|
3854
4670
|
parts.push('continue');
|
|
@@ -3860,10 +4676,25 @@ function printContinueStatement(node, path, options, print) {
|
|
|
3860
4676
|
return parts;
|
|
3861
4677
|
}
|
|
3862
4678
|
|
|
3863
|
-
|
|
4679
|
+
/**
|
|
4680
|
+
* Print a debugger statement
|
|
4681
|
+
* @param {RippleASTNode} node - The debugger statement node
|
|
4682
|
+
* @param {AstPath<RippleASTNode>} path - The AST path
|
|
4683
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
4684
|
+
* @returns {string}
|
|
4685
|
+
*/
|
|
4686
|
+
function printDebuggerStatement(node, path, options) {
|
|
3864
4687
|
return 'debugger' + semi(options);
|
|
3865
4688
|
}
|
|
3866
4689
|
|
|
4690
|
+
/**
|
|
4691
|
+
* Print a sequence expression
|
|
4692
|
+
* @param {RippleASTNode} node - The sequence expression node
|
|
4693
|
+
* @param {AstPath<RippleASTNode>} path - The AST path
|
|
4694
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
4695
|
+
* @param {PrintFn} print - Print callback
|
|
4696
|
+
* @returns {Doc[]}
|
|
4697
|
+
*/
|
|
3867
4698
|
function printSequenceExpression(node, path, options, print) {
|
|
3868
4699
|
const parts = [];
|
|
3869
4700
|
parts.push('(');
|
|
@@ -3876,6 +4707,12 @@ function printSequenceExpression(node, path, options, print) {
|
|
|
3876
4707
|
return parts;
|
|
3877
4708
|
}
|
|
3878
4709
|
|
|
4710
|
+
/**
|
|
4711
|
+
* Get number of blank lines between two positions
|
|
4712
|
+
* @param {{ line: number }} current_pos - Current position
|
|
4713
|
+
* @param {{ line: number }} next_pos - Next position
|
|
4714
|
+
* @returns {number}
|
|
4715
|
+
*/
|
|
3879
4716
|
function getBlankLinesBetweenPositions(current_pos, next_pos) {
|
|
3880
4717
|
const line_gap = next_pos.line - current_pos.line;
|
|
3881
4718
|
|
|
@@ -3885,6 +4722,12 @@ function getBlankLinesBetweenPositions(current_pos, next_pos) {
|
|
|
3885
4722
|
return Math.max(0, line_gap - 1);
|
|
3886
4723
|
}
|
|
3887
4724
|
|
|
4725
|
+
/**
|
|
4726
|
+
* Get number of blank lines between two nodes
|
|
4727
|
+
* @param {RippleASTNode} currentNode - Current node
|
|
4728
|
+
* @param {RippleASTNode} nextNode - Next node
|
|
4729
|
+
* @returns {number}
|
|
4730
|
+
*/
|
|
3888
4731
|
function getBlankLinesBetweenNodes(currentNode, nextNode) {
|
|
3889
4732
|
// Return the number of blank lines between two nodes based on their location
|
|
3890
4733
|
if (
|
|
@@ -3900,6 +4743,12 @@ function getBlankLinesBetweenNodes(currentNode, nextNode) {
|
|
|
3900
4743
|
return 0;
|
|
3901
4744
|
}
|
|
3902
4745
|
|
|
4746
|
+
/**
|
|
4747
|
+
* Determine if a blank line should be added between nodes
|
|
4748
|
+
* @param {RippleASTNode} currentNode - Current node
|
|
4749
|
+
* @param {RippleASTNode} nextNode - Next node
|
|
4750
|
+
* @returns {boolean}
|
|
4751
|
+
*/
|
|
3903
4752
|
function shouldAddBlankLine(currentNode, nextNode) {
|
|
3904
4753
|
// Simplified blank line logic:
|
|
3905
4754
|
// 1. Check if there was originally 1+ blank lines between nodes
|
|
@@ -3934,11 +4783,19 @@ function shouldAddBlankLine(currentNode, nextNode) {
|
|
|
3934
4783
|
return originalBlankLines > 0;
|
|
3935
4784
|
}
|
|
3936
4785
|
|
|
4786
|
+
/**
|
|
4787
|
+
* Print an object pattern (destructuring)
|
|
4788
|
+
* @param {RippleASTNode} node - The object pattern node
|
|
4789
|
+
* @param {AstPath<RippleASTNode>} path - The AST path
|
|
4790
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
4791
|
+
* @param {PrintFn} print - Print callback
|
|
4792
|
+
* @returns {Doc}
|
|
4793
|
+
*/
|
|
3937
4794
|
function printObjectPattern(node, path, options, print) {
|
|
3938
4795
|
const propList = path.map(print, 'properties');
|
|
3939
4796
|
if (propList.length === 0) {
|
|
3940
4797
|
if (node.typeAnnotation) {
|
|
3941
|
-
return
|
|
4798
|
+
return ['{}', ': ', path.call(print, 'typeAnnotation')];
|
|
3942
4799
|
}
|
|
3943
4800
|
return '{}';
|
|
3944
4801
|
}
|
|
@@ -3966,49 +4823,53 @@ function printObjectPattern(node, path, options, print) {
|
|
|
3966
4823
|
|
|
3967
4824
|
// Use softline for proper spacing - will become space when inline, line when breaking
|
|
3968
4825
|
// Format type members with semicolons between AND after the last member
|
|
3969
|
-
const typeMemberDocs = join(
|
|
4826
|
+
const typeMemberDocs = join([';', line], typeMembers);
|
|
3970
4827
|
|
|
3971
4828
|
// Don't wrap in group - let the outer params group control breaking
|
|
3972
|
-
const objectDoc =
|
|
4829
|
+
const objectDoc = [
|
|
3973
4830
|
'{',
|
|
3974
|
-
indent(
|
|
4831
|
+
indent([line, join([',', line], propList), trailingCommaDoc]),
|
|
3975
4832
|
line,
|
|
3976
4833
|
'}',
|
|
3977
|
-
]
|
|
4834
|
+
];
|
|
3978
4835
|
const typeDoc =
|
|
3979
4836
|
typeMembers.length === 0
|
|
3980
4837
|
? '{}'
|
|
3981
|
-
:
|
|
4838
|
+
: ['{', indent([line, typeMemberDocs, ifBreak(';', '')]), line, '}'];
|
|
3982
4839
|
|
|
3983
4840
|
// Return combined
|
|
3984
|
-
return
|
|
4841
|
+
return [objectDoc, ': ', typeDoc];
|
|
3985
4842
|
}
|
|
3986
4843
|
|
|
3987
4844
|
// For other type annotations, just concatenate
|
|
3988
|
-
const objectContent = group(
|
|
3989
|
-
concat([
|
|
3990
|
-
'{',
|
|
3991
|
-
indent(concat([line, join(concat([',', line]), propList), trailingCommaDoc])),
|
|
3992
|
-
line,
|
|
3993
|
-
'}',
|
|
3994
|
-
]),
|
|
3995
|
-
);
|
|
3996
|
-
return concat([objectContent, ': ', path.call(print, 'typeAnnotation')]);
|
|
3997
|
-
}
|
|
3998
|
-
|
|
3999
|
-
// No type annotation - just format the object pattern
|
|
4000
|
-
const objectContent = group(
|
|
4001
|
-
concat([
|
|
4845
|
+
const objectContent = group([
|
|
4002
4846
|
'{',
|
|
4003
|
-
indent(
|
|
4847
|
+
indent([line, join([',', line], propList), trailingCommaDoc]),
|
|
4004
4848
|
line,
|
|
4005
4849
|
'}',
|
|
4006
|
-
])
|
|
4007
|
-
|
|
4850
|
+
]);
|
|
4851
|
+
return [objectContent, ': ', path.call(print, 'typeAnnotation')];
|
|
4852
|
+
}
|
|
4853
|
+
|
|
4854
|
+
// No type annotation - just format the object pattern
|
|
4855
|
+
const objectContent = group([
|
|
4856
|
+
'{',
|
|
4857
|
+
indent([line, join([',', line], propList), trailingCommaDoc]),
|
|
4858
|
+
line,
|
|
4859
|
+
'}',
|
|
4860
|
+
]);
|
|
4008
4861
|
|
|
4009
4862
|
return objectContent;
|
|
4010
4863
|
}
|
|
4011
4864
|
|
|
4865
|
+
/**
|
|
4866
|
+
* Print an array pattern (destructuring)
|
|
4867
|
+
* @param {RippleASTNode} node - The array pattern node
|
|
4868
|
+
* @param {AstPath<RippleASTNode>} path - The AST path
|
|
4869
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
4870
|
+
* @param {PrintFn} print - Print callback
|
|
4871
|
+
* @returns {Doc}
|
|
4872
|
+
*/
|
|
4012
4873
|
function printArrayPattern(node, path, options, print) {
|
|
4013
4874
|
const parts = [];
|
|
4014
4875
|
parts.push('[');
|
|
@@ -4024,9 +4885,17 @@ function printArrayPattern(node, path, options, print) {
|
|
|
4024
4885
|
parts.push(path.call(print, 'typeAnnotation'));
|
|
4025
4886
|
}
|
|
4026
4887
|
|
|
4027
|
-
return
|
|
4888
|
+
return parts;
|
|
4028
4889
|
}
|
|
4029
4890
|
|
|
4891
|
+
/**
|
|
4892
|
+
* Print a property (object property or method)
|
|
4893
|
+
* @param {RippleASTNode} node - The property node
|
|
4894
|
+
* @param {AstPath<RippleASTNode>} path - The AST path
|
|
4895
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
4896
|
+
* @param {PrintFn} print - Print callback
|
|
4897
|
+
* @returns {Doc}
|
|
4898
|
+
*/
|
|
4030
4899
|
function printProperty(node, path, options, print) {
|
|
4031
4900
|
if (node.shorthand) {
|
|
4032
4901
|
// For shorthand properties, if value is AssignmentPattern, print the value (which includes the default)
|
|
@@ -4062,7 +4931,7 @@ function printProperty(node, path, options, print) {
|
|
|
4062
4931
|
}
|
|
4063
4932
|
|
|
4064
4933
|
methodParts.push(' ', path.call(print, 'value', 'body'));
|
|
4065
|
-
return
|
|
4934
|
+
return methodParts;
|
|
4066
4935
|
}
|
|
4067
4936
|
|
|
4068
4937
|
// Handle method shorthand: increment() {} instead of increment: function() {}
|
|
@@ -4085,11 +4954,16 @@ function printProperty(node, path, options, print) {
|
|
|
4085
4954
|
|
|
4086
4955
|
methodParts.push(...printKey(node, path, options, print));
|
|
4087
4956
|
|
|
4957
|
+
// Handle type parameters (generics)
|
|
4958
|
+
if (funcValue.typeParameters) {
|
|
4959
|
+
methodParts.push(path.call(print, 'value', 'typeParameters'));
|
|
4960
|
+
}
|
|
4961
|
+
|
|
4088
4962
|
if (is_component) {
|
|
4089
4963
|
methodParts.push(
|
|
4090
4964
|
path.call((childPath) => print(childPath, { skipComponentLabel: true }), 'value'),
|
|
4091
4965
|
);
|
|
4092
|
-
return
|
|
4966
|
+
return methodParts;
|
|
4093
4967
|
}
|
|
4094
4968
|
|
|
4095
4969
|
// Print parameters by calling into the value path
|
|
@@ -4105,7 +4979,7 @@ function printProperty(node, path, options, print) {
|
|
|
4105
4979
|
}
|
|
4106
4980
|
|
|
4107
4981
|
methodParts.push(' ', path.call(print, 'value', 'body'));
|
|
4108
|
-
return
|
|
4982
|
+
return methodParts;
|
|
4109
4983
|
}
|
|
4110
4984
|
|
|
4111
4985
|
const parts = [];
|
|
@@ -4113,9 +4987,17 @@ function printProperty(node, path, options, print) {
|
|
|
4113
4987
|
|
|
4114
4988
|
parts.push(': ');
|
|
4115
4989
|
parts.push(path.call(print, 'value'));
|
|
4116
|
-
return
|
|
4990
|
+
return parts;
|
|
4117
4991
|
}
|
|
4118
4992
|
|
|
4993
|
+
/**
|
|
4994
|
+
* Print a variable declarator
|
|
4995
|
+
* @param {RippleASTNode} node - The variable declarator node
|
|
4996
|
+
* @param {AstPath<RippleASTNode>} path - The AST path
|
|
4997
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
4998
|
+
* @param {PrintFn} print - Print callback
|
|
4999
|
+
* @returns {Doc}
|
|
5000
|
+
*/
|
|
4119
5001
|
function printVariableDeclarator(node, path, options, print) {
|
|
4120
5002
|
if (node.init) {
|
|
4121
5003
|
const id = path.call(print, 'id');
|
|
@@ -4143,7 +5025,7 @@ function printVariableDeclarator(node, path, options, print) {
|
|
|
4143
5025
|
node.init.alternate.type === 'ConditionalExpression';
|
|
4144
5026
|
|
|
4145
5027
|
if (ternaryWillBreak || hasComplexBranch || hasComplexTest || hasNestedTernary) {
|
|
4146
|
-
return
|
|
5028
|
+
return [id, ' =', indent([line, init])];
|
|
4147
5029
|
}
|
|
4148
5030
|
}
|
|
4149
5031
|
|
|
@@ -4187,9 +5069,9 @@ function printVariableDeclarator(node, path, options, print) {
|
|
|
4187
5069
|
// Prettier picks the broken version if inline doesn't fit
|
|
4188
5070
|
return conditionalGroup([
|
|
4189
5071
|
// Try inline first
|
|
4190
|
-
|
|
5072
|
+
[id, ' = ', init],
|
|
4191
5073
|
// Fall back to broken with extra indent
|
|
4192
|
-
|
|
5074
|
+
[id, ' =', indent([line, init])],
|
|
4193
5075
|
]);
|
|
4194
5076
|
}
|
|
4195
5077
|
}
|
|
@@ -4201,7 +5083,7 @@ function printVariableDeclarator(node, path, options, print) {
|
|
|
4201
5083
|
if (isBinaryish) {
|
|
4202
5084
|
// Use Prettier's break-after-operator strategy: break after = and let the expression break naturally
|
|
4203
5085
|
const init = path.call(print, 'init');
|
|
4204
|
-
return group([group(id), ' =', group(indent(
|
|
5086
|
+
return group([group(id), ' =', group(indent([line, init]))]);
|
|
4205
5087
|
}
|
|
4206
5088
|
// For CallExpression inits, use fluid layout strategy to break after = if needed
|
|
4207
5089
|
const isCallExpression = node.init.type === 'CallExpression';
|
|
@@ -4222,17 +5104,33 @@ function printVariableDeclarator(node, path, options, print) {
|
|
|
4222
5104
|
|
|
4223
5105
|
// Default: simple inline format with space
|
|
4224
5106
|
// Use group to allow breaking if needed - but keep inline when it fits
|
|
4225
|
-
return group(
|
|
5107
|
+
return group([id, ' = ', init]);
|
|
4226
5108
|
}
|
|
4227
5109
|
|
|
4228
5110
|
return path.call(print, 'id');
|
|
4229
5111
|
}
|
|
4230
5112
|
|
|
5113
|
+
/**
|
|
5114
|
+
* Print an assignment pattern (default parameter)
|
|
5115
|
+
* @param {RippleASTNode} node - The assignment pattern node
|
|
5116
|
+
* @param {AstPath<RippleASTNode>} path - The AST path
|
|
5117
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
5118
|
+
* @param {PrintFn} print - Print callback
|
|
5119
|
+
* @returns {Doc}
|
|
5120
|
+
*/
|
|
4231
5121
|
function printAssignmentPattern(node, path, options, print) {
|
|
4232
5122
|
// Handle default parameters like: count: number = 0
|
|
4233
|
-
return
|
|
5123
|
+
return [path.call(print, 'left'), ' = ', path.call(print, 'right')];
|
|
4234
5124
|
}
|
|
4235
5125
|
|
|
5126
|
+
/**
|
|
5127
|
+
* Print a TypeScript type literal
|
|
5128
|
+
* @param {RippleASTNode} node - The type literal node
|
|
5129
|
+
* @param {AstPath<RippleASTNode>} path - The AST path
|
|
5130
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
5131
|
+
* @param {PrintFn} print - Print callback
|
|
5132
|
+
* @returns {Doc}
|
|
5133
|
+
*/
|
|
4236
5134
|
function printTSTypeLiteral(node, path, options, print) {
|
|
4237
5135
|
if (!node.members || node.members.length === 0) {
|
|
4238
5136
|
return '{}';
|
|
@@ -4240,23 +5138,32 @@ function printTSTypeLiteral(node, path, options, print) {
|
|
|
4240
5138
|
|
|
4241
5139
|
const members = path.map(print, 'members');
|
|
4242
5140
|
const inlineMembers = members.map((member, index) =>
|
|
4243
|
-
index < members.length - 1 ?
|
|
5141
|
+
index < members.length - 1 ? [member, ';'] : member,
|
|
4244
5142
|
);
|
|
4245
|
-
const multilineMembers = members.map((member) =>
|
|
5143
|
+
const multilineMembers = members.map((member) => [member, ';']);
|
|
4246
5144
|
|
|
4247
|
-
const inlineDoc = group(
|
|
4248
|
-
concat(['{', indent(concat([line, join(line, inlineMembers)])), line, '}']),
|
|
4249
|
-
);
|
|
5145
|
+
const inlineDoc = group(['{', indent([line, join(line, inlineMembers)]), line, '}']);
|
|
4250
5146
|
|
|
4251
|
-
const multilineDoc = group(
|
|
4252
|
-
|
|
4253
|
-
|
|
5147
|
+
const multilineDoc = group([
|
|
5148
|
+
'{',
|
|
5149
|
+
indent([hardline, join(hardline, multilineMembers)]),
|
|
5150
|
+
hardline,
|
|
5151
|
+
'}',
|
|
5152
|
+
]);
|
|
4254
5153
|
|
|
4255
5154
|
return conditionalGroup(
|
|
4256
5155
|
wasOriginallySingleLine(node) ? [inlineDoc, multilineDoc] : [multilineDoc, inlineDoc],
|
|
4257
5156
|
);
|
|
4258
5157
|
}
|
|
4259
5158
|
|
|
5159
|
+
/**
|
|
5160
|
+
* Print a TypeScript property signature in an interface
|
|
5161
|
+
* @param {RippleASTNode} node - The property signature node
|
|
5162
|
+
* @param {AstPath<RippleASTNode>} path - The AST path
|
|
5163
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
5164
|
+
* @param {PrintFn} print - Print callback
|
|
5165
|
+
* @returns {Doc}
|
|
5166
|
+
*/
|
|
4260
5167
|
function printTSPropertySignature(node, path, options, print) {
|
|
4261
5168
|
const parts = [];
|
|
4262
5169
|
parts.push(path.call(print, 'key'));
|
|
@@ -4270,9 +5177,17 @@ function printTSPropertySignature(node, path, options, print) {
|
|
|
4270
5177
|
parts.push(path.call(print, 'typeAnnotation'));
|
|
4271
5178
|
}
|
|
4272
5179
|
|
|
4273
|
-
return
|
|
5180
|
+
return parts;
|
|
4274
5181
|
}
|
|
4275
5182
|
|
|
5183
|
+
/**
|
|
5184
|
+
* Print a TypeScript method signature in an interface
|
|
5185
|
+
* @param {RippleASTNode} node - The method signature node
|
|
5186
|
+
* @param {AstPath<RippleASTNode>} path - The AST path
|
|
5187
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
5188
|
+
* @param {PrintFn} print - Print callback
|
|
5189
|
+
* @returns {Doc}
|
|
5190
|
+
*/
|
|
4276
5191
|
function printTSMethodSignature(node, path, options, print) {
|
|
4277
5192
|
const parts = [];
|
|
4278
5193
|
|
|
@@ -4311,9 +5226,17 @@ function printTSMethodSignature(node, path, options, print) {
|
|
|
4311
5226
|
parts.push(path.call(print, 'typeAnnotation'));
|
|
4312
5227
|
}
|
|
4313
5228
|
|
|
4314
|
-
return
|
|
5229
|
+
return parts;
|
|
4315
5230
|
}
|
|
4316
5231
|
|
|
5232
|
+
/**
|
|
5233
|
+
* Print a TypeScript type reference (e.g., Array<string>)
|
|
5234
|
+
* @param {RippleASTNode} node - The type reference node
|
|
5235
|
+
* @param {AstPath<RippleASTNode>} path - The AST path
|
|
5236
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
5237
|
+
* @param {PrintFn} print - Print callback
|
|
5238
|
+
* @returns {Doc}
|
|
5239
|
+
*/
|
|
4317
5240
|
function printTSTypeReference(node, path, options, print) {
|
|
4318
5241
|
const parts = [path.call(print, 'typeName')];
|
|
4319
5242
|
|
|
@@ -4336,10 +5259,19 @@ function printTSTypeReference(node, path, options, print) {
|
|
|
4336
5259
|
parts.push('>');
|
|
4337
5260
|
}
|
|
4338
5261
|
|
|
4339
|
-
return
|
|
5262
|
+
return parts;
|
|
4340
5263
|
}
|
|
4341
5264
|
|
|
5265
|
+
/**
|
|
5266
|
+
* Print a TypeScript tuple type
|
|
5267
|
+
* @param {RippleASTNode} node - The tuple type node
|
|
5268
|
+
* @param {AstPath<RippleASTNode>} path - The AST path
|
|
5269
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
5270
|
+
* @param {PrintFn} print - Print callback
|
|
5271
|
+
* @returns {Doc}
|
|
5272
|
+
*/
|
|
4342
5273
|
function printTSTupleType(node, path, options, print) {
|
|
5274
|
+
/** @type {Doc[]} */
|
|
4343
5275
|
const parts = ['['];
|
|
4344
5276
|
const elements = node.elementTypes ? path.map(print, 'elementTypes') : [];
|
|
4345
5277
|
for (let i = 0; i < elements.length; i++) {
|
|
@@ -4347,9 +5279,17 @@ function printTSTupleType(node, path, options, print) {
|
|
|
4347
5279
|
parts.push(elements[i]);
|
|
4348
5280
|
}
|
|
4349
5281
|
parts.push(']');
|
|
4350
|
-
return
|
|
5282
|
+
return parts;
|
|
4351
5283
|
}
|
|
4352
5284
|
|
|
5285
|
+
/**
|
|
5286
|
+
* Print a TypeScript index signature
|
|
5287
|
+
* @param {RippleASTNode} node - The index signature node
|
|
5288
|
+
* @param {AstPath<RippleASTNode>} path - The AST path
|
|
5289
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
5290
|
+
* @param {PrintFn} print - Print callback
|
|
5291
|
+
* @returns {Doc}
|
|
5292
|
+
*/
|
|
4353
5293
|
function printTSIndexSignature(node, path, options, print) {
|
|
4354
5294
|
const parts = [];
|
|
4355
5295
|
if (node.readonly === true || node.readonly === 'plus' || node.readonly === '+') {
|
|
@@ -4371,9 +5311,17 @@ function printTSIndexSignature(node, path, options, print) {
|
|
|
4371
5311
|
parts.push(path.call(print, 'typeAnnotation'));
|
|
4372
5312
|
}
|
|
4373
5313
|
|
|
4374
|
-
return
|
|
5314
|
+
return parts;
|
|
4375
5315
|
}
|
|
4376
5316
|
|
|
5317
|
+
/**
|
|
5318
|
+
* Print a TypeScript constructor type
|
|
5319
|
+
* @param {RippleASTNode} node - The constructor type node
|
|
5320
|
+
* @param {AstPath<RippleASTNode>} path - The AST path
|
|
5321
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
5322
|
+
* @param {PrintFn} print - Print callback
|
|
5323
|
+
* @returns {Doc}
|
|
5324
|
+
*/
|
|
4377
5325
|
function printTSConstructorType(node, path, options, print) {
|
|
4378
5326
|
const parts = [];
|
|
4379
5327
|
parts.push('new ');
|
|
@@ -4394,9 +5342,17 @@ function printTSConstructorType(node, path, options, print) {
|
|
|
4394
5342
|
} else if (node.typeAnnotation) {
|
|
4395
5343
|
parts.push(path.call(print, 'typeAnnotation'));
|
|
4396
5344
|
}
|
|
4397
|
-
return
|
|
5345
|
+
return parts;
|
|
4398
5346
|
}
|
|
4399
5347
|
|
|
5348
|
+
/**
|
|
5349
|
+
* Print a TypeScript conditional type
|
|
5350
|
+
* @param {RippleASTNode} node - The conditional type node
|
|
5351
|
+
* @param {AstPath<RippleASTNode>} path - The AST path
|
|
5352
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
5353
|
+
* @param {PrintFn} print - Print callback
|
|
5354
|
+
* @returns {Doc}
|
|
5355
|
+
*/
|
|
4400
5356
|
function printTSConditionalType(node, path, options, print) {
|
|
4401
5357
|
const parts = [];
|
|
4402
5358
|
parts.push(path.call(print, 'checkType'));
|
|
@@ -4406,9 +5362,17 @@ function printTSConditionalType(node, path, options, print) {
|
|
|
4406
5362
|
parts.push(path.call(print, 'trueType'));
|
|
4407
5363
|
parts.push(' : ');
|
|
4408
5364
|
parts.push(path.call(print, 'falseType'));
|
|
4409
|
-
return
|
|
5365
|
+
return parts;
|
|
4410
5366
|
}
|
|
4411
5367
|
|
|
5368
|
+
/**
|
|
5369
|
+
* Print a TypeScript mapped type
|
|
5370
|
+
* @param {RippleASTNode} node - The mapped type node
|
|
5371
|
+
* @param {AstPath<RippleASTNode>} path - The AST path
|
|
5372
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
5373
|
+
* @param {PrintFn} print - Print callback
|
|
5374
|
+
* @returns {Doc}
|
|
5375
|
+
*/
|
|
4412
5376
|
function printTSMappedType(node, path, options, print) {
|
|
4413
5377
|
const readonlyMod =
|
|
4414
5378
|
node.readonly === true || node.readonly === 'plus' || node.readonly === '+'
|
|
@@ -4448,17 +5412,37 @@ function printTSMappedType(node, path, options, print) {
|
|
|
4448
5412
|
innerParts.push(path.call(print, 'typeAnnotation'));
|
|
4449
5413
|
}
|
|
4450
5414
|
|
|
4451
|
-
return group(['{ ', readonlyMod,
|
|
5415
|
+
return group(['{ ', readonlyMod, innerParts, ' }']);
|
|
4452
5416
|
}
|
|
4453
5417
|
|
|
5418
|
+
/**
|
|
5419
|
+
* @param {RippleASTNode} node
|
|
5420
|
+
* @param {AstPath<RippleASTNode>} path
|
|
5421
|
+
* @param {RippleFormatOptions} options
|
|
5422
|
+
* @param {PrintFn} print
|
|
5423
|
+
* @returns {Doc}
|
|
5424
|
+
*/
|
|
4454
5425
|
function printTSQualifiedName(node, path, options, print) {
|
|
4455
|
-
return
|
|
5426
|
+
return [path.call(print, 'left'), '.', path.call(print, 'right')];
|
|
4456
5427
|
}
|
|
4457
5428
|
|
|
5429
|
+
/**
|
|
5430
|
+
* @param {RippleASTNode} node
|
|
5431
|
+
* @param {AstPath<RippleASTNode>} path
|
|
5432
|
+
* @param {RippleFormatOptions} options
|
|
5433
|
+
* @param {PrintFn} print
|
|
5434
|
+
* @returns {Doc}
|
|
5435
|
+
*/
|
|
4458
5436
|
function printTSIndexedAccessType(node, path, options, print) {
|
|
4459
|
-
return
|
|
5437
|
+
return [path.call(print, 'objectType'), '[', path.call(print, 'indexType'), ']'];
|
|
4460
5438
|
}
|
|
4461
5439
|
|
|
5440
|
+
/**
|
|
5441
|
+
* @param {RippleASTNode} parentNode
|
|
5442
|
+
* @param {RippleASTNode} firstChild
|
|
5443
|
+
* @param {Doc} childDoc
|
|
5444
|
+
* @returns {boolean}
|
|
5445
|
+
*/
|
|
4462
5446
|
function shouldInlineSingleChild(parentNode, firstChild, childDoc) {
|
|
4463
5447
|
if (!firstChild || childDoc == null) {
|
|
4464
5448
|
return false;
|
|
@@ -4493,6 +5477,11 @@ function shouldInlineSingleChild(parentNode, firstChild, childDoc) {
|
|
|
4493
5477
|
return false;
|
|
4494
5478
|
}
|
|
4495
5479
|
|
|
5480
|
+
/**
|
|
5481
|
+
* Get leading comments from element metadata
|
|
5482
|
+
* @param {RippleASTNode} node - The element node
|
|
5483
|
+
* @returns {Comment[]}
|
|
5484
|
+
*/
|
|
4496
5485
|
function getElementLeadingComments(node) {
|
|
4497
5486
|
const fromMetadata = node?.metadata?.elementLeadingComments;
|
|
4498
5487
|
if (Array.isArray(fromMetadata)) {
|
|
@@ -4501,6 +5490,11 @@ function getElementLeadingComments(node) {
|
|
|
4501
5490
|
return [];
|
|
4502
5491
|
}
|
|
4503
5492
|
|
|
5493
|
+
/**
|
|
5494
|
+
* Create doc parts for element-level comments
|
|
5495
|
+
* @param {Comment[]} comments - Array of comments
|
|
5496
|
+
* @returns {Doc[]}
|
|
5497
|
+
*/
|
|
4504
5498
|
function createElementLevelCommentParts(comments) {
|
|
4505
5499
|
if (!comments || comments.length === 0) {
|
|
4506
5500
|
return [];
|
|
@@ -4531,6 +5525,11 @@ function createElementLevelCommentParts(comments) {
|
|
|
4531
5525
|
return parts;
|
|
4532
5526
|
}
|
|
4533
5527
|
|
|
5528
|
+
/**
|
|
5529
|
+
* Create element-level comment parts with trailing hardline trimmed
|
|
5530
|
+
* @param {Comment[]} comments - Array of comments
|
|
5531
|
+
* @returns {Doc[]}
|
|
5532
|
+
*/
|
|
4534
5533
|
function createElementLevelCommentPartsTrimmed(comments) {
|
|
4535
5534
|
const parts = createElementLevelCommentParts(comments);
|
|
4536
5535
|
if (parts.length > 0 && parts[parts.length - 1] === hardline) {
|
|
@@ -4539,6 +5538,14 @@ function createElementLevelCommentPartsTrimmed(comments) {
|
|
|
4539
5538
|
return parts;
|
|
4540
5539
|
}
|
|
4541
5540
|
|
|
5541
|
+
/**
|
|
5542
|
+
* Print a TSX compatibility node
|
|
5543
|
+
* @param {RippleASTNode} node - The TSX compat node
|
|
5544
|
+
* @param {AstPath<RippleASTNode>} path - The AST path
|
|
5545
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
5546
|
+
* @param {PrintFn} print - Print callback
|
|
5547
|
+
* @returns {Doc}
|
|
5548
|
+
*/
|
|
4542
5549
|
function printTsxCompat(node, path, options, print) {
|
|
4543
5550
|
const tagName = `<tsx:${node.kind}>`;
|
|
4544
5551
|
const closingTagName = `</tsx:${node.kind}>`;
|
|
@@ -4546,7 +5553,7 @@ function printTsxCompat(node, path, options, print) {
|
|
|
4546
5553
|
const hasChildren = Array.isArray(node.children) && node.children.length > 0;
|
|
4547
5554
|
|
|
4548
5555
|
if (!hasChildren) {
|
|
4549
|
-
return
|
|
5556
|
+
return [tagName, closingTagName];
|
|
4550
5557
|
}
|
|
4551
5558
|
|
|
4552
5559
|
// Print JSXElement children - they remain as JSX
|
|
@@ -4606,7 +5613,7 @@ function printTsxCompat(node, path, options, print) {
|
|
|
4606
5613
|
// Format the TsxCompat element
|
|
4607
5614
|
const elementOutput = group([
|
|
4608
5615
|
tagName,
|
|
4609
|
-
indent(
|
|
5616
|
+
indent([hardline, ...finalChildren]),
|
|
4610
5617
|
hardline,
|
|
4611
5618
|
closingTagName,
|
|
4612
5619
|
]);
|
|
@@ -4614,6 +5621,14 @@ function printTsxCompat(node, path, options, print) {
|
|
|
4614
5621
|
return elementOutput;
|
|
4615
5622
|
}
|
|
4616
5623
|
|
|
5624
|
+
/**
|
|
5625
|
+
* Print a JSX element
|
|
5626
|
+
* @param {RippleASTNode} node - The JSX element node
|
|
5627
|
+
* @param {AstPath<RippleASTNode>} path - The AST path
|
|
5628
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
5629
|
+
* @param {PrintFn} print - Print callback
|
|
5630
|
+
* @returns {Doc}
|
|
5631
|
+
*/
|
|
4617
5632
|
function printJSXElement(node, path, options, print) {
|
|
4618
5633
|
// Get the tag name from the opening element
|
|
4619
5634
|
const openingElement = node.openingElement;
|
|
@@ -4634,34 +5649,34 @@ function printJSXElement(node, path, options, print) {
|
|
|
4634
5649
|
const hasChildren = node.children && node.children.length > 0;
|
|
4635
5650
|
|
|
4636
5651
|
// Format attributes
|
|
5652
|
+
/** @type {Doc} */
|
|
4637
5653
|
let attributesDoc = '';
|
|
4638
5654
|
if (hasAttributes) {
|
|
4639
|
-
|
|
4640
|
-
|
|
4641
|
-
|
|
4642
|
-
|
|
4643
|
-
|
|
4644
|
-
|
|
4645
|
-
|
|
4646
|
-
|
|
4647
|
-
|
|
4648
|
-
|
|
4649
|
-
|
|
4650
|
-
path.call(print, 'openingElement', 'attributes', i, 'argument'),
|
|
4651
|
-
|
|
4652
|
-
|
|
4653
|
-
}
|
|
4654
|
-
|
|
4655
|
-
|
|
4656
|
-
attributesDoc = concat([' ', join(' ', attrs)]);
|
|
5655
|
+
/** @type {Doc[]} */
|
|
5656
|
+
const attrs = openingElement.attributes.map(
|
|
5657
|
+
(/** @type {RippleASTNode} */ attr, /** @type {number} */ i) => {
|
|
5658
|
+
if (attr.type === 'JSXAttribute') {
|
|
5659
|
+
return path.call(
|
|
5660
|
+
(attrPath) => printJSXAttribute(attrPath.getValue(), attrPath, options, print),
|
|
5661
|
+
'openingElement',
|
|
5662
|
+
'attributes',
|
|
5663
|
+
i,
|
|
5664
|
+
);
|
|
5665
|
+
} else if (attr.type === 'JSXSpreadAttribute') {
|
|
5666
|
+
return ['{...', path.call(print, 'openingElement', 'attributes', i, 'argument'), '}'];
|
|
5667
|
+
}
|
|
5668
|
+
return '';
|
|
5669
|
+
},
|
|
5670
|
+
);
|
|
5671
|
+
attributesDoc = [' ', join(' ', attrs)];
|
|
4657
5672
|
}
|
|
4658
5673
|
|
|
4659
5674
|
if (isSelfClosing) {
|
|
4660
|
-
return
|
|
5675
|
+
return ['<', tagName, attributesDoc, ' />'];
|
|
4661
5676
|
}
|
|
4662
5677
|
|
|
4663
5678
|
if (!hasChildren) {
|
|
4664
|
-
return
|
|
5679
|
+
return ['<', tagName, attributesDoc, '></', tagName, '>'];
|
|
4665
5680
|
}
|
|
4666
5681
|
|
|
4667
5682
|
// Format children - filter out empty text nodes and merge adjacent text nodes
|
|
@@ -4690,7 +5705,7 @@ function printJSXElement(node, path, options, print) {
|
|
|
4690
5705
|
|
|
4691
5706
|
if (child.type === 'JSXExpressionContainer') {
|
|
4692
5707
|
// Handle JSX expression containers
|
|
4693
|
-
childrenDocs.push(
|
|
5708
|
+
childrenDocs.push(['{', path.call(print, 'children', i, 'expression'), '}']);
|
|
4694
5709
|
} else {
|
|
4695
5710
|
// Handle nested JSX elements
|
|
4696
5711
|
childrenDocs.push(path.call(print, 'children', i));
|
|
@@ -4705,7 +5720,7 @@ function printJSXElement(node, path, options, print) {
|
|
|
4705
5720
|
|
|
4706
5721
|
// Check if content can be inlined (single text node or single expression)
|
|
4707
5722
|
if (childrenDocs.length === 1 && typeof childrenDocs[0] === 'string') {
|
|
4708
|
-
return
|
|
5723
|
+
return ['<', tagName, attributesDoc, '>', childrenDocs[0], '</', tagName, '>'];
|
|
4709
5724
|
}
|
|
4710
5725
|
|
|
4711
5726
|
// Multiple children or complex children - format with line breaks
|
|
@@ -4723,7 +5738,7 @@ function printJSXElement(node, path, options, print) {
|
|
|
4723
5738
|
tagName,
|
|
4724
5739
|
attributesDoc,
|
|
4725
5740
|
'>',
|
|
4726
|
-
indent(
|
|
5741
|
+
indent([hardline, ...formattedChildren]),
|
|
4727
5742
|
hardline,
|
|
4728
5743
|
'</',
|
|
4729
5744
|
tagName,
|
|
@@ -4731,6 +5746,14 @@ function printJSXElement(node, path, options, print) {
|
|
|
4731
5746
|
]);
|
|
4732
5747
|
}
|
|
4733
5748
|
|
|
5749
|
+
/**
|
|
5750
|
+
* Print a JSX fragment (<>...</>)
|
|
5751
|
+
* @param {RippleASTNode} node - The JSX fragment node
|
|
5752
|
+
* @param {AstPath<RippleASTNode>} path - The AST path
|
|
5753
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
5754
|
+
* @param {PrintFn} print - Print callback
|
|
5755
|
+
* @returns {Doc}
|
|
5756
|
+
*/
|
|
4734
5757
|
function printJSXFragment(node, path, options, print) {
|
|
4735
5758
|
const hasChildren = node.children && node.children.length > 0;
|
|
4736
5759
|
|
|
@@ -4751,7 +5774,7 @@ function printJSXFragment(node, path, options, print) {
|
|
|
4751
5774
|
}
|
|
4752
5775
|
} else if (child.type === 'JSXExpressionContainer') {
|
|
4753
5776
|
// Handle JSX expression containers
|
|
4754
|
-
childrenDocs.push(
|
|
5777
|
+
childrenDocs.push(['{', path.call(print, 'children', i, 'expression'), '}']);
|
|
4755
5778
|
} else {
|
|
4756
5779
|
// Handle nested JSX elements and fragments
|
|
4757
5780
|
childrenDocs.push(path.call(print, 'children', i));
|
|
@@ -4760,7 +5783,7 @@ function printJSXFragment(node, path, options, print) {
|
|
|
4760
5783
|
|
|
4761
5784
|
// Check if content can be inlined (single text node or single expression)
|
|
4762
5785
|
if (childrenDocs.length === 1 && typeof childrenDocs[0] === 'string') {
|
|
4763
|
-
return
|
|
5786
|
+
return ['<>', childrenDocs[0], '</>'];
|
|
4764
5787
|
}
|
|
4765
5788
|
|
|
4766
5789
|
// Multiple children or complex children - format with line breaks
|
|
@@ -4773,9 +5796,17 @@ function printJSXFragment(node, path, options, print) {
|
|
|
4773
5796
|
}
|
|
4774
5797
|
|
|
4775
5798
|
// Build the final fragment
|
|
4776
|
-
return group(['<>', indent(
|
|
5799
|
+
return group(['<>', indent([hardline, ...formattedChildren]), hardline, '</>']);
|
|
4777
5800
|
}
|
|
4778
5801
|
|
|
5802
|
+
/**
|
|
5803
|
+
* Print a JSX attribute
|
|
5804
|
+
* @param {RippleASTNode} attr - The JSX attribute node
|
|
5805
|
+
* @param {AstPath<RippleASTNode>} path - The AST path
|
|
5806
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
5807
|
+
* @param {PrintFn} print - Print callback
|
|
5808
|
+
* @returns {Doc}
|
|
5809
|
+
*/
|
|
4779
5810
|
function printJSXAttribute(attr, path, options, print) {
|
|
4780
5811
|
const name = attr.name.name;
|
|
4781
5812
|
|
|
@@ -4785,17 +5816,22 @@ function printJSXAttribute(attr, path, options, print) {
|
|
|
4785
5816
|
|
|
4786
5817
|
if (attr.value.type === 'Literal' || attr.value.type === 'StringLiteral') {
|
|
4787
5818
|
const quote = options.jsxSingleQuote ? "'" : '"';
|
|
4788
|
-
return
|
|
5819
|
+
return [name, '=', quote, attr.value.value, quote];
|
|
4789
5820
|
}
|
|
4790
5821
|
|
|
4791
5822
|
if (attr.value.type === 'JSXExpressionContainer') {
|
|
4792
5823
|
const exprDoc = path.call(print, 'value', 'expression');
|
|
4793
|
-
return
|
|
5824
|
+
return [name, '={', exprDoc, '}'];
|
|
4794
5825
|
}
|
|
4795
5826
|
|
|
4796
5827
|
return name;
|
|
4797
5828
|
}
|
|
4798
5829
|
|
|
5830
|
+
/**
|
|
5831
|
+
* Print a JSX member expression (e.g., React.Fragment)
|
|
5832
|
+
* @param {RippleASTNode} node - The JSX member expression or identifier
|
|
5833
|
+
* @returns {string}
|
|
5834
|
+
*/
|
|
4799
5835
|
function printJSXMemberExpression(node) {
|
|
4800
5836
|
if (node.type === 'JSXIdentifier') {
|
|
4801
5837
|
return node.name;
|
|
@@ -4806,6 +5842,13 @@ function printJSXMemberExpression(node) {
|
|
|
4806
5842
|
return 'Unknown';
|
|
4807
5843
|
}
|
|
4808
5844
|
|
|
5845
|
+
/**
|
|
5846
|
+
* Print a member expression as simple string (for element tag names)
|
|
5847
|
+
* @param {RippleASTNode} node - The node to print
|
|
5848
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
5849
|
+
* @param {boolean} [computed=false] - Whether the property is computed
|
|
5850
|
+
* @returns {string}
|
|
5851
|
+
*/
|
|
4809
5852
|
function printMemberExpressionSimple(node, options, computed = false) {
|
|
4810
5853
|
if (node.type === 'Identifier') {
|
|
4811
5854
|
// When computed is true, it means we're inside brackets and tracked is already handled by .@[ or [
|
|
@@ -4832,6 +5875,14 @@ function printMemberExpressionSimple(node, options, computed = false) {
|
|
|
4832
5875
|
return '';
|
|
4833
5876
|
}
|
|
4834
5877
|
|
|
5878
|
+
/**
|
|
5879
|
+
* Print a Ripple Element node
|
|
5880
|
+
* @param {RippleASTNode} node - The element node
|
|
5881
|
+
* @param {AstPath<RippleASTNode>} path - The AST path
|
|
5882
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
5883
|
+
* @param {PrintFn} print - Print callback
|
|
5884
|
+
* @returns {Doc}
|
|
5885
|
+
*/
|
|
4835
5886
|
function printElement(node, path, options, print) {
|
|
4836
5887
|
const tagName = printMemberExpressionSimple(node.id, options);
|
|
4837
5888
|
const elementLeadingComments = getElementLeadingComments(node);
|
|
@@ -4839,10 +5890,11 @@ function printElement(node, path, options, print) {
|
|
|
4839
5890
|
// `metadata.elementLeadingComments` may include comments that actually appear *inside* the element
|
|
4840
5891
|
// body (after the opening tag). Those must not be hoisted before the element.
|
|
4841
5892
|
const outerElementLeadingComments = elementLeadingComments.filter(
|
|
4842
|
-
(
|
|
5893
|
+
(/** @type {RippleASTNode} */ comment) =>
|
|
5894
|
+
typeof comment.start !== 'number' || comment.start < node.start,
|
|
4843
5895
|
);
|
|
4844
5896
|
const innerElementBodyComments = elementLeadingComments.filter(
|
|
4845
|
-
(comment) =>
|
|
5897
|
+
(/** @type {RippleASTNode} */ comment) =>
|
|
4846
5898
|
typeof comment.start === 'number' &&
|
|
4847
5899
|
comment.start >= node.openingElement.end &&
|
|
4848
5900
|
comment.start < node.end,
|
|
@@ -4861,9 +5913,7 @@ function printElement(node, path, options, print) {
|
|
|
4861
5913
|
|
|
4862
5914
|
if (isSelfClosing && !hasInnerComments && !hasAttributes) {
|
|
4863
5915
|
const elementDoc = group(['<', tagName, ' />']);
|
|
4864
|
-
return metadataCommentParts.length > 0
|
|
4865
|
-
? concat([...metadataCommentParts, elementDoc])
|
|
4866
|
-
: elementDoc;
|
|
5916
|
+
return metadataCommentParts.length > 0 ? [...metadataCommentParts, elementDoc] : elementDoc;
|
|
4867
5917
|
}
|
|
4868
5918
|
|
|
4869
5919
|
// Determine the line break type for attributes
|
|
@@ -4877,13 +5927,11 @@ function printElement(node, path, options, print) {
|
|
|
4877
5927
|
'<',
|
|
4878
5928
|
tagName,
|
|
4879
5929
|
hasAttributes
|
|
4880
|
-
? indent(
|
|
4881
|
-
|
|
4882
|
-
|
|
4883
|
-
|
|
4884
|
-
|
|
4885
|
-
]),
|
|
4886
|
-
)
|
|
5930
|
+
? indent([
|
|
5931
|
+
...path.map((attrPath) => {
|
|
5932
|
+
return [attrLineBreak, print(attrPath)];
|
|
5933
|
+
}, 'attributes'),
|
|
5934
|
+
])
|
|
4887
5935
|
: '',
|
|
4888
5936
|
// Add line break opportunity before > or />
|
|
4889
5937
|
// Use line for self-closing (keeps space), softline for non-self-closing when attributes present
|
|
@@ -4900,9 +5948,7 @@ function printElement(node, path, options, print) {
|
|
|
4900
5948
|
|
|
4901
5949
|
if (!hasChildren) {
|
|
4902
5950
|
if (!hasInnerComments) {
|
|
4903
|
-
return metadataCommentParts.length > 0
|
|
4904
|
-
? concat([...metadataCommentParts, openingTag])
|
|
4905
|
-
: openingTag;
|
|
5951
|
+
return metadataCommentParts.length > 0 ? [...metadataCommentParts, openingTag] : openingTag;
|
|
4906
5952
|
}
|
|
4907
5953
|
|
|
4908
5954
|
const innerParts = [];
|
|
@@ -4920,15 +5966,15 @@ function printElement(node, path, options, print) {
|
|
|
4920
5966
|
innerParts.pop();
|
|
4921
5967
|
}
|
|
4922
5968
|
|
|
4923
|
-
const closingTag =
|
|
5969
|
+
const closingTag = ['</', tagName, '>'];
|
|
4924
5970
|
const elementOutput = group([
|
|
4925
5971
|
openingTag,
|
|
4926
|
-
indent(
|
|
5972
|
+
indent([hardline, ...innerParts]),
|
|
4927
5973
|
hardline,
|
|
4928
5974
|
closingTag,
|
|
4929
5975
|
]);
|
|
4930
5976
|
return metadataCommentParts.length > 0
|
|
4931
|
-
?
|
|
5977
|
+
? [...metadataCommentParts, elementOutput]
|
|
4932
5978
|
: elementOutput;
|
|
4933
5979
|
}
|
|
4934
5980
|
|
|
@@ -4937,7 +5983,12 @@ function printElement(node, path, options, print) {
|
|
|
4937
5983
|
const finalChildren = [];
|
|
4938
5984
|
const sortedInnerElementBodyComments =
|
|
4939
5985
|
innerElementBodyComments.length > 0
|
|
4940
|
-
? innerElementBodyComments
|
|
5986
|
+
? innerElementBodyComments
|
|
5987
|
+
.slice()
|
|
5988
|
+
.sort(
|
|
5989
|
+
(/** @type {RippleASTNode} */ a, /** @type {RippleASTNode} */ b) =>
|
|
5990
|
+
(a.start ?? 0) - (b.start ?? 0),
|
|
5991
|
+
)
|
|
4941
5992
|
: [];
|
|
4942
5993
|
let innerElementBodyCommentIndex = 0;
|
|
4943
5994
|
|
|
@@ -4951,6 +6002,7 @@ function printElement(node, path, options, print) {
|
|
|
4951
6002
|
if (currentChildStart != null) {
|
|
4952
6003
|
const commentsBefore = [];
|
|
4953
6004
|
while (innerElementBodyCommentIndex < sortedInnerElementBodyComments.length) {
|
|
6005
|
+
/** @type {RippleASTNode} */
|
|
4954
6006
|
const comment = sortedInnerElementBodyComments[innerElementBodyCommentIndex];
|
|
4955
6007
|
if (typeof comment.start !== 'number' || comment.start >= currentChildStart) {
|
|
4956
6008
|
break;
|
|
@@ -4985,7 +6037,7 @@ function printElement(node, path, options, print) {
|
|
|
4985
6037
|
}
|
|
4986
6038
|
}
|
|
4987
6039
|
|
|
4988
|
-
const childPrintArgs = {};
|
|
6040
|
+
const childPrintArgs = /** @type {PrintArgs} */ ({});
|
|
4989
6041
|
if (hasTextLeadingComments) {
|
|
4990
6042
|
childPrintArgs.suppressLeadingComments = true;
|
|
4991
6043
|
}
|
|
@@ -5000,7 +6052,7 @@ function printElement(node, path, options, print) {
|
|
|
5000
6052
|
|
|
5001
6053
|
const childDoc =
|
|
5002
6054
|
rawExpressionLeadingComments && rawExpressionLeadingComments.length > 0
|
|
5003
|
-
?
|
|
6055
|
+
? [...createElementLevelCommentParts(rawExpressionLeadingComments), printedChild]
|
|
5004
6056
|
: printedChild;
|
|
5005
6057
|
finalChildren.push(childDoc);
|
|
5006
6058
|
|
|
@@ -5013,6 +6065,7 @@ function printElement(node, path, options, print) {
|
|
|
5013
6065
|
if (typeof currentChildEnd === 'number') {
|
|
5014
6066
|
const commentsBetween = [];
|
|
5015
6067
|
while (innerElementBodyCommentIndex < sortedInnerElementBodyComments.length) {
|
|
6068
|
+
/** @type {RippleASTNode} */
|
|
5016
6069
|
const comment = sortedInnerElementBodyComments[innerElementBodyCommentIndex];
|
|
5017
6070
|
if (typeof comment.start !== 'number') {
|
|
5018
6071
|
innerElementBodyCommentIndex++;
|
|
@@ -5057,7 +6110,11 @@ function printElement(node, path, options, print) {
|
|
|
5057
6110
|
if (insertedBodyCommentsBetween) {
|
|
5058
6111
|
continue;
|
|
5059
6112
|
}
|
|
5060
|
-
const
|
|
6113
|
+
const whitespaceTarget =
|
|
6114
|
+
nextChild.leadingComments && nextChild.leadingComments.length > 0
|
|
6115
|
+
? nextChild.leadingComments[0]
|
|
6116
|
+
: nextChild;
|
|
6117
|
+
const whitespaceLinesCount = getBlankLinesBetweenNodes(currentChild, whitespaceTarget);
|
|
5061
6118
|
const isTextOrHtmlChild =
|
|
5062
6119
|
currentChild.type === 'Text' ||
|
|
5063
6120
|
currentChild.type === 'Html' ||
|
|
@@ -5076,6 +6133,32 @@ function printElement(node, path, options, print) {
|
|
|
5076
6133
|
}
|
|
5077
6134
|
}
|
|
5078
6135
|
|
|
6136
|
+
// Collect comments attached to the closing element (comments that appear after the last child
|
|
6137
|
+
// but before the closing tag, e.g. `</div>`). The parser attaches these as leadingComments
|
|
6138
|
+
// on either the closingElement node or the closingElement.name node depending on context.
|
|
6139
|
+
const closingElementComments = [
|
|
6140
|
+
...(node.closingElement && Array.isArray(node.closingElement.leadingComments)
|
|
6141
|
+
? node.closingElement.leadingComments
|
|
6142
|
+
: []),
|
|
6143
|
+
...(node.closingElement &&
|
|
6144
|
+
node.closingElement.name &&
|
|
6145
|
+
Array.isArray(node.closingElement.name.leadingComments)
|
|
6146
|
+
? node.closingElement.name.leadingComments
|
|
6147
|
+
: []),
|
|
6148
|
+
];
|
|
6149
|
+
|
|
6150
|
+
if (closingElementComments.length > 0) {
|
|
6151
|
+
const lastChild = node.children[node.children.length - 1];
|
|
6152
|
+
if (lastChild) {
|
|
6153
|
+
const blankLinesBefore = getBlankLinesBetweenNodes(lastChild, closingElementComments[0]);
|
|
6154
|
+
finalChildren.push(hardline);
|
|
6155
|
+
if (blankLinesBefore > 0) {
|
|
6156
|
+
finalChildren.push(hardline);
|
|
6157
|
+
}
|
|
6158
|
+
}
|
|
6159
|
+
finalChildren.push(...createElementLevelCommentPartsTrimmed(closingElementComments));
|
|
6160
|
+
}
|
|
6161
|
+
|
|
5079
6162
|
const fallbackCommentParts =
|
|
5080
6163
|
fallbackElementComments.length > 0
|
|
5081
6164
|
? createElementLevelCommentParts(fallbackElementComments)
|
|
@@ -5085,12 +6168,14 @@ function printElement(node, path, options, print) {
|
|
|
5085
6168
|
? [...metadataCommentParts, ...fallbackCommentParts]
|
|
5086
6169
|
: fallbackCommentParts;
|
|
5087
6170
|
|
|
5088
|
-
const closingTag =
|
|
6171
|
+
const closingTag = ['</', tagName, '>'];
|
|
5089
6172
|
let elementOutput;
|
|
5090
6173
|
|
|
5091
6174
|
const hasComponentChild =
|
|
5092
6175
|
node.children &&
|
|
5093
|
-
node.children.some(
|
|
6176
|
+
node.children.some(
|
|
6177
|
+
(/** @type {RippleASTNode} */ child) => child.type === 'Component' && !child.selfClosing,
|
|
6178
|
+
);
|
|
5094
6179
|
|
|
5095
6180
|
if (finalChildren.length === 1 && !hasComponentChild) {
|
|
5096
6181
|
const child = finalChildren[0];
|
|
@@ -5111,42 +6196,28 @@ function printElement(node, path, options, print) {
|
|
|
5111
6196
|
shouldInlineSingleChild(node, firstChild, child)
|
|
5112
6197
|
) {
|
|
5113
6198
|
if (isElementChild && hasAttributes) {
|
|
5114
|
-
elementOutput =
|
|
5115
|
-
openingTag,
|
|
5116
|
-
indent(concat([hardline, child])),
|
|
5117
|
-
hardline,
|
|
5118
|
-
closingTag,
|
|
5119
|
-
]);
|
|
6199
|
+
elementOutput = [openingTag, indent([hardline, child]), hardline, closingTag];
|
|
5120
6200
|
} else {
|
|
5121
|
-
elementOutput = group([
|
|
5122
|
-
openingTag,
|
|
5123
|
-
indent(concat([softline, child])),
|
|
5124
|
-
softline,
|
|
5125
|
-
closingTag,
|
|
5126
|
-
]);
|
|
6201
|
+
elementOutput = group([openingTag, indent([softline, child]), softline, closingTag]);
|
|
5127
6202
|
}
|
|
5128
6203
|
} else {
|
|
5129
|
-
elementOutput =
|
|
5130
|
-
openingTag,
|
|
5131
|
-
indent(concat([hardline, ...finalChildren])),
|
|
5132
|
-
hardline,
|
|
5133
|
-
closingTag,
|
|
5134
|
-
]);
|
|
6204
|
+
elementOutput = [openingTag, indent([hardline, ...finalChildren]), hardline, closingTag];
|
|
5135
6205
|
}
|
|
5136
6206
|
} else {
|
|
5137
|
-
elementOutput = group([
|
|
5138
|
-
openingTag,
|
|
5139
|
-
indent(concat([hardline, ...finalChildren])),
|
|
5140
|
-
hardline,
|
|
5141
|
-
closingTag,
|
|
5142
|
-
]);
|
|
6207
|
+
elementOutput = group([openingTag, indent([hardline, ...finalChildren]), hardline, closingTag]);
|
|
5143
6208
|
}
|
|
5144
6209
|
|
|
5145
|
-
return leadingCommentParts.length > 0
|
|
5146
|
-
? concat([...leadingCommentParts, elementOutput])
|
|
5147
|
-
: elementOutput;
|
|
6210
|
+
return leadingCommentParts.length > 0 ? [...leadingCommentParts, elementOutput] : elementOutput;
|
|
5148
6211
|
}
|
|
5149
6212
|
|
|
6213
|
+
/**
|
|
6214
|
+
* Print a Ripple attribute node
|
|
6215
|
+
* @param {RippleASTNode} node - The attribute node
|
|
6216
|
+
* @param {AstPath<RippleASTNode>} path - The AST path
|
|
6217
|
+
* @param {RippleFormatOptions} options - Prettier options
|
|
6218
|
+
* @param {PrintFn} print - Print callback
|
|
6219
|
+
* @returns {Doc[]}
|
|
6220
|
+
*/
|
|
5150
6221
|
function printAttribute(node, path, options, print) {
|
|
5151
6222
|
const parts = [];
|
|
5152
6223
|
|