@tsrx/prettier-plugin 0.3.52 → 0.3.54
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/package.json +2 -2
- package/src/index.js +64 -19
- package/src/index.test.js +106 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tsrx/prettier-plugin",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.54",
|
|
4
4
|
"description": "Ripple plugin for Prettier",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "src/index.js",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"prettier": "^3.8.3"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@tsrx/core": "0.1.
|
|
30
|
+
"@tsrx/core": "0.1.4"
|
|
31
31
|
},
|
|
32
32
|
"files": [
|
|
33
33
|
"src/"
|
package/src/index.js
CHANGED
|
@@ -1687,7 +1687,7 @@ function printRippleNode(node, path, options, print, args) {
|
|
|
1687
1687
|
break;
|
|
1688
1688
|
|
|
1689
1689
|
case 'ArrowFunctionExpression':
|
|
1690
|
-
nodeContent = printArrowFunction(node, path, options, print);
|
|
1690
|
+
nodeContent = printArrowFunction(node, path, options, print, args);
|
|
1691
1691
|
break;
|
|
1692
1692
|
|
|
1693
1693
|
case 'FunctionExpression':
|
|
@@ -2723,9 +2723,10 @@ function printFunctionExpression(node, path, options, print) {
|
|
|
2723
2723
|
* @param {AstPath<AST.ArrowFunctionExpression>} path - The AST path
|
|
2724
2724
|
* @param {RippleFormatOptions} options - Prettier options
|
|
2725
2725
|
* @param {PrintFn} print - Print callback
|
|
2726
|
+
* @param {PrintArgs} [args] - Additional context arguments
|
|
2726
2727
|
* @returns {Doc}
|
|
2727
2728
|
*/
|
|
2728
|
-
function printArrowFunction(node, path, options, print) {
|
|
2729
|
+
function printArrowFunction(node, path, options, print, args) {
|
|
2729
2730
|
/** @type {Doc[]} */
|
|
2730
2731
|
const parts = [];
|
|
2731
2732
|
|
|
@@ -2773,22 +2774,44 @@ function printArrowFunction(node, path, options, print) {
|
|
|
2773
2774
|
// For expression bodies, check if we need to wrap in parens
|
|
2774
2775
|
// Wrap ObjectExpression, AssignmentExpression, and SequenceExpression in parens
|
|
2775
2776
|
// to avoid ambiguity with block statements or to clarify intent
|
|
2777
|
+
const bodyDoc = path.call(print, 'body');
|
|
2776
2778
|
if (
|
|
2777
2779
|
node.body.type === 'ObjectExpression' ||
|
|
2778
2780
|
node.body.type === 'AssignmentExpression' ||
|
|
2779
|
-
node.body.type === 'SequenceExpression'
|
|
2781
|
+
node.body.type === 'SequenceExpression' ||
|
|
2782
|
+
(args?.isInAttribute && isTemplateExpression(node.body))
|
|
2780
2783
|
) {
|
|
2781
2784
|
parts.push('(');
|
|
2782
|
-
|
|
2785
|
+
if (isTemplateExpression(node.body)) {
|
|
2786
|
+
parts.push(indent([hardline, bodyDoc]));
|
|
2787
|
+
parts.push(hardline);
|
|
2788
|
+
} else {
|
|
2789
|
+
parts.push(bodyDoc);
|
|
2790
|
+
}
|
|
2783
2791
|
parts.push(')');
|
|
2784
2792
|
} else {
|
|
2785
|
-
parts.push(
|
|
2793
|
+
parts.push(bodyDoc);
|
|
2786
2794
|
}
|
|
2787
2795
|
}
|
|
2788
2796
|
|
|
2789
2797
|
return parts;
|
|
2790
2798
|
}
|
|
2791
2799
|
|
|
2800
|
+
/**
|
|
2801
|
+
* Check whether an expression is one of TSRX's template expression wrappers.
|
|
2802
|
+
* @param {AST.Node} node - The node to check
|
|
2803
|
+
* @returns {boolean}
|
|
2804
|
+
*/
|
|
2805
|
+
function isTemplateExpression(node) {
|
|
2806
|
+
return (
|
|
2807
|
+
node.type === 'Tsx' ||
|
|
2808
|
+
node.type === 'TsxCompat' ||
|
|
2809
|
+
node.type === 'Tsrx' ||
|
|
2810
|
+
node.type === 'JSXElement' ||
|
|
2811
|
+
node.type === 'JSXFragment'
|
|
2812
|
+
);
|
|
2813
|
+
}
|
|
2814
|
+
|
|
2792
2815
|
/**
|
|
2793
2816
|
* Print an export default declaration
|
|
2794
2817
|
* @param {AST.ExportDefaultDeclaration} node - The export default node
|
|
@@ -5816,12 +5839,15 @@ function printJSXElement(node, path, options, print) {
|
|
|
5816
5839
|
// Format attributes
|
|
5817
5840
|
/** @type {Doc} */
|
|
5818
5841
|
let attributesDoc = '';
|
|
5842
|
+
let hasBreakingAttribute = false;
|
|
5819
5843
|
if (hasAttributes) {
|
|
5820
5844
|
/** @type {Doc[]} */
|
|
5821
5845
|
const attrs = openingElement.attributes.map(
|
|
5822
5846
|
(/** @type {AST.Node} */ attr, /** @type {number} */ i) => {
|
|
5847
|
+
/** @type {Doc} */
|
|
5848
|
+
let attrDoc = '';
|
|
5823
5849
|
if (attr.type === 'JSXAttribute') {
|
|
5824
|
-
|
|
5850
|
+
attrDoc = path.call(
|
|
5825
5851
|
(attrPath) =>
|
|
5826
5852
|
printJSXAttribute(
|
|
5827
5853
|
/** @type {ESTreeJSX.JSXAttribute} */ (attrPath.node),
|
|
@@ -5834,20 +5860,39 @@ function printJSXElement(node, path, options, print) {
|
|
|
5834
5860
|
i,
|
|
5835
5861
|
);
|
|
5836
5862
|
} else if (attr.type === 'JSXSpreadAttribute' || attr.type === 'SpreadAttribute') {
|
|
5837
|
-
|
|
5863
|
+
attrDoc = ['{...', path.call(print, 'openingElement', 'attributes', i, 'argument'), '}'];
|
|
5838
5864
|
}
|
|
5839
|
-
|
|
5865
|
+
if (!hasBreakingAttribute && attrDoc && willBreak(attrDoc)) {
|
|
5866
|
+
hasBreakingAttribute = true;
|
|
5867
|
+
}
|
|
5868
|
+
return attrDoc;
|
|
5840
5869
|
},
|
|
5841
5870
|
);
|
|
5842
|
-
|
|
5871
|
+
const attrLineBreak = options.singleAttributePerLine ? hardline : line;
|
|
5872
|
+
attributesDoc = indent([attrLineBreak, join(attrLineBreak, attrs)]);
|
|
5843
5873
|
}
|
|
5874
|
+
const shouldForceBreak = hasBreakingAttribute;
|
|
5844
5875
|
|
|
5845
5876
|
if (isSelfClosing) {
|
|
5846
|
-
return ['<', tagName, typeArgsDoc, attributesDoc, ' />']
|
|
5877
|
+
return group(['<', tagName, typeArgsDoc, attributesDoc, hasAttributes ? line : ' ', '/>'], {
|
|
5878
|
+
shouldBreak: shouldForceBreak,
|
|
5879
|
+
});
|
|
5847
5880
|
}
|
|
5848
5881
|
|
|
5882
|
+
const openingTag = group(
|
|
5883
|
+
[
|
|
5884
|
+
'<',
|
|
5885
|
+
tagName,
|
|
5886
|
+
typeArgsDoc,
|
|
5887
|
+
attributesDoc,
|
|
5888
|
+
hasAttributes && !options.bracketSameLine ? softline : '',
|
|
5889
|
+
'>',
|
|
5890
|
+
],
|
|
5891
|
+
{ shouldBreak: shouldForceBreak },
|
|
5892
|
+
);
|
|
5893
|
+
|
|
5849
5894
|
if (!hasChildren) {
|
|
5850
|
-
return [
|
|
5895
|
+
return [openingTag, '</', tagName, '>'];
|
|
5851
5896
|
}
|
|
5852
5897
|
|
|
5853
5898
|
// Format children - filter out empty text nodes and merge adjacent text nodes
|
|
@@ -5891,7 +5936,7 @@ function printJSXElement(node, path, options, print) {
|
|
|
5891
5936
|
|
|
5892
5937
|
// Check if content can be inlined (single text node or single expression)
|
|
5893
5938
|
if (childrenDocs.length === 1 && typeof childrenDocs[0] === 'string') {
|
|
5894
|
-
return [
|
|
5939
|
+
return group([openingTag, childrenDocs[0], '</', tagName, '>']);
|
|
5895
5940
|
}
|
|
5896
5941
|
const meaningfulChildren = node.children.filter(
|
|
5897
5942
|
(child) => child.type !== 'JSXText' || child.value.trim(),
|
|
@@ -5902,7 +5947,7 @@ function printJSXElement(node, path, options, print) {
|
|
|
5902
5947
|
singleMeaningfulChild?.type === 'JSXExpressionContainer' &&
|
|
5903
5948
|
singleMeaningfulChild.expression.type === 'Identifier'
|
|
5904
5949
|
) {
|
|
5905
|
-
return [
|
|
5950
|
+
return group([openingTag, childrenDocs[0], '</', tagName, '>']);
|
|
5906
5951
|
}
|
|
5907
5952
|
|
|
5908
5953
|
// Multiple children or complex children - format with line breaks
|
|
@@ -5916,11 +5961,7 @@ function printJSXElement(node, path, options, print) {
|
|
|
5916
5961
|
|
|
5917
5962
|
// Build the final element
|
|
5918
5963
|
return group([
|
|
5919
|
-
|
|
5920
|
-
tagName,
|
|
5921
|
-
typeArgsDoc,
|
|
5922
|
-
attributesDoc,
|
|
5923
|
-
'>',
|
|
5964
|
+
openingTag,
|
|
5924
5965
|
indent([hardline, ...formattedChildren]),
|
|
5925
5966
|
hardline,
|
|
5926
5967
|
'</',
|
|
@@ -6009,7 +6050,11 @@ function printJSXAttribute(attr, path, options, print) {
|
|
|
6009
6050
|
}
|
|
6010
6051
|
|
|
6011
6052
|
if (attr.value.type === 'JSXExpressionContainer') {
|
|
6012
|
-
const exprDoc = path.call(
|
|
6053
|
+
const exprDoc = path.call(
|
|
6054
|
+
(valuePath) => print(valuePath, { isInAttribute: true }),
|
|
6055
|
+
'value',
|
|
6056
|
+
'expression',
|
|
6057
|
+
);
|
|
6013
6058
|
return [name, '={', exprDoc, '}'];
|
|
6014
6059
|
}
|
|
6015
6060
|
|
package/src/index.test.js
CHANGED
|
@@ -157,6 +157,112 @@ describe('prettier-plugin', () => {
|
|
|
157
157
|
expect(result).toBeWithNewline(expected);
|
|
158
158
|
});
|
|
159
159
|
|
|
160
|
+
it('should break nested TSX element attributes inside expression props', async () => {
|
|
161
|
+
const cases = [
|
|
162
|
+
{
|
|
163
|
+
input: `component Test() {
|
|
164
|
+
<A fallback={(error) => <>
|
|
165
|
+
<B id="xyz" status="error" moreProps={{ a: 1, b: 2 }} value={getErrorMessage(
|
|
166
|
+
error,
|
|
167
|
+
)} otherProp={2} />
|
|
168
|
+
</>} />
|
|
169
|
+
}`,
|
|
170
|
+
expected: `component Test() {
|
|
171
|
+
<A
|
|
172
|
+
fallback={(error) => (
|
|
173
|
+
<>
|
|
174
|
+
<B
|
|
175
|
+
id="xyz"
|
|
176
|
+
status="error"
|
|
177
|
+
moreProps={{ a: 1, b: 2 }}
|
|
178
|
+
value={getErrorMessage(error)}
|
|
179
|
+
otherProp={2}
|
|
180
|
+
/>
|
|
181
|
+
</>
|
|
182
|
+
)}
|
|
183
|
+
/>
|
|
184
|
+
}`,
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
input: `component Test() {
|
|
188
|
+
<A fallback={(error) => <tsx>
|
|
189
|
+
<B id="xyz" status="error" moreProps={{ a: 1, b: 2 }} value={getErrorMessage(
|
|
190
|
+
error,
|
|
191
|
+
)} otherProp={2} />
|
|
192
|
+
</tsx>} />
|
|
193
|
+
}`,
|
|
194
|
+
expected: `component Test() {
|
|
195
|
+
<A
|
|
196
|
+
fallback={(error) => (
|
|
197
|
+
<tsx>
|
|
198
|
+
<B
|
|
199
|
+
id="xyz"
|
|
200
|
+
status="error"
|
|
201
|
+
moreProps={{ a: 1, b: 2 }}
|
|
202
|
+
value={getErrorMessage(error)}
|
|
203
|
+
otherProp={2}
|
|
204
|
+
/>
|
|
205
|
+
</tsx>
|
|
206
|
+
)}
|
|
207
|
+
/>
|
|
208
|
+
}`,
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
input: `component Test() {
|
|
212
|
+
<A fallback={(error) => <tsrx>
|
|
213
|
+
<B id="xyz" status="error" moreProps={{ a: 1, b: 2 }} value={getErrorMessage(
|
|
214
|
+
error,
|
|
215
|
+
)} otherProp={2} />
|
|
216
|
+
</tsrx>} />
|
|
217
|
+
}`,
|
|
218
|
+
expected: `component Test() {
|
|
219
|
+
<A
|
|
220
|
+
fallback={(error) => (
|
|
221
|
+
<tsrx>
|
|
222
|
+
<B
|
|
223
|
+
id="xyz"
|
|
224
|
+
status="error"
|
|
225
|
+
moreProps={{ a: 1, b: 2 }}
|
|
226
|
+
value={getErrorMessage(error)}
|
|
227
|
+
otherProp={2}
|
|
228
|
+
/>
|
|
229
|
+
</tsrx>
|
|
230
|
+
)}
|
|
231
|
+
/>
|
|
232
|
+
}`,
|
|
233
|
+
},
|
|
234
|
+
{
|
|
235
|
+
input: `component Test() {
|
|
236
|
+
<A fallback={(error) => <tsx:react>
|
|
237
|
+
<B id="xyz" status="error" moreProps={{ a: 1, b: 2 }} value={getErrorMessage(
|
|
238
|
+
error,
|
|
239
|
+
)} otherProp={2} />
|
|
240
|
+
</tsx:react>} />
|
|
241
|
+
}`,
|
|
242
|
+
expected: `component Test() {
|
|
243
|
+
<A
|
|
244
|
+
fallback={(error) => (
|
|
245
|
+
<tsx:react>
|
|
246
|
+
<B
|
|
247
|
+
id="xyz"
|
|
248
|
+
status="error"
|
|
249
|
+
moreProps={{ a: 1, b: 2 }}
|
|
250
|
+
value={getErrorMessage(error)}
|
|
251
|
+
otherProp={2}
|
|
252
|
+
/>
|
|
253
|
+
</tsx:react>
|
|
254
|
+
)}
|
|
255
|
+
/>
|
|
256
|
+
}`,
|
|
257
|
+
},
|
|
258
|
+
];
|
|
259
|
+
|
|
260
|
+
for (const { input, expected } of cases) {
|
|
261
|
+
const result = await format(input);
|
|
262
|
+
expect(result).toBeWithNewline(expected);
|
|
263
|
+
}
|
|
264
|
+
});
|
|
265
|
+
|
|
160
266
|
it('should format whitespace correctly', async () => {
|
|
161
267
|
const input = `export component Test(){
|
|
162
268
|
let count=0
|