@tsrx/prettier-plugin 0.3.74 → 0.3.77
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 +25 -26
- package/src/index.test.js +122 -94
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tsrx/prettier-plugin",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.77",
|
|
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.25"
|
|
31
31
|
},
|
|
32
32
|
"files": [
|
|
33
33
|
"src/"
|
package/src/index.js
CHANGED
|
@@ -42,16 +42,16 @@ const { replaceEndOfLine, willBreak } = utils;
|
|
|
42
42
|
/** @type {import('prettier').Plugin['languages']} */
|
|
43
43
|
export const languages = [
|
|
44
44
|
{
|
|
45
|
-
name: '
|
|
46
|
-
parsers: ['
|
|
45
|
+
name: 'tsrx',
|
|
46
|
+
parsers: ['tsrx'],
|
|
47
47
|
extensions: ['.tsrx'],
|
|
48
|
-
vscodeLanguageIds: ['ripple'],
|
|
48
|
+
vscodeLanguageIds: ['tsrx', 'ripple'],
|
|
49
49
|
},
|
|
50
50
|
];
|
|
51
51
|
|
|
52
52
|
/** @type {import('prettier').Plugin['parsers']} */
|
|
53
53
|
export const parsers = {
|
|
54
|
-
|
|
54
|
+
tsrx: {
|
|
55
55
|
astFormat: 'ripple-ast',
|
|
56
56
|
/**
|
|
57
57
|
* @param {string} text
|
|
@@ -1732,18 +1732,12 @@ function printRippleNode(node, path, options, print, args) {
|
|
|
1732
1732
|
}
|
|
1733
1733
|
case 'Identifier': {
|
|
1734
1734
|
// Simple case - just return the name directly like Prettier core
|
|
1735
|
-
const trackedPrefix = node.tracked ? '@' : '';
|
|
1736
1735
|
let identifierContent;
|
|
1737
1736
|
if (node.typeAnnotation) {
|
|
1738
1737
|
const optionalMarker = node.optional ? '?' : '';
|
|
1739
|
-
identifierContent = [
|
|
1740
|
-
trackedPrefix + node.name,
|
|
1741
|
-
optionalMarker,
|
|
1742
|
-
': ',
|
|
1743
|
-
path.call(print, 'typeAnnotation'),
|
|
1744
|
-
];
|
|
1738
|
+
identifierContent = [node.name, optionalMarker, ': ', path.call(print, 'typeAnnotation')];
|
|
1745
1739
|
} else {
|
|
1746
|
-
identifierContent =
|
|
1740
|
+
identifierContent = node.name;
|
|
1747
1741
|
}
|
|
1748
1742
|
// Preserve parentheses for type-cast identifiers, but only if:
|
|
1749
1743
|
// 1. The identifier itself is marked as parenthesized
|
|
@@ -1857,7 +1851,13 @@ function printRippleNode(node, path, options, print, args) {
|
|
|
1857
1851
|
blockParent.type === 'ForOfStatement' ||
|
|
1858
1852
|
blockParent.type === 'WhileStatement' ||
|
|
1859
1853
|
blockParent.type === 'DoWhileStatement' ||
|
|
1860
|
-
blockParent.type === '
|
|
1854
|
+
blockParent.type === 'TryStatement' ||
|
|
1855
|
+
blockParent.type === 'CatchClause' ||
|
|
1856
|
+
blockParent.type === 'SwitchCase' ||
|
|
1857
|
+
blockParent.type === 'JSXIfExpression' ||
|
|
1858
|
+
blockParent.type === 'JSXForExpression' ||
|
|
1859
|
+
blockParent.type === 'JSXTryExpression' ||
|
|
1860
|
+
blockParent.type === 'JSXSwitchExpression');
|
|
1861
1861
|
|
|
1862
1862
|
if (isControlFlow) {
|
|
1863
1863
|
nodeContent = ['{', hardline, '}'];
|
|
@@ -4010,7 +4010,6 @@ function printMemberExpression(node, path, options, print) {
|
|
|
4010
4010
|
|
|
4011
4011
|
let result;
|
|
4012
4012
|
if (node.computed) {
|
|
4013
|
-
// Check if the MemberExpression itself is tracked to add @ symbol
|
|
4014
4013
|
const openBracket = node.optional ? '?.[' : '[';
|
|
4015
4014
|
result = [objectPart, openBracket, propertyPart, ']'];
|
|
4016
4015
|
} else {
|
|
@@ -6086,11 +6085,19 @@ function printJSXElement(node, path, options, print) {
|
|
|
6086
6085
|
return Array.isArray(leadingComments) && leadingComments.length > 0;
|
|
6087
6086
|
});
|
|
6088
6087
|
const forceMultiline = hasClosingComments || hasChildLeadingComments;
|
|
6088
|
+
const singleChildNode = childNodes.length === 1 ? childNodes[0] : null;
|
|
6089
|
+
const hasAuthoredMultilineSingleTextChild =
|
|
6090
|
+
singleChildNode?.type === 'JSXText' && /[\r\n]/u.test(singleChildNode.value);
|
|
6089
6091
|
|
|
6090
6092
|
// Check if content can be inlined (single text node or single expression).
|
|
6091
6093
|
// Trailing or child-leading comments force the multi-line layout. A single
|
|
6092
6094
|
// text child stays inline when it fits and otherwise fills/wraps to printWidth.
|
|
6093
|
-
if (
|
|
6095
|
+
if (
|
|
6096
|
+
!forceMultiline &&
|
|
6097
|
+
!hasAuthoredMultilineSingleTextChild &&
|
|
6098
|
+
childrenDocs.length === 1 &&
|
|
6099
|
+
typeof childrenDocs[0] === 'string'
|
|
6100
|
+
) {
|
|
6094
6101
|
// The open tag breaks for attributes independently; the text+closing get
|
|
6095
6102
|
// their own group so the text only drops to its own (filled) lines when it
|
|
6096
6103
|
// itself overflows — otherwise it hugs `>text</tag>`.
|
|
@@ -6464,7 +6471,7 @@ function printJSXAttribute(attr, path, options, print) {
|
|
|
6464
6471
|
*/
|
|
6465
6472
|
function printJSXElementName(node) {
|
|
6466
6473
|
if (node.type === 'JSXIdentifier') {
|
|
6467
|
-
return
|
|
6474
|
+
return node.name;
|
|
6468
6475
|
}
|
|
6469
6476
|
if (node.type === 'JSXMemberExpression') {
|
|
6470
6477
|
return printJSXElementName(node.object) + '.' + printJSXElementName(node.property);
|
|
@@ -6477,14 +6484,6 @@ function printJSXElementName(node) {
|
|
|
6477
6484
|
return 'Unknown';
|
|
6478
6485
|
}
|
|
6479
6486
|
|
|
6480
|
-
/**
|
|
6481
|
-
* @param {ESTreeJSX.JSXIdentifier} node
|
|
6482
|
-
* @returns {boolean}
|
|
6483
|
-
*/
|
|
6484
|
-
function isDynamicJSXIdentifier(node) {
|
|
6485
|
-
return /** @type {{ dynamic?: boolean }} */ (node).dynamic === true;
|
|
6486
|
-
}
|
|
6487
|
-
|
|
6488
6487
|
/**
|
|
6489
6488
|
* Print a member expression as simple string (for element tag names)
|
|
6490
6489
|
* @param {AST.Node} node - The node to print
|
|
@@ -6494,7 +6493,7 @@ function isDynamicJSXIdentifier(node) {
|
|
|
6494
6493
|
*/
|
|
6495
6494
|
function printMemberExpressionSimple(node, options, computed = false) {
|
|
6496
6495
|
if (node.type === 'JSXIdentifier') {
|
|
6497
|
-
return
|
|
6496
|
+
return node.name;
|
|
6498
6497
|
}
|
|
6499
6498
|
|
|
6500
6499
|
if (node.type === 'JSXMemberExpression') {
|
|
@@ -6510,7 +6509,7 @@ function printMemberExpressionSimple(node, options, computed = false) {
|
|
|
6510
6509
|
}
|
|
6511
6510
|
|
|
6512
6511
|
if (node.type === 'Identifier') {
|
|
6513
|
-
return
|
|
6512
|
+
return node.name;
|
|
6514
6513
|
}
|
|
6515
6514
|
|
|
6516
6515
|
if (node.type === 'MemberExpression') {
|
package/src/index.test.js
CHANGED
|
@@ -2,7 +2,7 @@ import { describe, it, expect } from 'vitest';
|
|
|
2
2
|
import prettier from 'prettier';
|
|
3
3
|
import { fileURLToPath } from 'url';
|
|
4
4
|
import { dirname, join } from 'path';
|
|
5
|
-
import { languages } from './index.js';
|
|
5
|
+
import { languages, parsers } from './index.js';
|
|
6
6
|
|
|
7
7
|
const __filename = fileURLToPath(import.meta.url);
|
|
8
8
|
const __dirname = dirname(__filename);
|
|
@@ -40,13 +40,16 @@ expect.extend({
|
|
|
40
40
|
|
|
41
41
|
describe('prettier-plugin', () => {
|
|
42
42
|
it('registers .tsrx as a supported file extension', () => {
|
|
43
|
-
const
|
|
43
|
+
const tsrx_language = languages?.[0];
|
|
44
44
|
|
|
45
|
-
if (!
|
|
46
|
-
throw new Error('Missing
|
|
45
|
+
if (!tsrx_language) {
|
|
46
|
+
throw new Error('Missing TSRX language metadata');
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
expect(
|
|
49
|
+
expect(tsrx_language.extensions).toContain('.tsrx');
|
|
50
|
+
expect(tsrx_language.parsers).toContain('tsrx');
|
|
51
|
+
expect(parsers?.tsrx).toBeDefined();
|
|
52
|
+
expect(parsers?.ripple).toBeUndefined();
|
|
50
53
|
});
|
|
51
54
|
|
|
52
55
|
/**
|
|
@@ -55,7 +58,7 @@ describe('prettier-plugin', () => {
|
|
|
55
58
|
*/
|
|
56
59
|
const format = async (code, options = {}) => {
|
|
57
60
|
return await prettier.format(code, {
|
|
58
|
-
parser: '
|
|
61
|
+
parser: 'tsrx',
|
|
59
62
|
plugins: [join(__dirname, 'index.js')],
|
|
60
63
|
...options,
|
|
61
64
|
});
|
|
@@ -233,10 +236,10 @@ const items=[1,2,3];
|
|
|
233
236
|
});
|
|
234
237
|
|
|
235
238
|
it('keeps native fragments expression based', async () => {
|
|
236
|
-
const input = `function App(){return <><div>
|
|
239
|
+
const input = `function App(){return <><div>Hello world</div>{value}</>}`;
|
|
237
240
|
const expected = `function App() {
|
|
238
241
|
return <>
|
|
239
|
-
<div>
|
|
242
|
+
<div>Hello world</div>
|
|
240
243
|
{value}
|
|
241
244
|
</>;
|
|
242
245
|
}`;
|
|
@@ -277,17 +280,17 @@ const items=[1,2,3];
|
|
|
277
280
|
const input = `export function App() {
|
|
278
281
|
let [count] = track(0);
|
|
279
282
|
return <div>
|
|
280
|
-
<p>
|
|
281
|
-
<p>
|
|
282
|
-
<button onClick={() => count++}>
|
|
283
|
+
<p>Count: {count}</p>
|
|
284
|
+
<p>Count: {count}</p>
|
|
285
|
+
<button onClick={() => count++}>Increment</button>
|
|
283
286
|
</div>;
|
|
284
287
|
}`;
|
|
285
288
|
const expected = `export function App() {
|
|
286
289
|
let [count] = track(0);
|
|
287
290
|
return <div>
|
|
288
|
-
<p>
|
|
289
|
-
<p>
|
|
290
|
-
<button onClick={() => count++}>
|
|
291
|
+
<p>Count: {count}</p>
|
|
292
|
+
<p>Count: {count}</p>
|
|
293
|
+
<button onClick={() => count++}>Increment</button>
|
|
291
294
|
</div>;
|
|
292
295
|
}`;
|
|
293
296
|
|
|
@@ -295,6 +298,39 @@ const items=[1,2,3];
|
|
|
295
298
|
expect(result).toBeWithNewline(expected);
|
|
296
299
|
});
|
|
297
300
|
|
|
301
|
+
it('preserves authored multiline whitespace around a single JSXText child', async () => {
|
|
302
|
+
const input = `function Foo() @{
|
|
303
|
+
@if (props.onRemove) {
|
|
304
|
+
<button
|
|
305
|
+
class={\`\${styles.actionButton} \${styles.actionButtonDanger}\`}
|
|
306
|
+
type="button"
|
|
307
|
+
onClick={() => {
|
|
308
|
+
void props.onRemove?.();
|
|
309
|
+
}}
|
|
310
|
+
>
|
|
311
|
+
Remove shortcut
|
|
312
|
+
</button>
|
|
313
|
+
}
|
|
314
|
+
}`;
|
|
315
|
+
|
|
316
|
+
const expected = `function Foo() @{
|
|
317
|
+
@if (props.onRemove) {
|
|
318
|
+
<button
|
|
319
|
+
class={\`\${styles.actionButton} \${styles.actionButtonDanger}\`}
|
|
320
|
+
type="button"
|
|
321
|
+
onClick={() => {
|
|
322
|
+
void props.onRemove?.();
|
|
323
|
+
}}
|
|
324
|
+
>
|
|
325
|
+
Remove shortcut
|
|
326
|
+
</button>
|
|
327
|
+
}
|
|
328
|
+
}`;
|
|
329
|
+
|
|
330
|
+
const result = await format(input);
|
|
331
|
+
expect(result).toBeWithNewline(expected);
|
|
332
|
+
});
|
|
333
|
+
|
|
298
334
|
it('preserves inline text spaces around expression children', async () => {
|
|
299
335
|
const input = `function Test(){return <div><p class="status">Visible: {String(visible)}</p><p>{name} is visible</p><p>Hello {name}!</p></div>}`;
|
|
300
336
|
const expected = `function Test() {
|
|
@@ -400,28 +436,6 @@ function App() {
|
|
|
400
436
|
expect(result).toBeWithNewline(expected);
|
|
401
437
|
});
|
|
402
438
|
|
|
403
|
-
it('preserves dynamic component syntax', async () => {
|
|
404
|
-
const input = `function App(){return <>@{
|
|
405
|
-
function Basic(){return <><div>{"Basic Component"}</div></>;}
|
|
406
|
-
const obj={Basic};
|
|
407
|
-
const comp=obj.Basic;
|
|
408
|
-
<@comp />
|
|
409
|
-
}</>}`;
|
|
410
|
-
const expected = `function App() {
|
|
411
|
-
return <>@{
|
|
412
|
-
function Basic() {
|
|
413
|
-
return <><div>{"Basic Component"}</div></>;
|
|
414
|
-
}
|
|
415
|
-
const obj = { Basic };
|
|
416
|
-
const comp = obj.Basic;
|
|
417
|
-
<@comp />
|
|
418
|
-
}</>;
|
|
419
|
-
}`;
|
|
420
|
-
|
|
421
|
-
const result = await format(input);
|
|
422
|
-
expect(result).toBeWithNewline(expected);
|
|
423
|
-
});
|
|
424
|
-
|
|
425
439
|
it('formats raw HTML props inside native elements', async () => {
|
|
426
440
|
const input = `function App(){return <article innerHTML={source}/>}`;
|
|
427
441
|
const expected = `function App() {
|
|
@@ -608,10 +622,10 @@ const items=[1,2,3];
|
|
|
608
622
|
});
|
|
609
623
|
|
|
610
624
|
it('should keep sibling children in tsrx expression fragments on separate lines', async () => {
|
|
611
|
-
const input = `function Test(p1,p2){return <><div>
|
|
625
|
+
const input = `function Test(p1,p2){return <><div>Hello</div><div>{p1}</div><div>{p2}</div></>}`;
|
|
612
626
|
const expected = `function Test(p1, p2) {
|
|
613
627
|
return <>
|
|
614
|
-
<div>
|
|
628
|
+
<div>Hello</div>
|
|
615
629
|
<div>{p1}</div>
|
|
616
630
|
<div>{p2}</div>
|
|
617
631
|
</>;
|
|
@@ -706,9 +720,9 @@ const items=[1,2,3];
|
|
|
706
720
|
});
|
|
707
721
|
|
|
708
722
|
it('keeps fitting single-child fragments inline and expands non-fitting single-child fragments', async () => {
|
|
709
|
-
const input = `function Test(){const short=<><span>
|
|
723
|
+
const input = `function Test(){const short=<><span>Ready</span></>;const long=<><ReallyLongComponentName first={alpha} second={beta} third={gamma}/></>;}`;
|
|
710
724
|
const expected = `function Test() {
|
|
711
|
-
const short = <><span>
|
|
725
|
+
const short = <><span>Ready</span></>;
|
|
712
726
|
const long = <>
|
|
713
727
|
<ReallyLongComponentName
|
|
714
728
|
first={alpha}
|
|
@@ -723,16 +737,16 @@ const items=[1,2,3];
|
|
|
723
737
|
});
|
|
724
738
|
|
|
725
739
|
it('expands multi-child fragments while keeping fitting openers on the first line', async () => {
|
|
726
|
-
const input = `function Test(){const short=<><div>
|
|
740
|
+
const input = `function Test(){const short=<><div>A</div><div>B</div></>;const thisNameIsRidiculouslyLongEnoughToMissThePrintWidth=<><div>A</div><div>B</div></>;}`;
|
|
727
741
|
const expected = `function Test() {
|
|
728
742
|
const short = <>
|
|
729
|
-
<div>
|
|
730
|
-
<div>
|
|
743
|
+
<div>A</div>
|
|
744
|
+
<div>B</div>
|
|
731
745
|
</>;
|
|
732
746
|
const thisNameIsRidiculouslyLongEnoughToMissThePrintWidth =
|
|
733
747
|
<>
|
|
734
|
-
<div>
|
|
735
|
-
<div>
|
|
748
|
+
<div>A</div>
|
|
749
|
+
<div>B</div>
|
|
736
750
|
</>;
|
|
737
751
|
}`;
|
|
738
752
|
|
|
@@ -816,7 +830,7 @@ const items=[1,2,3];
|
|
|
816
830
|
*/
|
|
817
831
|
const format = async (code, options = {}) => {
|
|
818
832
|
return await prettier.format(code, {
|
|
819
|
-
parser: '
|
|
833
|
+
parser: 'tsrx',
|
|
820
834
|
plugins: [join(__dirname, 'index.js')],
|
|
821
835
|
...options,
|
|
822
836
|
});
|
|
@@ -829,7 +843,7 @@ const items=[1,2,3];
|
|
|
829
843
|
*/
|
|
830
844
|
const formatWithCursorHelper = async (code, options) =>
|
|
831
845
|
await prettier.formatWithCursor(code, {
|
|
832
|
-
parser: '
|
|
846
|
+
parser: 'tsrx',
|
|
833
847
|
plugins: [join(__dirname, 'index.js')],
|
|
834
848
|
...options,
|
|
835
849
|
});
|
|
@@ -882,13 +896,14 @@ const items=[1,2,3];
|
|
|
882
896
|
});
|
|
883
897
|
|
|
884
898
|
it('registers .tsrx as a supported file extension', () => {
|
|
885
|
-
const
|
|
899
|
+
const tsrx_language = languages?.[0];
|
|
886
900
|
|
|
887
|
-
if (!
|
|
888
|
-
throw new Error('Missing
|
|
901
|
+
if (!tsrx_language) {
|
|
902
|
+
throw new Error('Missing TSRX language metadata');
|
|
889
903
|
}
|
|
890
904
|
|
|
891
|
-
expect(
|
|
905
|
+
expect(tsrx_language.extensions).toContain('.tsrx');
|
|
906
|
+
expect(tsrx_language.parsers).toContain('tsrx');
|
|
892
907
|
});
|
|
893
908
|
|
|
894
909
|
it('should format a simple component', async () => {
|
|
@@ -966,23 +981,12 @@ const items=[1,2,3];
|
|
|
966
981
|
expect(result).toBeWithNewline(expected);
|
|
967
982
|
});
|
|
968
983
|
|
|
969
|
-
it('should format a function with a dynamic function using props member access', async () => {
|
|
970
|
-
const expected = `function Card(props) {
|
|
971
|
-
<div class="card">
|
|
972
|
-
<@props.children />
|
|
973
|
-
</div>
|
|
974
|
-
}`;
|
|
975
|
-
|
|
976
|
-
const result = await format(expected, { singleQuote: true });
|
|
977
|
-
expect(result).toBeWithNewline(expected);
|
|
978
|
-
});
|
|
979
|
-
|
|
980
984
|
it('should respect print width when using ternary expressions', async () => {
|
|
981
985
|
const input = `function printMemberExpressionSimple(node, options, computed = false) {
|
|
982
986
|
if (node.type === 'MemberExpression') {
|
|
983
987
|
const prop = node.computed
|
|
984
|
-
? (node.
|
|
985
|
-
: (node.
|
|
988
|
+
? (node.optional ? '?.[' : '[') + printMemberExpressionSimple(node.property, options, node.computed) + ']'
|
|
989
|
+
: (node.optional ? '?.' : '.') + printMemberExpressionSimple(node.property, options, node.computed);
|
|
986
990
|
}
|
|
987
991
|
}`;
|
|
988
992
|
|
|
@@ -993,14 +997,14 @@ const items=[1,2,3];
|
|
|
993
997
|
) {
|
|
994
998
|
if (node.type === 'MemberExpression') {
|
|
995
999
|
const prop = node.computed
|
|
996
|
-
? (node.
|
|
1000
|
+
? (node.optional ? '?.[' : '[') +
|
|
997
1001
|
printMemberExpressionSimple(
|
|
998
1002
|
node.property,
|
|
999
1003
|
options,
|
|
1000
1004
|
node.computed,
|
|
1001
1005
|
) +
|
|
1002
1006
|
']'
|
|
1003
|
-
: (node.
|
|
1007
|
+
: (node.optional ? '?.' : '.') +
|
|
1004
1008
|
printMemberExpressionSimple(
|
|
1005
1009
|
node.property,
|
|
1006
1010
|
options,
|
|
@@ -1398,11 +1402,11 @@ export function Test({ a, b }: Props) {}`;
|
|
|
1398
1402
|
|
|
1399
1403
|
it('should not force attribute-less elements to break with singleAttributePerLine', async () => {
|
|
1400
1404
|
const input = `function One() @{
|
|
1401
|
-
<div>
|
|
1405
|
+
<div>Hello</div>
|
|
1402
1406
|
}`;
|
|
1403
1407
|
|
|
1404
1408
|
const expected = `function One() @{
|
|
1405
|
-
<div>
|
|
1409
|
+
<div>Hello</div>
|
|
1406
1410
|
}`;
|
|
1407
1411
|
|
|
1408
1412
|
const result = await format(input, {
|
|
@@ -1462,18 +1466,6 @@ export function Test({ a, b }: Props) {}`;
|
|
|
1462
1466
|
expect(result).toBeWithNewline(expected);
|
|
1463
1467
|
});
|
|
1464
1468
|
|
|
1465
|
-
it('should not strip @ from dynamic @tag', async () => {
|
|
1466
|
-
const expected = `export function Four() {
|
|
1467
|
-
let tag = track('div');
|
|
1468
|
-
|
|
1469
|
-
<@tag {href} {...props}>
|
|
1470
|
-
<@children />
|
|
1471
|
-
</@tag>
|
|
1472
|
-
}`;
|
|
1473
|
-
const result = await format(expected, { singleQuote: true, printWidth: 100 });
|
|
1474
|
-
expect(result).toBeWithNewline(expected);
|
|
1475
|
-
});
|
|
1476
|
-
|
|
1477
1469
|
it('should not include a comma after the last rest parameter', async () => {
|
|
1478
1470
|
const expected = `function Foo({
|
|
1479
1471
|
lorem,
|
|
@@ -1490,15 +1482,6 @@ export function Test({ a, b }: Props) {}`;
|
|
|
1490
1482
|
expect(result).toBeWithNewline(expected);
|
|
1491
1483
|
});
|
|
1492
1484
|
|
|
1493
|
-
it('should not strip @ from dynamic self-closing components', async () => {
|
|
1494
|
-
const expected = `function App() {
|
|
1495
|
-
<@ripple_object.tracked_basic />
|
|
1496
|
-
}`;
|
|
1497
|
-
|
|
1498
|
-
const result = await format(expected, { singleQuote: true, printWidth: 100 });
|
|
1499
|
-
expect(result).toBeWithNewline(expected);
|
|
1500
|
-
});
|
|
1501
|
-
|
|
1502
1485
|
it('keeps a new line between comments above and code if one is present', async () => {
|
|
1503
1486
|
const expected = `// comment
|
|
1504
1487
|
|
|
@@ -2545,6 +2528,51 @@ files = [...(files ?? []), ...dt.files];`;
|
|
|
2545
2528
|
expect(result).toBeWithNewline(expected);
|
|
2546
2529
|
});
|
|
2547
2530
|
|
|
2531
|
+
it('expands empty braces for template control-flow blocks', async () => {
|
|
2532
|
+
const input = `const App=()=> <>@if (ready) {} @else {}@for (const item of items) {} @empty {}</>;`;
|
|
2533
|
+
const expected = `const App = () => <>
|
|
2534
|
+
@if (ready) {
|
|
2535
|
+
} @else {
|
|
2536
|
+
}
|
|
2537
|
+
@for (const item of items) {
|
|
2538
|
+
} @empty {
|
|
2539
|
+
}
|
|
2540
|
+
</>;`;
|
|
2541
|
+
const result = await format(input);
|
|
2542
|
+
expect(result).toBeWithNewline(expected);
|
|
2543
|
+
});
|
|
2544
|
+
|
|
2545
|
+
it('expands empty braces for try family blocks', async () => {
|
|
2546
|
+
const input = `function Foo() @{ @try {} @pending {} @catch {} }
|
|
2547
|
+
function Bar() @{ @try {} @catch {} }
|
|
2548
|
+
function Baz() { try {} catch {} finally {} }
|
|
2549
|
+
function Qux() { try {} catch {} }`;
|
|
2550
|
+
const expected = `function Foo() @{
|
|
2551
|
+
@try {
|
|
2552
|
+
} @pending {
|
|
2553
|
+
} @catch {
|
|
2554
|
+
}
|
|
2555
|
+
}
|
|
2556
|
+
function Bar() @{
|
|
2557
|
+
@try {
|
|
2558
|
+
} @catch {
|
|
2559
|
+
}
|
|
2560
|
+
}
|
|
2561
|
+
function Baz() {
|
|
2562
|
+
try {
|
|
2563
|
+
} catch {
|
|
2564
|
+
} finally {
|
|
2565
|
+
}
|
|
2566
|
+
}
|
|
2567
|
+
function Qux() {
|
|
2568
|
+
try {
|
|
2569
|
+
} catch {
|
|
2570
|
+
}
|
|
2571
|
+
}`;
|
|
2572
|
+
const result = await format(input);
|
|
2573
|
+
expect(result).toBeWithNewline(expected);
|
|
2574
|
+
});
|
|
2575
|
+
|
|
2548
2576
|
it('prints function with a rest parameter correctly', async () => {
|
|
2549
2577
|
const expected = `function TestRest(...args: string[]) {
|
|
2550
2578
|
console.log(args);
|
|
@@ -5604,7 +5632,7 @@ render(App);`;
|
|
|
5604
5632
|
expect(result).toBeWithNewline(expected);
|
|
5605
5633
|
});
|
|
5606
5634
|
|
|
5607
|
-
it('should preserve the order of try / pending / catch
|
|
5635
|
+
it('should preserve the order of try / pending / catch blocks', async () => {
|
|
5608
5636
|
const expected = `function Test() {
|
|
5609
5637
|
let items: RippleArray<string> | null = null;
|
|
5610
5638
|
let error: string | null = null;
|
|
@@ -5622,8 +5650,6 @@ render(App);`;
|
|
|
5622
5650
|
<div>{'Loading...'}</div>
|
|
5623
5651
|
} @catch (e) {
|
|
5624
5652
|
error = (e as Error).message;
|
|
5625
|
-
} finally {
|
|
5626
|
-
<div>finally block</div>
|
|
5627
5653
|
};
|
|
5628
5654
|
}`;
|
|
5629
5655
|
|
|
@@ -5738,7 +5764,8 @@ render(App);`;
|
|
|
5738
5764
|
// <div>
|
|
5739
5765
|
@try {
|
|
5740
5766
|
<div>b is true</div>
|
|
5741
|
-
} @catch (e) {
|
|
5767
|
+
} @catch (e) {
|
|
5768
|
+
}
|
|
5742
5769
|
// <div>
|
|
5743
5770
|
// <div>
|
|
5744
5771
|
// @if (b) {
|
|
@@ -5756,7 +5783,8 @@ render(App);`;
|
|
|
5756
5783
|
// <div>
|
|
5757
5784
|
@try {
|
|
5758
5785
|
<div>b is true</div>
|
|
5759
|
-
} @catch (e) {
|
|
5786
|
+
} @catch (e) {
|
|
5787
|
+
}
|
|
5760
5788
|
// <div>
|
|
5761
5789
|
// <div>
|
|
5762
5790
|
// @if (b) {
|