@ripple-ts/prettier-plugin 0.2.168 → 0.2.170
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 +43 -274
- package/src/index.test.js +53 -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.170",
|
|
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.170"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {},
|
|
31
31
|
"files": [
|
package/src/index.js
CHANGED
|
@@ -21,11 +21,6 @@ const {
|
|
|
21
21
|
} = builders;
|
|
22
22
|
const { willBreak } = utils;
|
|
23
23
|
|
|
24
|
-
// Embed function - not needed for now
|
|
25
|
-
export function embed(path, options) {
|
|
26
|
-
return null;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
24
|
export const languages = [
|
|
30
25
|
{
|
|
31
26
|
name: 'ripple',
|
|
@@ -39,8 +34,7 @@ export const parsers = {
|
|
|
39
34
|
ripple: {
|
|
40
35
|
astFormat: 'ripple-ast',
|
|
41
36
|
parse(text, parsers, options) {
|
|
42
|
-
|
|
43
|
-
return ast;
|
|
37
|
+
return parse(text);
|
|
44
38
|
},
|
|
45
39
|
|
|
46
40
|
locStart(node) {
|
|
@@ -66,11 +60,50 @@ export const printers = {
|
|
|
66
60
|
}
|
|
67
61
|
return typeof parts === 'string' ? parts : parts;
|
|
68
62
|
},
|
|
63
|
+
embed(path, options) {
|
|
64
|
+
const node = path.getValue();
|
|
65
|
+
|
|
66
|
+
// Handle StyleSheet nodes inside style tags
|
|
67
|
+
if (node.type === 'StyleSheet' && node.source) {
|
|
68
|
+
// Return async function that will be called by Prettier
|
|
69
|
+
return async (textToDoc) => {
|
|
70
|
+
try {
|
|
71
|
+
// Format CSS using Prettier's textToDoc
|
|
72
|
+
const body = await textToDoc(node.source, {
|
|
73
|
+
parser: 'css',
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
// Return the formatted CSS
|
|
77
|
+
// Note: printElement will wrap this in indent(), so we don't add indent here
|
|
78
|
+
return body;
|
|
79
|
+
} catch (error) {
|
|
80
|
+
// If CSS has syntax errors, return original unformatted content
|
|
81
|
+
console.error('Error formatting CSS:', error);
|
|
82
|
+
return node.source;
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return null;
|
|
88
|
+
},
|
|
69
89
|
getVisitorKeys(node) {
|
|
90
|
+
// Exclude metadata and raw text properties that shouldn't be traversed
|
|
91
|
+
// The css property is specifically excluded so embed() can handle it
|
|
92
|
+
const excludedKeys = new Set([
|
|
93
|
+
'start',
|
|
94
|
+
'end',
|
|
95
|
+
'loc',
|
|
96
|
+
'metadata',
|
|
97
|
+
'css', // Handled by embed()
|
|
98
|
+
'raw',
|
|
99
|
+
'regex',
|
|
100
|
+
]);
|
|
101
|
+
|
|
70
102
|
const keys = Object.keys(node).filter((key) => {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
103
|
+
if (excludedKeys.has(key)) {
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
return typeof node[key] === 'object' && node[key] !== null;
|
|
74
107
|
});
|
|
75
108
|
|
|
76
109
|
return keys;
|
|
@@ -1923,61 +1956,6 @@ function printRippleNode(node, path, options, print, args) {
|
|
|
1923
1956
|
}
|
|
1924
1957
|
break;
|
|
1925
1958
|
|
|
1926
|
-
case 'StyleSheet':
|
|
1927
|
-
nodeContent = printStyleSheet(node, path, options, print);
|
|
1928
|
-
break;
|
|
1929
|
-
case 'Rule':
|
|
1930
|
-
nodeContent = printCSSRule(node, path, options, print);
|
|
1931
|
-
break;
|
|
1932
|
-
|
|
1933
|
-
case 'Declaration':
|
|
1934
|
-
nodeContent = printCSSDeclaration(node, path, options, print);
|
|
1935
|
-
break;
|
|
1936
|
-
|
|
1937
|
-
case 'Atrule':
|
|
1938
|
-
nodeContent = printCSSAtrule(node, path, options, print);
|
|
1939
|
-
break;
|
|
1940
|
-
|
|
1941
|
-
case 'SelectorList':
|
|
1942
|
-
nodeContent = printCSSSelectorList(node, path, options, print);
|
|
1943
|
-
break;
|
|
1944
|
-
|
|
1945
|
-
case 'ComplexSelector':
|
|
1946
|
-
nodeContent = printCSSComplexSelector(node, path, options, print);
|
|
1947
|
-
break;
|
|
1948
|
-
|
|
1949
|
-
case 'RelativeSelector':
|
|
1950
|
-
nodeContent = printCSSRelativeSelector(node, path, options, print);
|
|
1951
|
-
break;
|
|
1952
|
-
|
|
1953
|
-
case 'TypeSelector':
|
|
1954
|
-
nodeContent = printCSSTypeSelector(node, path, options, print);
|
|
1955
|
-
break;
|
|
1956
|
-
|
|
1957
|
-
case 'IdSelector':
|
|
1958
|
-
nodeContent = printCSSIdSelector(node, path, options, print);
|
|
1959
|
-
break;
|
|
1960
|
-
|
|
1961
|
-
case 'ClassSelector':
|
|
1962
|
-
nodeContent = printCSSClassSelector(node, path, options, print);
|
|
1963
|
-
break;
|
|
1964
|
-
|
|
1965
|
-
case 'NestingSelector':
|
|
1966
|
-
nodeContent = printCSSNestingSelector(node, path, options, print);
|
|
1967
|
-
break;
|
|
1968
|
-
|
|
1969
|
-
case 'PseudoClassSelector':
|
|
1970
|
-
nodeContent = printCSSPseudoClassSelector(node, path, options, print);
|
|
1971
|
-
break;
|
|
1972
|
-
|
|
1973
|
-
case 'PseudoElementSelector':
|
|
1974
|
-
nodeContent = printCSSPseudoElementSelector(node, path, options, print);
|
|
1975
|
-
break;
|
|
1976
|
-
|
|
1977
|
-
case 'Block':
|
|
1978
|
-
nodeContent = printCSSBlock(node, path, options, print);
|
|
1979
|
-
break;
|
|
1980
|
-
|
|
1981
1959
|
case 'Attribute':
|
|
1982
1960
|
nodeContent = printAttribute(node, path, options, print);
|
|
1983
1961
|
break;
|
|
@@ -4319,215 +4297,6 @@ function printTSIndexedAccessType(node, path, options, print) {
|
|
|
4319
4297
|
return concat([path.call(print, 'objectType'), '[', path.call(print, 'indexType'), ']']);
|
|
4320
4298
|
}
|
|
4321
4299
|
|
|
4322
|
-
function printStyleSheet(node, path, options, print) {
|
|
4323
|
-
// StyleSheet contains CSS rules in the 'body' property
|
|
4324
|
-
if (node.body && node.body.length > 0) {
|
|
4325
|
-
const cssItems = [];
|
|
4326
|
-
|
|
4327
|
-
// Process each item in the stylesheet body
|
|
4328
|
-
for (let i = 0; i < node.body.length; i++) {
|
|
4329
|
-
const item = path.call(print, 'body', i);
|
|
4330
|
-
if (item) {
|
|
4331
|
-
cssItems.push(item);
|
|
4332
|
-
}
|
|
4333
|
-
}
|
|
4334
|
-
|
|
4335
|
-
// Structure the CSS with proper indentation and spacing
|
|
4336
|
-
// Check for blank lines between CSS items and preserve them
|
|
4337
|
-
const result = [];
|
|
4338
|
-
for (let i = 0; i < cssItems.length; i++) {
|
|
4339
|
-
result.push(cssItems[i]);
|
|
4340
|
-
if (i < cssItems.length - 1) {
|
|
4341
|
-
// Check if there are blank lines between current and next item
|
|
4342
|
-
const currentItem = node.body[i];
|
|
4343
|
-
const nextItem = node.body[i + 1];
|
|
4344
|
-
|
|
4345
|
-
// Check for blank lines in the original CSS source between rules
|
|
4346
|
-
let hasBlankLine = false;
|
|
4347
|
-
if (
|
|
4348
|
-
node.source &&
|
|
4349
|
-
typeof currentItem.end === 'number' &&
|
|
4350
|
-
typeof nextItem.start === 'number'
|
|
4351
|
-
) {
|
|
4352
|
-
const textBetween = node.source.substring(currentItem.end, nextItem.start);
|
|
4353
|
-
// Count newlines in the text between the rules
|
|
4354
|
-
const newlineCount = (textBetween.match(/\n/g) || []).length;
|
|
4355
|
-
// If there are 2 or more newlines, there's at least one blank line
|
|
4356
|
-
hasBlankLine = newlineCount >= 2;
|
|
4357
|
-
}
|
|
4358
|
-
if (hasBlankLine) {
|
|
4359
|
-
// If there are blank lines, add an extra hardline (to create a blank line)
|
|
4360
|
-
result.push(hardline, hardline);
|
|
4361
|
-
} else {
|
|
4362
|
-
result.push(hardline);
|
|
4363
|
-
}
|
|
4364
|
-
}
|
|
4365
|
-
}
|
|
4366
|
-
|
|
4367
|
-
return concat(result);
|
|
4368
|
-
}
|
|
4369
|
-
|
|
4370
|
-
// If no body, return empty string
|
|
4371
|
-
return '';
|
|
4372
|
-
}
|
|
4373
|
-
|
|
4374
|
-
function printCSSRule(node, path, options, print) {
|
|
4375
|
-
// CSS Rule has prelude (selector) and block (declarations)
|
|
4376
|
-
const selector = path.call(print, 'prelude');
|
|
4377
|
-
const block = path.call(print, 'block');
|
|
4378
|
-
|
|
4379
|
-
return group([selector, ' {', indent([hardline, block]), hardline, '}']);
|
|
4380
|
-
}
|
|
4381
|
-
|
|
4382
|
-
function printCSSDeclaration(node, path, options, print) {
|
|
4383
|
-
// CSS Declaration has property and value
|
|
4384
|
-
const parts = [node.property];
|
|
4385
|
-
|
|
4386
|
-
if (node.value) {
|
|
4387
|
-
parts.push(': ');
|
|
4388
|
-
const value = path.call(print, 'value');
|
|
4389
|
-
parts.push(value);
|
|
4390
|
-
}
|
|
4391
|
-
|
|
4392
|
-
parts.push(';');
|
|
4393
|
-
return concat(parts);
|
|
4394
|
-
}
|
|
4395
|
-
|
|
4396
|
-
function printCSSAtrule(node, path, options, print) {
|
|
4397
|
-
// CSS At-rule like @media, @keyframes, etc.
|
|
4398
|
-
const parts = ['@', node.name];
|
|
4399
|
-
|
|
4400
|
-
if (node.prelude) {
|
|
4401
|
-
parts.push(' ');
|
|
4402
|
-
const prelude = path.call(print, 'prelude');
|
|
4403
|
-
parts.push(prelude);
|
|
4404
|
-
}
|
|
4405
|
-
|
|
4406
|
-
if (node.block) {
|
|
4407
|
-
const block = path.call(print, 'block');
|
|
4408
|
-
parts.push(' {');
|
|
4409
|
-
parts.push(indent([hardline, block]));
|
|
4410
|
-
parts.push(hardline, '}');
|
|
4411
|
-
} else {
|
|
4412
|
-
parts.push(';');
|
|
4413
|
-
}
|
|
4414
|
-
|
|
4415
|
-
return group(parts);
|
|
4416
|
-
}
|
|
4417
|
-
|
|
4418
|
-
function printCSSSelectorList(node, path, options, print) {
|
|
4419
|
-
// SelectorList contains multiple selectors
|
|
4420
|
-
if (node.children && node.children.length > 0) {
|
|
4421
|
-
const selectors = [];
|
|
4422
|
-
for (let i = 0; i < node.children.length; i++) {
|
|
4423
|
-
const selector = path.call(print, 'children', i);
|
|
4424
|
-
selectors.push(selector);
|
|
4425
|
-
}
|
|
4426
|
-
// Join selectors with comma and line break for proper CSS formatting
|
|
4427
|
-
return join([',', hardline], selectors);
|
|
4428
|
-
}
|
|
4429
|
-
return '';
|
|
4430
|
-
}
|
|
4431
|
-
|
|
4432
|
-
function printCSSComplexSelector(node, path, options, print) {
|
|
4433
|
-
// ComplexSelector contains selector components
|
|
4434
|
-
if (node.children && node.children.length > 0) {
|
|
4435
|
-
const selectorParts = [];
|
|
4436
|
-
for (let i = 0; i < node.children.length; i++) {
|
|
4437
|
-
const part = path.call(print, 'children', i);
|
|
4438
|
-
selectorParts.push(part);
|
|
4439
|
-
}
|
|
4440
|
-
return concat(selectorParts);
|
|
4441
|
-
}
|
|
4442
|
-
return '';
|
|
4443
|
-
}
|
|
4444
|
-
|
|
4445
|
-
function printCSSRelativeSelector(node, path, options, print) {
|
|
4446
|
-
// RelativeSelector contains selector components in the 'selectors' property
|
|
4447
|
-
const parts = [];
|
|
4448
|
-
|
|
4449
|
-
// Print combinator if it exists (e.g., +, >, ~, or space)
|
|
4450
|
-
if (node.combinator) {
|
|
4451
|
-
if (node.combinator.name === ' ') {
|
|
4452
|
-
// Space combinator (descendant selector)
|
|
4453
|
-
parts.push(' ');
|
|
4454
|
-
} else {
|
|
4455
|
-
// Other combinators (+, >, ~)
|
|
4456
|
-
parts.push(' ', node.combinator.name, ' ');
|
|
4457
|
-
}
|
|
4458
|
-
}
|
|
4459
|
-
|
|
4460
|
-
if (node.selectors && node.selectors.length > 0) {
|
|
4461
|
-
const selectorParts = [];
|
|
4462
|
-
for (let i = 0; i < node.selectors.length; i++) {
|
|
4463
|
-
const part = path.call(print, 'selectors', i);
|
|
4464
|
-
selectorParts.push(part);
|
|
4465
|
-
}
|
|
4466
|
-
parts.push(...selectorParts);
|
|
4467
|
-
}
|
|
4468
|
-
|
|
4469
|
-
return concat(parts);
|
|
4470
|
-
}
|
|
4471
|
-
|
|
4472
|
-
function printCSSTypeSelector(node, path, options, print) {
|
|
4473
|
-
// TypeSelector for element names like 'div', 'body', 'p', etc.
|
|
4474
|
-
return node.name || '';
|
|
4475
|
-
}
|
|
4476
|
-
|
|
4477
|
-
function printCSSIdSelector(node, path, options, print) {
|
|
4478
|
-
// IdSelector for #id
|
|
4479
|
-
return concat(['#', node.name || '']);
|
|
4480
|
-
}
|
|
4481
|
-
|
|
4482
|
-
function printCSSClassSelector(node, path, options, print) {
|
|
4483
|
-
// ClassSelector for .class
|
|
4484
|
-
return concat(['.', node.name || '']);
|
|
4485
|
-
}
|
|
4486
|
-
|
|
4487
|
-
function printCSSNestingSelector(node, path, options, print) {
|
|
4488
|
-
// NestingSelector for & (parent reference in nested CSS)
|
|
4489
|
-
return '&';
|
|
4490
|
-
}
|
|
4491
|
-
|
|
4492
|
-
function printCSSPseudoClassSelector(node, path, options, print) {
|
|
4493
|
-
// PseudoClassSelector for :hover, :global(), etc.
|
|
4494
|
-
const parts = [':', node.name || ''];
|
|
4495
|
-
|
|
4496
|
-
// If it has args (like :global(.classname)), print them
|
|
4497
|
-
if (node.args !== null && node.args !== undefined) {
|
|
4498
|
-
parts.push('(', node.args, ')');
|
|
4499
|
-
}
|
|
4500
|
-
|
|
4501
|
-
return concat(parts);
|
|
4502
|
-
}
|
|
4503
|
-
|
|
4504
|
-
function printCSSPseudoElementSelector(node, path, options, print) {
|
|
4505
|
-
// PseudoElementSelector for ::before, ::after, etc.
|
|
4506
|
-
const parts = ['::', node.name || ''];
|
|
4507
|
-
|
|
4508
|
-
// If it has args (like ::slotted(span)), print them
|
|
4509
|
-
if (node.args !== null && node.args !== undefined) {
|
|
4510
|
-
parts.push('(', node.args, ')');
|
|
4511
|
-
}
|
|
4512
|
-
|
|
4513
|
-
return concat(parts);
|
|
4514
|
-
}
|
|
4515
|
-
|
|
4516
|
-
function printCSSBlock(node, path, options, print) {
|
|
4517
|
-
// CSS Block contains declarations
|
|
4518
|
-
if (node.children && node.children.length > 0) {
|
|
4519
|
-
const declarations = [];
|
|
4520
|
-
for (let i = 0; i < node.children.length; i++) {
|
|
4521
|
-
const decl = path.call(print, 'children', i);
|
|
4522
|
-
if (decl) {
|
|
4523
|
-
declarations.push(decl);
|
|
4524
|
-
}
|
|
4525
|
-
}
|
|
4526
|
-
return join(hardline, declarations);
|
|
4527
|
-
}
|
|
4528
|
-
return '';
|
|
4529
|
-
}
|
|
4530
|
-
|
|
4531
4300
|
function shouldInlineSingleChild(parentNode, firstChild, childDoc) {
|
|
4532
4301
|
if (!firstChild || childDoc == null) {
|
|
4533
4302
|
return false;
|
package/src/index.test.js
CHANGED
|
@@ -1135,6 +1135,59 @@ const [obj1, obj2] = arrayOfObjects;`;
|
|
|
1135
1135
|
expect(result).toBeWithNewline(expected);
|
|
1136
1136
|
});
|
|
1137
1137
|
|
|
1138
|
+
it('should keep css @keyframes syntax intact', async () => {
|
|
1139
|
+
const input = `export component App() {
|
|
1140
|
+
<style>
|
|
1141
|
+
/* Scoped keyframe - only usable within Parent */
|
|
1142
|
+
@keyframes slideIn {
|
|
1143
|
+
from { transform: translateX(-100%); }
|
|
1144
|
+
to { transform: translateX(0); }
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
/* Global keyframe - usable in any component */
|
|
1148
|
+
@keyframes -global-fadeIn {
|
|
1149
|
+
0% { opacity: 0; }
|
|
1150
|
+
100% { opacity: 1; }
|
|
1151
|
+
}
|
|
1152
|
+
|
|
1153
|
+
.parent {
|
|
1154
|
+
animation: slideIn 1s;
|
|
1155
|
+
}
|
|
1156
|
+
</style>
|
|
1157
|
+
}`;
|
|
1158
|
+
|
|
1159
|
+
const expected = `export component App() {
|
|
1160
|
+
<style>
|
|
1161
|
+
/* Scoped keyframe - only usable within Parent */
|
|
1162
|
+
@keyframes slideIn {
|
|
1163
|
+
from {
|
|
1164
|
+
transform: translateX(-100%);
|
|
1165
|
+
}
|
|
1166
|
+
to {
|
|
1167
|
+
transform: translateX(0);
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1171
|
+
/* Global keyframe - usable in any component */
|
|
1172
|
+
@keyframes -global-fadeIn {
|
|
1173
|
+
0% {
|
|
1174
|
+
opacity: 0;
|
|
1175
|
+
}
|
|
1176
|
+
100% {
|
|
1177
|
+
opacity: 1;
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
1180
|
+
|
|
1181
|
+
.parent {
|
|
1182
|
+
animation: slideIn 1s;
|
|
1183
|
+
}
|
|
1184
|
+
</style>
|
|
1185
|
+
}`;
|
|
1186
|
+
|
|
1187
|
+
const result = await format(input, { singleQuote: true, printWidth: 100 });
|
|
1188
|
+
expect(result).toBeWithNewline(expected);
|
|
1189
|
+
});
|
|
1190
|
+
|
|
1138
1191
|
it('should keep TrackedMap short syntax intact', async () => {
|
|
1139
1192
|
const expected = `const map = new #Map([['key1', 'value1'], ['key2', 'value2']]);
|
|
1140
1193
|
const set = new #Set([1, 2, 3]);`;
|