@ripple-ts/prettier-plugin 0.2.156 → 0.2.158
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 +127 -24
- package/src/index.test.js +114 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ripple-ts/prettier-plugin",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.158",
|
|
4
4
|
"description": "Ripple plugin for Prettier",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "src/index.js",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
27
|
"prettier": "^3.6.2",
|
|
28
|
-
"ripple": "0.2.
|
|
28
|
+
"ripple": "0.2.158"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {},
|
|
31
31
|
"files": [
|
package/src/index.js
CHANGED
|
@@ -1163,10 +1163,19 @@ function printRippleNode(node, path, options, print, args) {
|
|
|
1163
1163
|
break;
|
|
1164
1164
|
}
|
|
1165
1165
|
|
|
1166
|
+
case 'TSNonNullExpression': {
|
|
1167
|
+
nodeContent = concat([path.call(print, 'expression'), '!']);
|
|
1168
|
+
break;
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1171
|
+
case 'JSXExpressionContainer': {
|
|
1172
|
+
nodeContent = concat(['{', path.call(print, 'expression'), '}']);
|
|
1173
|
+
break;
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1166
1176
|
case 'NewExpression':
|
|
1167
1177
|
nodeContent = printNewExpression(node, path, options, print);
|
|
1168
1178
|
break;
|
|
1169
|
-
|
|
1170
1179
|
case 'TemplateLiteral':
|
|
1171
1180
|
nodeContent = printTemplateLiteral(node, path, options, print);
|
|
1172
1181
|
break;
|
|
@@ -1324,8 +1333,10 @@ function printRippleNode(node, path, options, print, args) {
|
|
|
1324
1333
|
const trackedPrefix = node.tracked ? '@' : '';
|
|
1325
1334
|
let identifierContent;
|
|
1326
1335
|
if (node.typeAnnotation) {
|
|
1336
|
+
const optionalMarker = node.optional ? '?' : '';
|
|
1327
1337
|
identifierContent = concat([
|
|
1328
1338
|
trackedPrefix + node.name,
|
|
1339
|
+
optionalMarker,
|
|
1329
1340
|
': ',
|
|
1330
1341
|
path.call(print, 'typeAnnotation'),
|
|
1331
1342
|
]);
|
|
@@ -1348,7 +1359,6 @@ function printRippleNode(node, path, options, print, args) {
|
|
|
1348
1359
|
}
|
|
1349
1360
|
break;
|
|
1350
1361
|
}
|
|
1351
|
-
|
|
1352
1362
|
case 'Literal':
|
|
1353
1363
|
// Handle regex literals specially
|
|
1354
1364
|
if (node.regex) {
|
|
@@ -1645,10 +1655,13 @@ function printRippleNode(node, path, options, print, args) {
|
|
|
1645
1655
|
nodeContent = printTSPropertySignature(node, path, options, print);
|
|
1646
1656
|
break;
|
|
1647
1657
|
|
|
1658
|
+
case 'TSMethodSignature':
|
|
1659
|
+
nodeContent = printTSMethodSignature(node, path, options, print);
|
|
1660
|
+
break;
|
|
1661
|
+
|
|
1648
1662
|
case 'TSEnumMember':
|
|
1649
1663
|
nodeContent = printTSEnumMember(node, path, options, print);
|
|
1650
1664
|
break;
|
|
1651
|
-
|
|
1652
1665
|
case 'TSLiteralType':
|
|
1653
1666
|
nodeContent = path.call(print, 'literal');
|
|
1654
1667
|
break;
|
|
@@ -3863,6 +3876,47 @@ function printTSPropertySignature(node, path, options, print) {
|
|
|
3863
3876
|
return concat(parts);
|
|
3864
3877
|
}
|
|
3865
3878
|
|
|
3879
|
+
function printTSMethodSignature(node, path, options, print) {
|
|
3880
|
+
const parts = [];
|
|
3881
|
+
|
|
3882
|
+
// Print the method name/key
|
|
3883
|
+
parts.push(path.call(print, 'key'));
|
|
3884
|
+
|
|
3885
|
+
// Add optional marker if present
|
|
3886
|
+
if (node.optional) {
|
|
3887
|
+
parts.push('?');
|
|
3888
|
+
}
|
|
3889
|
+
|
|
3890
|
+
// Add TypeScript generics/type parameters if present
|
|
3891
|
+
if (node.typeParameters) {
|
|
3892
|
+
const typeParams = path.call(print, 'typeParameters');
|
|
3893
|
+
if (Array.isArray(typeParams)) {
|
|
3894
|
+
parts.push(...typeParams);
|
|
3895
|
+
} else {
|
|
3896
|
+
parts.push(typeParams);
|
|
3897
|
+
}
|
|
3898
|
+
}
|
|
3899
|
+
|
|
3900
|
+
// Print parameters - use 'parameters' property for TypeScript signature nodes
|
|
3901
|
+
parts.push('(');
|
|
3902
|
+
if (node.parameters && node.parameters.length > 0) {
|
|
3903
|
+
const params = path.map(print, 'parameters');
|
|
3904
|
+
for (let i = 0; i < params.length; i++) {
|
|
3905
|
+
if (i > 0) parts.push(', ');
|
|
3906
|
+
parts.push(params[i]);
|
|
3907
|
+
}
|
|
3908
|
+
}
|
|
3909
|
+
parts.push(')');
|
|
3910
|
+
|
|
3911
|
+
// Return type annotation
|
|
3912
|
+
if (node.typeAnnotation) {
|
|
3913
|
+
parts.push(': ');
|
|
3914
|
+
parts.push(path.call(print, 'typeAnnotation'));
|
|
3915
|
+
}
|
|
3916
|
+
|
|
3917
|
+
return concat(parts);
|
|
3918
|
+
}
|
|
3919
|
+
|
|
3866
3920
|
function printTSTypeReference(node, path, options, print) {
|
|
3867
3921
|
const parts = [path.call(print, 'typeName')];
|
|
3868
3922
|
|
|
@@ -4276,29 +4330,59 @@ function printTsxCompat(node, path, options, print) {
|
|
|
4276
4330
|
}
|
|
4277
4331
|
|
|
4278
4332
|
// Print JSXElement children - they remain as JSX
|
|
4279
|
-
// Filter out whitespace-only JSXText nodes
|
|
4333
|
+
// Filter out whitespace-only JSXText nodes and merge adjacent text-like nodes
|
|
4280
4334
|
const finalChildren = [];
|
|
4335
|
+
let accumulatedText = '';
|
|
4281
4336
|
|
|
4282
4337
|
for (let i = 0; i < node.children.length; i++) {
|
|
4283
4338
|
const child = node.children[i];
|
|
4284
4339
|
|
|
4285
|
-
//
|
|
4286
|
-
|
|
4287
|
-
continue;
|
|
4288
|
-
}
|
|
4340
|
+
// Check if this is a text-like node (JSXText or Identifier in JSX context)
|
|
4341
|
+
const isTextLike = child.type === 'JSXText' || child.type === 'Identifier';
|
|
4289
4342
|
|
|
4290
|
-
|
|
4291
|
-
|
|
4343
|
+
if (isTextLike) {
|
|
4344
|
+
// Get the text content
|
|
4345
|
+
let text;
|
|
4346
|
+
if (child.type === 'JSXText') {
|
|
4347
|
+
text = child.value.trim();
|
|
4348
|
+
} else if (child.type === 'Identifier') {
|
|
4349
|
+
text = child.name;
|
|
4350
|
+
}
|
|
4292
4351
|
|
|
4293
|
-
|
|
4294
|
-
|
|
4295
|
-
|
|
4296
|
-
|
|
4352
|
+
if (text) {
|
|
4353
|
+
if (accumulatedText) {
|
|
4354
|
+
accumulatedText += ' ' + text;
|
|
4355
|
+
} else {
|
|
4356
|
+
accumulatedText = text;
|
|
4357
|
+
}
|
|
4358
|
+
}
|
|
4359
|
+
} else {
|
|
4360
|
+
// Before adding non-text node, flush accumulated text
|
|
4361
|
+
if (accumulatedText) {
|
|
4362
|
+
if (finalChildren.length > 0) {
|
|
4363
|
+
finalChildren.push(hardline);
|
|
4364
|
+
}
|
|
4365
|
+
finalChildren.push(accumulatedText);
|
|
4366
|
+
accumulatedText = '';
|
|
4367
|
+
}
|
|
4368
|
+
|
|
4369
|
+
if (finalChildren.length > 0) {
|
|
4297
4370
|
finalChildren.push(hardline);
|
|
4298
4371
|
}
|
|
4372
|
+
|
|
4373
|
+
const printedChild = path.call(print, 'children', i);
|
|
4374
|
+
finalChildren.push(printedChild);
|
|
4299
4375
|
}
|
|
4300
4376
|
}
|
|
4301
4377
|
|
|
4378
|
+
// Don't forget any remaining accumulated text
|
|
4379
|
+
if (accumulatedText) {
|
|
4380
|
+
if (finalChildren.length > 0) {
|
|
4381
|
+
finalChildren.push(hardline);
|
|
4382
|
+
}
|
|
4383
|
+
finalChildren.push(accumulatedText);
|
|
4384
|
+
}
|
|
4385
|
+
|
|
4302
4386
|
// Format the TsxCompat element
|
|
4303
4387
|
const elementOutput = group([
|
|
4304
4388
|
tagName,
|
|
@@ -4355,26 +4439,45 @@ function printJSXElement(node, path, options, print) {
|
|
|
4355
4439
|
return concat(['<', tagName, attributesDoc, '></', tagName, '>']);
|
|
4356
4440
|
}
|
|
4357
4441
|
|
|
4358
|
-
// Format children - filter out empty text nodes
|
|
4442
|
+
// Format children - filter out empty text nodes and merge adjacent text nodes
|
|
4359
4443
|
const childrenDocs = [];
|
|
4444
|
+
let currentText = '';
|
|
4445
|
+
|
|
4360
4446
|
for (let i = 0; i < node.children.length; i++) {
|
|
4361
4447
|
const child = node.children[i];
|
|
4362
4448
|
|
|
4363
4449
|
if (child.type === 'JSXText') {
|
|
4364
|
-
//
|
|
4365
|
-
const
|
|
4366
|
-
if (
|
|
4367
|
-
|
|
4450
|
+
// Accumulate text content, preserving spaces between words
|
|
4451
|
+
const trimmed = child.value.trim();
|
|
4452
|
+
if (trimmed) {
|
|
4453
|
+
if (currentText) {
|
|
4454
|
+
currentText += ' ' + trimmed;
|
|
4455
|
+
} else {
|
|
4456
|
+
currentText = trimmed;
|
|
4457
|
+
}
|
|
4368
4458
|
}
|
|
4369
|
-
} else if (child.type === 'JSXExpressionContainer') {
|
|
4370
|
-
// Handle JSX expression containers
|
|
4371
|
-
childrenDocs.push(concat(['{', path.call(print, 'children', i, 'expression'), '}']));
|
|
4372
4459
|
} else {
|
|
4373
|
-
//
|
|
4374
|
-
|
|
4460
|
+
// If we have accumulated text, push it before the non-text node
|
|
4461
|
+
if (currentText) {
|
|
4462
|
+
childrenDocs.push(currentText);
|
|
4463
|
+
currentText = '';
|
|
4464
|
+
}
|
|
4465
|
+
|
|
4466
|
+
if (child.type === 'JSXExpressionContainer') {
|
|
4467
|
+
// Handle JSX expression containers
|
|
4468
|
+
childrenDocs.push(concat(['{', path.call(print, 'children', i, 'expression'), '}']));
|
|
4469
|
+
} else {
|
|
4470
|
+
// Handle nested JSX elements
|
|
4471
|
+
childrenDocs.push(path.call(print, 'children', i));
|
|
4472
|
+
}
|
|
4375
4473
|
}
|
|
4376
4474
|
}
|
|
4377
4475
|
|
|
4476
|
+
// Don't forget any remaining text
|
|
4477
|
+
if (currentText) {
|
|
4478
|
+
childrenDocs.push(currentText);
|
|
4479
|
+
}
|
|
4480
|
+
|
|
4378
4481
|
// Check if content can be inlined (single text node or single expression)
|
|
4379
4482
|
if (childrenDocs.length === 1 && typeof childrenDocs[0] === 'string') {
|
|
4380
4483
|
return concat(['<', tagName, attributesDoc, '>', childrenDocs[0], '</', tagName, '>']);
|
package/src/index.test.js
CHANGED
|
@@ -2282,6 +2282,44 @@ const items = [] as unknown[];`;
|
|
|
2282
2282
|
expect(result).toBeWithNewline(expected);
|
|
2283
2283
|
});
|
|
2284
2284
|
|
|
2285
|
+
it('should format TSMethodSignature in interfaces', async () => {
|
|
2286
|
+
const input = `interface API{get(path:string):Promise<Response>;post<T>(path:string,data:T):Promise<Response>;delete?(id:number):void}`;
|
|
2287
|
+
const expected = `interface API {
|
|
2288
|
+
get(path: string): Promise<Response>;
|
|
2289
|
+
post<T>(path: string, data: T): Promise<Response>;
|
|
2290
|
+
delete?(id: number): void;
|
|
2291
|
+
}`;
|
|
2292
|
+
const result = await format(input);
|
|
2293
|
+
expect(result).toBeWithNewline(expected);
|
|
2294
|
+
});
|
|
2295
|
+
|
|
2296
|
+
it('should format TSMethodSignature with type parameters', async () => {
|
|
2297
|
+
const input = `interface Collection{map<U>(fn:(item:T)=>U):U[];filter(predicate:(item:T)=>boolean):T[]}`;
|
|
2298
|
+
const expected = `interface Collection {\n map<U>(fn: (item: T) => U): U[];\n filter(predicate: (item: T) => boolean): T[];\n}`;
|
|
2299
|
+
const result = await format(input);
|
|
2300
|
+
expect(result).toBeWithNewline(expected);
|
|
2301
|
+
});
|
|
2302
|
+
|
|
2303
|
+
it('should format TSNonNullExpression', async () => {
|
|
2304
|
+
const input = `component Test(){let value:string|null=null;let length=value!.length;<div>{length}</div>}`;
|
|
2305
|
+
const expected = `component Test() {
|
|
2306
|
+
let value: string | null = null;
|
|
2307
|
+
let length = value!.length;
|
|
2308
|
+
<div>{length}</div>
|
|
2309
|
+
}`;
|
|
2310
|
+
const result = await format(input);
|
|
2311
|
+
expect(result).toBeWithNewline(expected);
|
|
2312
|
+
});
|
|
2313
|
+
|
|
2314
|
+
it('should format TSNonNullExpression in complex expressions', async () => {
|
|
2315
|
+
const input = `function getValue(x?:string){return x!.toUpperCase()}`;
|
|
2316
|
+
const expected = `function getValue(x?: string) {
|
|
2317
|
+
return x!.toUpperCase();
|
|
2318
|
+
}`;
|
|
2319
|
+
const result = await format(input);
|
|
2320
|
+
expect(result).toBeWithNewline(expected);
|
|
2321
|
+
});
|
|
2322
|
+
|
|
2285
2323
|
it('should retain templated declarations', async () => {
|
|
2286
2324
|
const expected = `function Wrapper() {
|
|
2287
2325
|
return {
|
|
@@ -3774,6 +3812,82 @@ component Polygon() {
|
|
|
3774
3812
|
const result = await format(input, { singleQuote: true });
|
|
3775
3813
|
expect(result).toBeWithNewline(expected);
|
|
3776
3814
|
});
|
|
3815
|
+
|
|
3816
|
+
it('should format JSXExpressionContainer with function calls', async () => {
|
|
3817
|
+
const input = `function foo(){return 123}component App(){<div><tsx:react>{foo()}</tsx:react></div>}`;
|
|
3818
|
+
|
|
3819
|
+
const expected = `function foo() {
|
|
3820
|
+
return 123;
|
|
3821
|
+
}
|
|
3822
|
+
component App() {
|
|
3823
|
+
<div>
|
|
3824
|
+
<tsx:react>
|
|
3825
|
+
{foo()}
|
|
3826
|
+
</tsx:react>
|
|
3827
|
+
</div>
|
|
3828
|
+
}`;
|
|
3829
|
+
|
|
3830
|
+
const result = await format(input);
|
|
3831
|
+
expect(result).toBeWithNewline(expected);
|
|
3832
|
+
});
|
|
3833
|
+
|
|
3834
|
+
it('should format JSXExpressionContainer with function calls', async () => {
|
|
3835
|
+
const input = `function foo(){return 123}component App(){<div><tsx:react>{foo()}<div>Hello world</div>Hello world</tsx:react></div>}`;
|
|
3836
|
+
|
|
3837
|
+
const expected = `function foo() {
|
|
3838
|
+
return 123;
|
|
3839
|
+
}
|
|
3840
|
+
component App() {
|
|
3841
|
+
<div>
|
|
3842
|
+
<tsx:react>
|
|
3843
|
+
{foo()}
|
|
3844
|
+
<div>Hello world</div>
|
|
3845
|
+
Hello world
|
|
3846
|
+
</tsx:react>
|
|
3847
|
+
</div>
|
|
3848
|
+
}`;
|
|
3849
|
+
|
|
3850
|
+
const result = await format(input);
|
|
3851
|
+
expect(result).toBeWithNewline(expected);
|
|
3852
|
+
});
|
|
3853
|
+
|
|
3854
|
+
it('should format JSXExpressionContainer with function calls #2', async () => {
|
|
3855
|
+
const input = `export component App() {
|
|
3856
|
+
<tsx:react>
|
|
3857
|
+
Hello world
|
|
3858
|
+
<DemoContext.Provider value={"Hello from Context!"}>
|
|
3859
|
+
<Child count={@count} />
|
|
3860
|
+
</DemoContext.Provider>
|
|
3861
|
+
</tsx:react>
|
|
3862
|
+
}`;
|
|
3863
|
+
const expected = `export component App() {
|
|
3864
|
+
<tsx:react>
|
|
3865
|
+
Hello world
|
|
3866
|
+
<DemoContext.Provider value={"Hello from Context!"}>
|
|
3867
|
+
<Child count={@count} />
|
|
3868
|
+
</DemoContext.Provider>
|
|
3869
|
+
</tsx:react>
|
|
3870
|
+
}`;
|
|
3871
|
+
|
|
3872
|
+
const result = await format(input);
|
|
3873
|
+
expect(result).toBeWithNewline(expected);
|
|
3874
|
+
});
|
|
3875
|
+
it('should format JSXExpressionContainer with complex expressions', async () => {
|
|
3876
|
+
const input = `component App(){let count=track(0);<tsx:react><div>{count*2+10}</div>{getMessage("test")}</tsx:react>}`;
|
|
3877
|
+
|
|
3878
|
+
const expected = `component App() {
|
|
3879
|
+
let count = track(0);
|
|
3880
|
+
<tsx:react>
|
|
3881
|
+
<div>
|
|
3882
|
+
{count * 2 + 10}
|
|
3883
|
+
</div>
|
|
3884
|
+
{getMessage('test')}
|
|
3885
|
+
</tsx:react>
|
|
3886
|
+
}`;
|
|
3887
|
+
|
|
3888
|
+
const result = await format(input, { singleQuote: true });
|
|
3889
|
+
expect(result).toBeWithNewline(expected);
|
|
3890
|
+
});
|
|
3777
3891
|
});
|
|
3778
3892
|
});
|
|
3779
3893
|
});
|