@ripple-ts/prettier-plugin 0.2.199 → 0.2.201
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 +107 -65
- package/src/index.test.js +133 -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.201",
|
|
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.201"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {},
|
|
31
31
|
"files": [
|
package/src/index.js
CHANGED
|
@@ -550,6 +550,36 @@ function buildInlineArrayCommentDoc(comments) {
|
|
|
550
550
|
return docs.length > 0 ? concat(docs) : null;
|
|
551
551
|
}
|
|
552
552
|
|
|
553
|
+
/**
|
|
554
|
+
* @param {AST.Property | AST.MethodDefinition} node
|
|
555
|
+
*/
|
|
556
|
+
function printKey(node, path, options, print) {
|
|
557
|
+
const parts = [];
|
|
558
|
+
if (node.computed) {
|
|
559
|
+
// computed are never converted to identifiers
|
|
560
|
+
parts.push('[', path.call(print, 'key'), ']');
|
|
561
|
+
return parts;
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
if (node.key.type === 'Literal' && typeof node.key.value === 'string') {
|
|
565
|
+
// Check if the key is a valid identifier that doesn't need quotes
|
|
566
|
+
const key = node.key.value;
|
|
567
|
+
const isValidIdentifier = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(key);
|
|
568
|
+
|
|
569
|
+
if (isValidIdentifier) {
|
|
570
|
+
// Don't quote valid identifiers
|
|
571
|
+
parts.push(key);
|
|
572
|
+
} else {
|
|
573
|
+
// Quote keys that need it (e.g., contain special characters)
|
|
574
|
+
parts.push(formatStringLiteral(key, options));
|
|
575
|
+
}
|
|
576
|
+
} else {
|
|
577
|
+
parts.push(path.call(print, 'key'));
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
return parts;
|
|
581
|
+
}
|
|
582
|
+
|
|
553
583
|
function printRippleNode(node, path, options, print, args) {
|
|
554
584
|
if (!node || typeof node !== 'object') {
|
|
555
585
|
return String(node || '');
|
|
@@ -682,7 +712,7 @@ function printRippleNode(node, path, options, print, args) {
|
|
|
682
712
|
break;
|
|
683
713
|
|
|
684
714
|
case 'Component':
|
|
685
|
-
nodeContent = printComponent(node, path, options, print, innerCommentParts);
|
|
715
|
+
nodeContent = printComponent(node, path, options, print, innerCommentParts, args);
|
|
686
716
|
break;
|
|
687
717
|
|
|
688
718
|
case 'ExportNamedDeclaration':
|
|
@@ -2200,9 +2230,20 @@ function printExportNamedDeclaration(node, path, options, print) {
|
|
|
2200
2230
|
return 'export';
|
|
2201
2231
|
}
|
|
2202
2232
|
|
|
2203
|
-
function printComponent(
|
|
2233
|
+
function printComponent(
|
|
2234
|
+
node,
|
|
2235
|
+
path,
|
|
2236
|
+
options,
|
|
2237
|
+
print,
|
|
2238
|
+
innerCommentParts = [],
|
|
2239
|
+
args = { skipComponentLabel: false },
|
|
2240
|
+
) {
|
|
2204
2241
|
// Use arrays instead of string concatenation
|
|
2205
|
-
const signatureParts =
|
|
2242
|
+
const signatureParts = args.skipComponentLabel
|
|
2243
|
+
? []
|
|
2244
|
+
: node.id
|
|
2245
|
+
? ['component ', node.id.name]
|
|
2246
|
+
: ['component'];
|
|
2206
2247
|
|
|
2207
2248
|
// Add TypeScript generics if present
|
|
2208
2249
|
if (node.typeParameters) {
|
|
@@ -3106,9 +3147,24 @@ function printObjectExpression(node, path, options, print, args) {
|
|
|
3106
3147
|
propertyParts.push(',');
|
|
3107
3148
|
|
|
3108
3149
|
// Check for blank lines between properties and preserve them
|
|
3150
|
+
// Need to account for trailing comments on previous property and
|
|
3151
|
+
// leading comments on current property
|
|
3109
3152
|
const prevProp = node.properties[i - 1];
|
|
3110
3153
|
const currentProp = node.properties[i];
|
|
3111
|
-
|
|
3154
|
+
|
|
3155
|
+
// Determine the source node (end of previous property or its trailing comments)
|
|
3156
|
+
let sourceNode = prevProp;
|
|
3157
|
+
if (prevProp?.trailingComments?.length > 0) {
|
|
3158
|
+
sourceNode = prevProp.trailingComments[prevProp.trailingComments.length - 1];
|
|
3159
|
+
}
|
|
3160
|
+
|
|
3161
|
+
// Determine the target node (start of current property or its leading comments)
|
|
3162
|
+
let targetNode = currentProp;
|
|
3163
|
+
if (currentProp?.leadingComments?.length > 0) {
|
|
3164
|
+
targetNode = currentProp.leadingComments[0];
|
|
3165
|
+
}
|
|
3166
|
+
|
|
3167
|
+
if (sourceNode && targetNode && getBlankLinesBetweenNodes(sourceNode, targetNode) > 0) {
|
|
3112
3168
|
propertyParts.push(hardline);
|
|
3113
3169
|
propertyParts.push(hardline); // Two hardlines = blank line
|
|
3114
3170
|
} else {
|
|
@@ -3259,6 +3315,7 @@ function printPropertyDefinition(node, path, options, print) {
|
|
|
3259
3315
|
|
|
3260
3316
|
function printMethodDefinition(node, path, options, print) {
|
|
3261
3317
|
const parts = [];
|
|
3318
|
+
const is_component = node.value?.type === 'Component';
|
|
3262
3319
|
|
|
3263
3320
|
// Access modifiers (public, private, protected)
|
|
3264
3321
|
if (node.accessibility) {
|
|
@@ -3271,24 +3328,37 @@ function printMethodDefinition(node, path, options, print) {
|
|
|
3271
3328
|
parts.push('static ');
|
|
3272
3329
|
}
|
|
3273
3330
|
|
|
3274
|
-
// Async keyword
|
|
3275
|
-
if (node.value && node.value.async) {
|
|
3276
|
-
parts.push('async ');
|
|
3277
|
-
}
|
|
3278
|
-
|
|
3279
3331
|
// Method kind and name
|
|
3280
3332
|
if (node.kind === 'constructor') {
|
|
3281
|
-
|
|
3333
|
+
// skip as it's covered by the key
|
|
3282
3334
|
} else if (node.kind === 'get') {
|
|
3283
3335
|
parts.push('get ');
|
|
3284
|
-
parts.push(path.call(print, 'key'));
|
|
3285
3336
|
} else if (node.kind === 'set') {
|
|
3286
3337
|
parts.push('set ');
|
|
3287
|
-
parts.push(path.call(print, 'key'));
|
|
3288
|
-
} else {
|
|
3289
|
-
parts.push(path.call(print, 'key'));
|
|
3290
3338
|
}
|
|
3291
3339
|
|
|
3340
|
+
// Async keyword
|
|
3341
|
+
if (node.value && node.value.async) {
|
|
3342
|
+
parts.push('async ');
|
|
3343
|
+
}
|
|
3344
|
+
|
|
3345
|
+
if (node.value.generator) {
|
|
3346
|
+
parts.push('*');
|
|
3347
|
+
}
|
|
3348
|
+
|
|
3349
|
+
if (is_component) {
|
|
3350
|
+
if (node.value.id) {
|
|
3351
|
+
// takes care of component methods
|
|
3352
|
+
parts.push(path.call(print, 'value'));
|
|
3353
|
+
return concat(parts);
|
|
3354
|
+
}
|
|
3355
|
+
|
|
3356
|
+
parts.push('component ');
|
|
3357
|
+
}
|
|
3358
|
+
|
|
3359
|
+
// the key is 'constructor' and we already handled that above
|
|
3360
|
+
parts.push(...printKey(node, path, options, print));
|
|
3361
|
+
|
|
3292
3362
|
// Add TypeScript generics if present (always on the method node, not on value)
|
|
3293
3363
|
if (node.typeParameters) {
|
|
3294
3364
|
const typeParams = path.call(print, 'typeParameters');
|
|
@@ -3299,6 +3369,13 @@ function printMethodDefinition(node, path, options, print) {
|
|
|
3299
3369
|
}
|
|
3300
3370
|
}
|
|
3301
3371
|
|
|
3372
|
+
if (is_component) {
|
|
3373
|
+
parts.push(
|
|
3374
|
+
...path.call((childPath) => print(childPath, { skipComponentLabel: true }), 'value'),
|
|
3375
|
+
);
|
|
3376
|
+
return concat(parts);
|
|
3377
|
+
}
|
|
3378
|
+
|
|
3302
3379
|
// Parameters - use proper path.map for TypeScript support
|
|
3303
3380
|
parts.push('(');
|
|
3304
3381
|
if (node.value && node.value.params && node.value.params.length > 0) {
|
|
@@ -3960,7 +4037,7 @@ function printProperty(node, path, options, print) {
|
|
|
3960
4037
|
return path.call(print, 'key');
|
|
3961
4038
|
}
|
|
3962
4039
|
|
|
3963
|
-
const
|
|
4040
|
+
const is_component = node.value?.type === 'Component';
|
|
3964
4041
|
|
|
3965
4042
|
// Handle getter/setter methods
|
|
3966
4043
|
if (node.kind === 'get' || node.kind === 'set') {
|
|
@@ -3970,20 +4047,7 @@ function printProperty(node, path, options, print) {
|
|
|
3970
4047
|
// Add get/set keyword
|
|
3971
4048
|
methodParts.push(node.kind, ' ');
|
|
3972
4049
|
|
|
3973
|
-
|
|
3974
|
-
if (node.computed) {
|
|
3975
|
-
methodParts.push('[', path.call(print, 'key'), ']');
|
|
3976
|
-
} else if (node.key.type === 'Literal' && typeof node.key.value === 'string') {
|
|
3977
|
-
const key = node.key.value;
|
|
3978
|
-
const isValidIdentifier = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(key);
|
|
3979
|
-
if (isValidIdentifier) {
|
|
3980
|
-
methodParts.push(key);
|
|
3981
|
-
} else {
|
|
3982
|
-
methodParts.push(formatStringLiteral(key, options));
|
|
3983
|
-
}
|
|
3984
|
-
} else {
|
|
3985
|
-
methodParts.push(path.call(print, 'key'));
|
|
3986
|
-
}
|
|
4050
|
+
methodParts.push(...printKey(node, path, options, print));
|
|
3987
4051
|
|
|
3988
4052
|
// Print parameters by calling into the value path
|
|
3989
4053
|
const paramsPart = path.call(
|
|
@@ -4002,7 +4066,7 @@ function printProperty(node, path, options, print) {
|
|
|
4002
4066
|
}
|
|
4003
4067
|
|
|
4004
4068
|
// Handle method shorthand: increment() {} instead of increment: function() {}
|
|
4005
|
-
if (node.method && node.value.type === 'FunctionExpression') {
|
|
4069
|
+
if (node.method && (node.value.type === 'FunctionExpression' || is_component)) {
|
|
4006
4070
|
const methodParts = [];
|
|
4007
4071
|
const funcValue = node.value;
|
|
4008
4072
|
|
|
@@ -4011,26 +4075,23 @@ function printProperty(node, path, options, print) {
|
|
|
4011
4075
|
methodParts.push('async ');
|
|
4012
4076
|
}
|
|
4013
4077
|
|
|
4014
|
-
|
|
4015
|
-
|
|
4016
|
-
methodParts.push('[', path.call(print, 'key'), ']');
|
|
4017
|
-
} else if (node.key.type === 'Literal' && typeof node.key.value === 'string') {
|
|
4018
|
-
// Check if the key is a valid identifier that doesn't need quotes
|
|
4019
|
-
const key = node.key.value;
|
|
4020
|
-
const isValidIdentifier = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(key);
|
|
4021
|
-
if (isValidIdentifier) {
|
|
4022
|
-
methodParts.push(key);
|
|
4023
|
-
} else {
|
|
4024
|
-
methodParts.push(formatStringLiteral(key, options));
|
|
4025
|
-
}
|
|
4026
|
-
} else {
|
|
4027
|
-
methodParts.push(path.call(print, 'key'));
|
|
4078
|
+
if (is_component) {
|
|
4079
|
+
methodParts.push('component ');
|
|
4028
4080
|
}
|
|
4029
4081
|
|
|
4030
4082
|
if (funcValue.generator) {
|
|
4031
4083
|
methodParts.push('*');
|
|
4032
4084
|
}
|
|
4033
4085
|
|
|
4086
|
+
methodParts.push(...printKey(node, path, options, print));
|
|
4087
|
+
|
|
4088
|
+
if (is_component) {
|
|
4089
|
+
methodParts.push(
|
|
4090
|
+
path.call((childPath) => print(childPath, { skipComponentLabel: true }), 'value'),
|
|
4091
|
+
);
|
|
4092
|
+
return concat(methodParts);
|
|
4093
|
+
}
|
|
4094
|
+
|
|
4034
4095
|
// Print parameters by calling into the value path
|
|
4035
4096
|
const paramsPart = path.call(
|
|
4036
4097
|
(valuePath) => printFunctionParameters(valuePath, options, print),
|
|
@@ -4047,27 +4108,8 @@ function printProperty(node, path, options, print) {
|
|
|
4047
4108
|
return concat(methodParts);
|
|
4048
4109
|
}
|
|
4049
4110
|
|
|
4050
|
-
|
|
4051
|
-
|
|
4052
|
-
if (node.computed) {
|
|
4053
|
-
// Computed property: [key]
|
|
4054
|
-
parts.push('[', path.call(print, 'key'), ']');
|
|
4055
|
-
} else if (node.key.type === 'Literal' && typeof node.key.value === 'string') {
|
|
4056
|
-
// Check if the key is a valid identifier that doesn't need quotes
|
|
4057
|
-
const key = node.key.value;
|
|
4058
|
-
const isValidIdentifier = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(key);
|
|
4059
|
-
|
|
4060
|
-
if (isValidIdentifier) {
|
|
4061
|
-
// Don't quote valid identifiers
|
|
4062
|
-
parts.push(key);
|
|
4063
|
-
} else {
|
|
4064
|
-
// Quote keys that need it (e.g., contain special characters)
|
|
4065
|
-
parts.push(formatStringLiteral(key, options));
|
|
4066
|
-
}
|
|
4067
|
-
} else {
|
|
4068
|
-
// For non-literal keys, print normally
|
|
4069
|
-
parts.push(path.call(print, 'key'));
|
|
4070
|
-
}
|
|
4111
|
+
const parts = [];
|
|
4112
|
+
parts.push(...printKey(node, path, options, print));
|
|
4071
4113
|
|
|
4072
4114
|
parts.push(': ');
|
|
4073
4115
|
parts.push(path.call(print, 'value'));
|
package/src/index.test.js
CHANGED
|
@@ -1781,6 +1781,116 @@ files = [...(files ?? []), ...dt.files];`;
|
|
|
1781
1781
|
const result = await format(expected, { singleQuote: true, printWidth: 100 });
|
|
1782
1782
|
expect(result).toBeWithNewline(expected);
|
|
1783
1783
|
});
|
|
1784
|
+
|
|
1785
|
+
it('should preserve class component method', async () => {
|
|
1786
|
+
const expected = `class TestClass {
|
|
1787
|
+
component something() {
|
|
1788
|
+
<div>{'Nested component'}</div>
|
|
1789
|
+
}
|
|
1790
|
+
}`;
|
|
1791
|
+
|
|
1792
|
+
const result = await format(expected, { singleQuote: true, printWidth: 100 });
|
|
1793
|
+
expect(result).toBeWithNewline(expected);
|
|
1794
|
+
});
|
|
1795
|
+
|
|
1796
|
+
it('should preserve class computed method', async () => {
|
|
1797
|
+
const expected = `class TestClass {
|
|
1798
|
+
['something']() {
|
|
1799
|
+
const i = 10;
|
|
1800
|
+
}
|
|
1801
|
+
}`;
|
|
1802
|
+
|
|
1803
|
+
const result = await format(expected, { singleQuote: true, printWidth: 100 });
|
|
1804
|
+
expect(result).toBeWithNewline(expected);
|
|
1805
|
+
});
|
|
1806
|
+
|
|
1807
|
+
it('should preserve class computed component method', async () => {
|
|
1808
|
+
const expected = `class TestClass {
|
|
1809
|
+
component ['something']() {
|
|
1810
|
+
<div>{'Nested component'}</div>
|
|
1811
|
+
}
|
|
1812
|
+
}`;
|
|
1813
|
+
|
|
1814
|
+
const result = await format(expected, { singleQuote: true, printWidth: 100 });
|
|
1815
|
+
expect(result).toBeWithNewline(expected);
|
|
1816
|
+
});
|
|
1817
|
+
|
|
1818
|
+
it('should format class with a literal component method', async () => {
|
|
1819
|
+
const input = `class TestClass {
|
|
1820
|
+
component 'something'() {
|
|
1821
|
+
<div>{'Nested component'}</div>
|
|
1822
|
+
}
|
|
1823
|
+
}`;
|
|
1824
|
+
|
|
1825
|
+
const expected = `class TestClass {
|
|
1826
|
+
component something() {
|
|
1827
|
+
<div>{'Nested component'}</div>
|
|
1828
|
+
}
|
|
1829
|
+
}`;
|
|
1830
|
+
|
|
1831
|
+
const result = await format(input, { singleQuote: true, printWidth: 100 });
|
|
1832
|
+
expect(result).toBeWithNewline(expected);
|
|
1833
|
+
});
|
|
1834
|
+
|
|
1835
|
+
it('should preserve object component methods', async () => {
|
|
1836
|
+
const expected = `const obj = {
|
|
1837
|
+
component something() {
|
|
1838
|
+
<div>{'Nested component'}</div>
|
|
1839
|
+
},
|
|
1840
|
+
};`;
|
|
1841
|
+
|
|
1842
|
+
const result = await format(expected, { singleQuote: true, printWidth: 100 });
|
|
1843
|
+
expect(result).toBeWithNewline(expected);
|
|
1844
|
+
});
|
|
1845
|
+
|
|
1846
|
+
it('should preserve object computed methods', async () => {
|
|
1847
|
+
const expected = `const obj = {
|
|
1848
|
+
['something']() {
|
|
1849
|
+
const i = 10;
|
|
1850
|
+
},
|
|
1851
|
+
};`;
|
|
1852
|
+
|
|
1853
|
+
const result = await format(expected, { singleQuote: true, printWidth: 100 });
|
|
1854
|
+
expect(result).toBeWithNewline(expected);
|
|
1855
|
+
});
|
|
1856
|
+
|
|
1857
|
+
it('should preserve object computed component method', async () => {
|
|
1858
|
+
const expected = `const obj = {
|
|
1859
|
+
component ['something']() {
|
|
1860
|
+
<div>{'Nested component'}</div>
|
|
1861
|
+
},
|
|
1862
|
+
};`;
|
|
1863
|
+
|
|
1864
|
+
const result = await format(expected, { singleQuote: true, printWidth: 100 });
|
|
1865
|
+
expect(result).toBeWithNewline(expected);
|
|
1866
|
+
});
|
|
1867
|
+
|
|
1868
|
+
it('should format object with a literal component method', async () => {
|
|
1869
|
+
const input = `const obj = {
|
|
1870
|
+
component 'something'() {
|
|
1871
|
+
<div>{'Nested component'}</div>
|
|
1872
|
+
},
|
|
1873
|
+
};`;
|
|
1874
|
+
const expected = `const obj = {
|
|
1875
|
+
component something() {
|
|
1876
|
+
<div>{'Nested component'}</div>
|
|
1877
|
+
},
|
|
1878
|
+
};`;
|
|
1879
|
+
|
|
1880
|
+
const result = await format(input, { singleQuote: true, printWidth: 100 });
|
|
1881
|
+
expect(result).toBeWithNewline(expected);
|
|
1882
|
+
});
|
|
1883
|
+
|
|
1884
|
+
it('should print class constructor method only once', async () => {
|
|
1885
|
+
const expected = `class TestClass {
|
|
1886
|
+
constructor(value: T) {
|
|
1887
|
+
this.value = value;
|
|
1888
|
+
}
|
|
1889
|
+
}`;
|
|
1890
|
+
|
|
1891
|
+
const result = await format(expected, { singleQuote: true, printWidth: 100 });
|
|
1892
|
+
expect(result).toBeWithNewline(expected);
|
|
1893
|
+
});
|
|
1784
1894
|
});
|
|
1785
1895
|
|
|
1786
1896
|
describe('edge cases', () => {
|
|
@@ -2110,6 +2220,21 @@ const obj2 = #{
|
|
|
2110
2220
|
expect(result).toBeWithNewline(expected);
|
|
2111
2221
|
});
|
|
2112
2222
|
|
|
2223
|
+
it('should not add an extra new line above a comment inside objects and in between properties', async () => {
|
|
2224
|
+
const expected = `let obj = {
|
|
2225
|
+
['hey']: function () {
|
|
2226
|
+
const i = 'yo';
|
|
2227
|
+
},
|
|
2228
|
+
// <div>{'Weird name component'}</div>
|
|
2229
|
+
normal() {
|
|
2230
|
+
const b = 'hey';
|
|
2231
|
+
},
|
|
2232
|
+
};`;
|
|
2233
|
+
|
|
2234
|
+
const result = await format(expected, { singleQuote: true });
|
|
2235
|
+
expect(result).toBeWithNewline(expected);
|
|
2236
|
+
});
|
|
2237
|
+
|
|
2113
2238
|
it('should preserve comment if the whole component code is commented out', async () => {
|
|
2114
2239
|
const expected = `export component Test() {
|
|
2115
2240
|
// thing
|
|
@@ -2939,6 +3064,10 @@ try {
|
|
|
2939
3064
|
{
|
|
2940
3065
|
"id": "toast:6",
|
|
2941
3066
|
"stacked": false,
|
|
3067
|
+
},
|
|
3068
|
+
{
|
|
3069
|
+
["id"]: "toast:6",
|
|
3070
|
+
["stacked"]: false,
|
|
2942
3071
|
}
|
|
2943
3072
|
];`;
|
|
2944
3073
|
|
|
@@ -2963,6 +3092,10 @@ try {
|
|
|
2963
3092
|
id: 'toast:6',
|
|
2964
3093
|
stacked: false,
|
|
2965
3094
|
},
|
|
3095
|
+
{
|
|
3096
|
+
['id']: 'toast:6',
|
|
3097
|
+
['stacked']: false,
|
|
3098
|
+
},
|
|
2966
3099
|
];`;
|
|
2967
3100
|
|
|
2968
3101
|
const result = await format(input, { singleQuote: true, arrowParens: 'always' });
|