prettier-plugin-astro 1.0.0-beta.0 → 1.0.0-beta.2
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/dist/index.js +384 -66
- package/dist/index.js.map +1 -1
- package/package.json +45 -40
package/dist/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { parse as parse$1 } from '@astrojs/compiler-rs';
|
|
2
|
+
import parseSrcset from '@prettier/parse-srcset';
|
|
2
3
|
import { doc } from 'prettier';
|
|
3
4
|
import { printers as printers$1 } from 'prettier/plugins/estree';
|
|
4
5
|
import { SassFormatter } from 'sass-formatter';
|
|
@@ -53,6 +54,15 @@ function tagNameOf(node) {
|
|
|
53
54
|
const name = node.openingElement?.name;
|
|
54
55
|
return name?.type === 'JSXIdentifier' ? name.name : null;
|
|
55
56
|
}
|
|
57
|
+
function jsxNameOf(name) {
|
|
58
|
+
if (name.type === 'JSXIdentifier')
|
|
59
|
+
return name.name;
|
|
60
|
+
if (name.type !== 'JSXMemberExpression')
|
|
61
|
+
return null;
|
|
62
|
+
const object = jsxNameOf(name.object);
|
|
63
|
+
const property = jsxNameOf(name.property);
|
|
64
|
+
return object !== null && property !== null ? `${object}.${property}` : null;
|
|
65
|
+
}
|
|
56
66
|
const isComponentName = (name) => name === null || /^[A-Z]/.test(name) || name.includes('.');
|
|
57
67
|
function attributesOf(node) {
|
|
58
68
|
const opening = node.openingElement;
|
|
@@ -242,19 +252,20 @@ function isInlineDisplay(display) {
|
|
|
242
252
|
return inlineLevel.has(display);
|
|
243
253
|
}
|
|
244
254
|
|
|
255
|
+
const { group: group$3, ifBreak, indent: indent$3, join: join$1, line: line$2, softline: softline$3 } = doc.builders;
|
|
245
256
|
function manualDedent(input) {
|
|
246
257
|
let minTabSize = Infinity;
|
|
247
258
|
let result = input;
|
|
248
259
|
result = result.replace(/\r\n/g, '\n');
|
|
249
260
|
let char = '';
|
|
250
|
-
for (const
|
|
251
|
-
if (!
|
|
261
|
+
for (const row of result.split('\n')) {
|
|
262
|
+
if (!row)
|
|
252
263
|
continue;
|
|
253
|
-
if (
|
|
264
|
+
if (row[0] && /^\S/.test(row[0])) {
|
|
254
265
|
minTabSize = 0;
|
|
255
266
|
break;
|
|
256
267
|
}
|
|
257
|
-
const match = /^(\s+)\S+/.exec(
|
|
268
|
+
const match = /^(\s+)\S+/.exec(row);
|
|
258
269
|
if (match) {
|
|
259
270
|
if (match[1] && !char)
|
|
260
271
|
char = match[1][0];
|
|
@@ -271,11 +282,39 @@ function manualDedent(input) {
|
|
|
271
282
|
result,
|
|
272
283
|
};
|
|
273
284
|
}
|
|
285
|
+
function printSrcset(value) {
|
|
286
|
+
const candidates = parseSrcset(decodeQuoteEntities(value));
|
|
287
|
+
const descriptorUnits = { width: 'w', height: 'h', density: 'x' };
|
|
288
|
+
const descriptorTypes = Object.keys(descriptorUnits).filter((type) => candidates.some((candidate) => candidate[type]));
|
|
289
|
+
if (descriptorTypes.length > 1)
|
|
290
|
+
throw new Error('Mixed descriptor in srcset is not supported');
|
|
291
|
+
const descriptorType = descriptorTypes[0];
|
|
292
|
+
const unit = descriptorType ? descriptorUnits[descriptorType] : '';
|
|
293
|
+
const urls = candidates.map((candidate) => candidate.source.value);
|
|
294
|
+
const widestUrl = Math.max(...urls.map((url) => url.length));
|
|
295
|
+
const descriptors = candidates.map((candidate) => descriptorType && candidate[descriptorType] ? String(candidate[descriptorType].value) : '');
|
|
296
|
+
const descriptorLeftLengths = descriptors.map((descriptor) => {
|
|
297
|
+
const decimal = descriptor.indexOf('.');
|
|
298
|
+
return decimal === -1 ? descriptor.length : decimal;
|
|
299
|
+
});
|
|
300
|
+
const widestDescriptorLeft = Math.max(...descriptorLeftLengths);
|
|
301
|
+
const printed = urls.map((url, index) => {
|
|
302
|
+
const parts = [url.replaceAll('"', '"')];
|
|
303
|
+
const descriptor = descriptors[index];
|
|
304
|
+
if (descriptor) {
|
|
305
|
+
const padding = widestUrl - url.length + 1 + widestDescriptorLeft - descriptorLeftLengths[index];
|
|
306
|
+
parts.push(ifBreak(' '.repeat(padding), ' '), descriptor + unit);
|
|
307
|
+
}
|
|
308
|
+
return parts;
|
|
309
|
+
});
|
|
310
|
+
return group$3([indent$3([softline$3, join$1([',', line$2], printed)]), softline$3]);
|
|
311
|
+
}
|
|
312
|
+
const decodeQuoteEntities = (text) => text.replaceAll(''', "'").replaceAll('"', '"');
|
|
274
313
|
function printClassNames(value) {
|
|
275
314
|
const lines = value.trim().split(/[\r\n]+/);
|
|
276
|
-
const formattedLines = lines.map((
|
|
277
|
-
const spaces = /^\s+/.exec(
|
|
278
|
-
return (spaces ? spaces[0] : '') +
|
|
315
|
+
const formattedLines = lines.map((row) => {
|
|
316
|
+
const spaces = /^\s+/.exec(row);
|
|
317
|
+
return (spaces ? spaces[0] : '') + row.trim().split(/\s+/).join(' ');
|
|
279
318
|
});
|
|
280
319
|
return formattedLines.join('\n');
|
|
281
320
|
}
|
|
@@ -284,11 +323,14 @@ const leadingWhitespace$1 = /^[\t\n\f\r ]+/;
|
|
|
284
323
|
const trailingWhitespace$1 = /[\t\n\f\r ]+$/;
|
|
285
324
|
const hasNewline = (run) => /[\n\r]/.test(run);
|
|
286
325
|
const isText = (node) => node?.type === 'JSXText';
|
|
326
|
+
const isComment = (node) => node?.type === 'AstroComment';
|
|
287
327
|
const rawTextOf = (node) => node.raw ?? '';
|
|
288
328
|
const isWhitespaceOnly = (node) => isText(node) && rawTextOf(node).trim().length === 0;
|
|
289
329
|
function opensRawSubtree(node) {
|
|
290
330
|
if (node.type !== 'JSXElement')
|
|
291
331
|
return false;
|
|
332
|
+
if (node.astroPreserveWhitespace)
|
|
333
|
+
return true;
|
|
292
334
|
if (hasAttribute(node, 'is:raw'))
|
|
293
335
|
return true;
|
|
294
336
|
const tag = tagNameOf(node);
|
|
@@ -301,9 +343,62 @@ function displayOf(node) {
|
|
|
301
343
|
const tag = tagNameOf(node);
|
|
302
344
|
if (tag === null || isComponentName(tag) || tag.includes('-'))
|
|
303
345
|
return 'inline';
|
|
346
|
+
if (node.astroSvg)
|
|
347
|
+
return tag === 'svg' ? 'inline-block' : node.astroSvgText ? 'inline' : 'block';
|
|
304
348
|
return displayOfTag(tag);
|
|
305
349
|
}
|
|
350
|
+
const isBlockBox = (node) => node !== null && node.type !== 'JSXText' && !isInlineDisplay(displayOf(node));
|
|
351
|
+
const swallowsEdgeWhitespace = (node) => {
|
|
352
|
+
const display = displayOf(node);
|
|
353
|
+
return display === 'inline-block' || !isInlineDisplay(display);
|
|
354
|
+
};
|
|
355
|
+
const breaksOwnChildren = new Set(['html', 'head', 'ul', 'ol', 'select']);
|
|
356
|
+
const breaksOwnContent = new Set(['body', 'script', 'style']);
|
|
357
|
+
function breaksChildren(node) {
|
|
358
|
+
const tag = node.type === 'JSXElement' ? tagNameOf(node) : null;
|
|
359
|
+
if (tag === null || isComponentName(tag))
|
|
360
|
+
return false;
|
|
361
|
+
if (breaksOwnChildren.has(tag))
|
|
362
|
+
return true;
|
|
363
|
+
const display = displayOfTag(tag);
|
|
364
|
+
return display.startsWith('table') && display !== 'table-cell';
|
|
365
|
+
}
|
|
366
|
+
const hasElementChild = (node) => childrenOf(node)?.some((child) => child.type === 'JSXElement') ?? false;
|
|
367
|
+
const runBefore = (node) => node && isText(node) ? (trailingWhitespace$1.exec(rawTextOf(node))?.[0] ?? '') : '';
|
|
368
|
+
const runAfter = (node) => node && isText(node) ? (leadingWhitespace$1.exec(rawTextOf(node))?.[0] ?? '') : '';
|
|
369
|
+
function sitsOnItsOwnLine(container, child) {
|
|
370
|
+
if (child === null || isText(child))
|
|
371
|
+
return false;
|
|
372
|
+
const children = childrenOf(container);
|
|
373
|
+
const index = children?.indexOf(child) ?? -1;
|
|
374
|
+
if (index === -1)
|
|
375
|
+
return false;
|
|
376
|
+
return hasNewline(runBefore(children[index - 1])) && hasNewline(runAfter(children[index + 1]));
|
|
377
|
+
}
|
|
378
|
+
const hasChildOnItsOwnLine = (node) => childrenOf(node)?.some((child) => sitsOnItsOwnLine(node, child)) ?? false;
|
|
379
|
+
function forcesBreak(node) {
|
|
380
|
+
if (breaksChildren(node))
|
|
381
|
+
return true;
|
|
382
|
+
const children = childrenOf(node);
|
|
383
|
+
if (children === null)
|
|
384
|
+
return false;
|
|
385
|
+
const tag = node.type === 'JSXElement' ? tagNameOf(node) : null;
|
|
386
|
+
if (tag !== null && breaksOwnContent.has(tag))
|
|
387
|
+
return true;
|
|
388
|
+
return children.some(hasElementChild) || hasChildOnItsOwnLine(node);
|
|
389
|
+
}
|
|
306
390
|
const isBlankRun = (run) => /[\n\r][^\S\n\r]*[\n\r]/.test(run);
|
|
391
|
+
const isEmptySlot = (node) => node.type === 'JSXElement' && tagNameOf(node) === 'slot' && (childrenOf(node)?.length ?? 0) === 0;
|
|
392
|
+
function canRenderEmpty(container) {
|
|
393
|
+
const tag = container.type === 'JSXElement' ? tagNameOf(container) : null;
|
|
394
|
+
if (tag === null || isComponentName(tag))
|
|
395
|
+
return false;
|
|
396
|
+
const children = childrenOf(container);
|
|
397
|
+
if (children === null)
|
|
398
|
+
return false;
|
|
399
|
+
const content = children.filter((child) => !isWhitespaceOnly(child) && !isComment(child));
|
|
400
|
+
return (children.some((child) => isComment(child) || isEmptySlot(child)) && content.every(isEmptySlot));
|
|
401
|
+
}
|
|
307
402
|
function sidesFor(boundary) {
|
|
308
403
|
if (boundary.edge)
|
|
309
404
|
return [null];
|
|
@@ -318,7 +413,7 @@ function sidesFor(boundary) {
|
|
|
318
413
|
sides.push(boundary.next);
|
|
319
414
|
return sides.length > 0 ? sides : null;
|
|
320
415
|
}
|
|
321
|
-
function blankContentIsFree(container,
|
|
416
|
+
function blankContentIsFree(container, isRoot, settings) {
|
|
322
417
|
const tag = container.type === 'JSXElement' ? tagNameOf(container) : null;
|
|
323
418
|
if (tag === 'slot')
|
|
324
419
|
return false;
|
|
@@ -352,16 +447,26 @@ function separatorFor(run, boundary, settings) {
|
|
|
352
447
|
return run === '' ? 'none' : 'space';
|
|
353
448
|
const free = isFree(internal) || (sides !== null && mayAlterRenderedWhitespace(internal));
|
|
354
449
|
if (boundary.edge) {
|
|
450
|
+
if (settings.sensitivity !== 'ignore' && canRenderEmpty(boundary.container)) {
|
|
451
|
+
return run === '' ? 'none' : 'space';
|
|
452
|
+
}
|
|
355
453
|
if (free)
|
|
356
454
|
return 'soft';
|
|
357
455
|
return run === '' ? 'none' : 'space';
|
|
358
456
|
}
|
|
359
457
|
if (isBlankRun(run))
|
|
360
458
|
return 'blank';
|
|
361
|
-
if (
|
|
459
|
+
if (settings.sensitivity === 'ignore')
|
|
460
|
+
return 'break';
|
|
461
|
+
if (hasNewline(run) &&
|
|
462
|
+
(sitsOnItsOwnLine(boundary.container, boundary.prev) ||
|
|
463
|
+
sitsOnItsOwnLine(boundary.container, boundary.next))) {
|
|
464
|
+
return 'break';
|
|
465
|
+
}
|
|
466
|
+
if (run !== '' && (isComment(boundary.prev) || isComment(boundary.next)))
|
|
362
467
|
return 'break';
|
|
363
468
|
if (free)
|
|
364
|
-
return 'soft';
|
|
469
|
+
return isBlockBox(boundary.prev) || isBlockBox(boundary.next) ? 'break' : 'soft';
|
|
365
470
|
return run === '' ? 'none' : 'space';
|
|
366
471
|
}
|
|
367
472
|
function normalizeWhitespace(template, options) {
|
|
@@ -455,6 +560,8 @@ function decide(run, boundary) {
|
|
|
455
560
|
const { mode } = boundary.context;
|
|
456
561
|
if (isSlotFallback(boundary))
|
|
457
562
|
return 'space';
|
|
563
|
+
if (boundary.context.sensitivity !== 'ignore' && canRenderEmpty(boundary.container))
|
|
564
|
+
return 'keep';
|
|
458
565
|
if (isFree(boundary))
|
|
459
566
|
return 'drop';
|
|
460
567
|
if (mayAlterRenderedWhitespace(boundary))
|
|
@@ -475,11 +582,11 @@ function isFree(boundary) {
|
|
|
475
582
|
const tag = container.type === 'JSXElement' ? tagNameOf(container) : null;
|
|
476
583
|
if (loneChild && tag !== null && isComponentName(tag))
|
|
477
584
|
return true;
|
|
585
|
+
if (context.sensitivity !== 'strict' && breaksChildren(container))
|
|
586
|
+
return true;
|
|
478
587
|
if (mode === 'html') {
|
|
479
588
|
if (loneChild)
|
|
480
589
|
return true;
|
|
481
|
-
if (tag === 'head')
|
|
482
|
-
return true;
|
|
483
590
|
}
|
|
484
591
|
return false;
|
|
485
592
|
}
|
|
@@ -489,7 +596,7 @@ function mayAlterRenderedWhitespace(boundary) {
|
|
|
489
596
|
return true;
|
|
490
597
|
if (sensitivity === 'strict')
|
|
491
598
|
return false;
|
|
492
|
-
return boundary.sides.
|
|
599
|
+
return boundary.sides.some((side) => side === null ? swallowsEdgeWhitespace(boundary.container) : isBlockBox(side));
|
|
493
600
|
}
|
|
494
601
|
function isSlotFallback(boundary) {
|
|
495
602
|
return (boundary.container.type === 'JSXElement' &&
|
|
@@ -502,9 +609,10 @@ function parse(source, options) {
|
|
|
502
609
|
const failure = diagnostics.find((diagnostic) => diagnostic.severity === 'error');
|
|
503
610
|
if (failure)
|
|
504
611
|
throw syntaxError(failure);
|
|
505
|
-
|
|
612
|
+
stripParentheses(ast);
|
|
506
613
|
repairSpans(ast);
|
|
507
614
|
markAttributes(ast, source);
|
|
615
|
+
markSvgNamespace(ast);
|
|
508
616
|
applyPrettierIgnore(ast);
|
|
509
617
|
const body = ast.body;
|
|
510
618
|
const template = templateFragment(ast, body);
|
|
@@ -532,7 +640,7 @@ function syntaxError(diagnostic) {
|
|
|
532
640
|
error.loc = { start: { line, column } };
|
|
533
641
|
return error;
|
|
534
642
|
}
|
|
535
|
-
function
|
|
643
|
+
function stripParentheses(root) {
|
|
536
644
|
walk(root, (node) => {
|
|
537
645
|
for (const key of Object.keys(node)) {
|
|
538
646
|
const value = node[key];
|
|
@@ -549,8 +657,13 @@ function stripParenthesizedExpressions(root) {
|
|
|
549
657
|
}
|
|
550
658
|
function unwrapParens(node) {
|
|
551
659
|
let current = node;
|
|
552
|
-
while (isNode(current)
|
|
553
|
-
current
|
|
660
|
+
while (isNode(current)) {
|
|
661
|
+
if (current.type === 'ParenthesizedExpression')
|
|
662
|
+
current = current.expression;
|
|
663
|
+
else if (current.type === 'TSParenthesizedType')
|
|
664
|
+
current = current.typeAnnotation;
|
|
665
|
+
else
|
|
666
|
+
break;
|
|
554
667
|
}
|
|
555
668
|
return current;
|
|
556
669
|
}
|
|
@@ -567,28 +680,43 @@ function repairSpans(root) {
|
|
|
567
680
|
}
|
|
568
681
|
function markAttributes(root, source) {
|
|
569
682
|
walk(root, (node) => {
|
|
570
|
-
if (node.type !== '
|
|
571
|
-
return;
|
|
572
|
-
const value = node.value;
|
|
573
|
-
if (!value)
|
|
683
|
+
if (node.type !== 'JSXElement')
|
|
574
684
|
return;
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
if (
|
|
579
|
-
|
|
580
|
-
|
|
685
|
+
const tag = tagNameOf(node);
|
|
686
|
+
const htmlElement = tag !== null && !isComponentName(tag);
|
|
687
|
+
for (const attribute of attributesOf(node)) {
|
|
688
|
+
if (attribute.type !== 'JSXAttribute')
|
|
689
|
+
continue;
|
|
690
|
+
const name = String(attribute.name.name).toLowerCase();
|
|
691
|
+
if (htmlElement && name === 'style')
|
|
692
|
+
attribute.astroStyleAttribute = true;
|
|
693
|
+
if ((tag === 'img' || tag === 'source') && name === 'srcset') {
|
|
694
|
+
attribute.astroSrcsetAttribute = true;
|
|
581
695
|
}
|
|
582
|
-
|
|
696
|
+
markAttribute(attribute, source);
|
|
583
697
|
}
|
|
584
|
-
if (value.type !== 'JSXExpressionContainer')
|
|
585
|
-
return;
|
|
586
|
-
if (source[node.start] === '{')
|
|
587
|
-
node.astroShorthand = true;
|
|
588
|
-
if (source[value.start] === '`')
|
|
589
|
-
node.astroBacktick = true;
|
|
590
698
|
});
|
|
591
699
|
}
|
|
700
|
+
function markAttribute(node, source) {
|
|
701
|
+
const value = node.value;
|
|
702
|
+
if (!value)
|
|
703
|
+
return;
|
|
704
|
+
if (value.type === 'Literal' && typeof value.value === 'string') {
|
|
705
|
+
const name = node.name.name;
|
|
706
|
+
const text = name === 'class' ? printClassNames(value.value) : value.value;
|
|
707
|
+
if (value.raw === null || text !== value.value) {
|
|
708
|
+
value.value = text;
|
|
709
|
+
value.raw = `"${text.replaceAll('"', '"')}"`;
|
|
710
|
+
}
|
|
711
|
+
return;
|
|
712
|
+
}
|
|
713
|
+
if (value.type !== 'JSXExpressionContainer')
|
|
714
|
+
return;
|
|
715
|
+
if (source[node.start] === '{')
|
|
716
|
+
node.astroShorthand = true;
|
|
717
|
+
if (source[value.start] === '`')
|
|
718
|
+
node.astroBacktick = true;
|
|
719
|
+
}
|
|
592
720
|
function applyPrettierIgnore(root) {
|
|
593
721
|
walk(root, (node) => {
|
|
594
722
|
const children = node.type === 'AstroRoot' ? node.body : childrenOf(node);
|
|
@@ -605,6 +733,28 @@ function applyPrettierIgnore(root) {
|
|
|
605
733
|
}
|
|
606
734
|
});
|
|
607
735
|
}
|
|
736
|
+
const svgTextElements = new Set(['text', 'textPath', 'tspan']);
|
|
737
|
+
function markSvgNamespace(root) {
|
|
738
|
+
const mark = (node, inText = false, inheritedPreserve = false) => {
|
|
739
|
+
node.astroSvg = true;
|
|
740
|
+
const textContent = inText || svgTextElements.has(tagNameOf(node) ?? '');
|
|
741
|
+
const whitespace = attributeStringValue(node, 'xml:space');
|
|
742
|
+
const preserve = whitespace === 'preserve' || (inheritedPreserve && whitespace !== 'default');
|
|
743
|
+
if (textContent)
|
|
744
|
+
node.astroSvgText = true;
|
|
745
|
+
if (textContent && preserve)
|
|
746
|
+
node.astroPreserveWhitespace = true;
|
|
747
|
+
for (const child of childrenOf(node) ?? []) {
|
|
748
|
+
if (child.type !== 'JSXElement' || tagNameOf(child) === 'foreignObject')
|
|
749
|
+
continue;
|
|
750
|
+
mark(child, textContent, preserve);
|
|
751
|
+
}
|
|
752
|
+
};
|
|
753
|
+
walk(root, (node) => {
|
|
754
|
+
if (node.type === 'JSXElement' && tagNameOf(node) === 'svg')
|
|
755
|
+
mark(node);
|
|
756
|
+
});
|
|
757
|
+
}
|
|
608
758
|
function templateFragment(root, body) {
|
|
609
759
|
const start = body[0]?.start ?? root.end;
|
|
610
760
|
const end = body.at(-1)?.end ?? root.end;
|
|
@@ -673,8 +823,7 @@ function resolveBlankContainers(template, settings) {
|
|
|
673
823
|
const blank = children.every((child) => child.type === 'JSXText' && String(child.raw ?? '').trim() === '');
|
|
674
824
|
if (!blank)
|
|
675
825
|
return;
|
|
676
|
-
const
|
|
677
|
-
const free = blankContentIsFree(node, run, node.astroRoot === true, settings);
|
|
826
|
+
const free = blankContentIsFree(node, node.astroRoot === true, settings);
|
|
678
827
|
children.length = 0;
|
|
679
828
|
if (!free) {
|
|
680
829
|
children.push({ type: 'JSXText', start: node.start, end: node.start, raw: ' ', value: ' ' });
|
|
@@ -713,32 +862,38 @@ function printableComments(root) {
|
|
|
713
862
|
|
|
714
863
|
const estree = printers$1.estree;
|
|
715
864
|
|
|
716
|
-
const { fill, group: group$
|
|
865
|
+
const { fill, group: group$2, hardline: hardline$2, indent: indent$2, line: line$1, softline: softline$2 } = doc.builders;
|
|
717
866
|
const leadingWhitespace = /^[\t\n\f\r ]+/;
|
|
718
867
|
const trailingWhitespace = /[\t\n\f\r ]+$/;
|
|
719
868
|
const whitespaceRun = /[\t\n\f\r ]+/;
|
|
869
|
+
const lends = 'lends-closing-bracket';
|
|
870
|
+
const withholdsClosingBracket = (node) => node.type === 'JSXElement' &&
|
|
871
|
+
!node.astroIgnored &&
|
|
872
|
+
Boolean(node.closingElement) &&
|
|
873
|
+
Boolean(node.astroChildren) &&
|
|
874
|
+
!opensRawSubtree(node);
|
|
720
875
|
function docFor(separator) {
|
|
721
876
|
switch (separator) {
|
|
722
877
|
case 'none':
|
|
723
878
|
return null;
|
|
724
879
|
case 'soft':
|
|
725
|
-
return softline;
|
|
880
|
+
return softline$2;
|
|
726
881
|
case 'space':
|
|
727
|
-
return line;
|
|
882
|
+
return line$1;
|
|
728
883
|
case 'break':
|
|
729
884
|
return hardline$2;
|
|
730
885
|
case 'blank':
|
|
731
886
|
return [hardline$2, hardline$2];
|
|
732
887
|
}
|
|
733
888
|
}
|
|
734
|
-
function collect(children
|
|
889
|
+
function collect(children) {
|
|
735
890
|
const items = [];
|
|
736
891
|
const runs = [];
|
|
737
892
|
let pending = '';
|
|
738
893
|
for (const [index, child] of children.entries()) {
|
|
739
894
|
if (child.type !== 'JSXText') {
|
|
740
895
|
runs.push(pending);
|
|
741
|
-
items.push({ node: child, words: null, doc:
|
|
896
|
+
items.push({ node: child, index, words: null, doc: '' });
|
|
742
897
|
pending = '';
|
|
743
898
|
continue;
|
|
744
899
|
}
|
|
@@ -752,6 +907,7 @@ function collect(children, docs) {
|
|
|
752
907
|
runs.push(pending + lead);
|
|
753
908
|
items.push({
|
|
754
909
|
node: child,
|
|
910
|
+
index,
|
|
755
911
|
words: raw.slice(lead.length, raw.length - trail.length).split(whitespaceRun),
|
|
756
912
|
doc: '',
|
|
757
913
|
});
|
|
@@ -760,13 +916,11 @@ function collect(children, docs) {
|
|
|
760
916
|
runs.push(pending);
|
|
761
917
|
return { items, runs };
|
|
762
918
|
}
|
|
763
|
-
function printChildren(path, options, print) {
|
|
919
|
+
function printChildren(path, options, print, childrenOptions = {}) {
|
|
920
|
+
const { mode, suffix } = childrenOptions;
|
|
764
921
|
const container = path.node;
|
|
765
|
-
const
|
|
766
|
-
|
|
767
|
-
docs.push(child.node.type === 'JSXText' ? '' : print());
|
|
768
|
-
}, 'astroChildren');
|
|
769
|
-
const { items, runs } = collect(container.astroChildren, docs);
|
|
922
|
+
const children = container.astroChildren;
|
|
923
|
+
const { items, runs } = collect(children);
|
|
770
924
|
if (items.length === 0)
|
|
771
925
|
return runs[0] === '' ? '' : ' ';
|
|
772
926
|
const isRoot = container.astroRoot === true;
|
|
@@ -782,6 +936,28 @@ function printChildren(path, options, print) {
|
|
|
782
936
|
loneChild: false,
|
|
783
937
|
edge,
|
|
784
938
|
}, settings));
|
|
939
|
+
const lenders = new Set();
|
|
940
|
+
const lending = new Set();
|
|
941
|
+
for (let position = 1; position < items.length; position++) {
|
|
942
|
+
if (separatorAt(position, false) !== null)
|
|
943
|
+
continue;
|
|
944
|
+
if (!withholdsClosingBracket(items[position - 1].node))
|
|
945
|
+
continue;
|
|
946
|
+
lenders.add(position);
|
|
947
|
+
lending.add(items[position - 1].index);
|
|
948
|
+
}
|
|
949
|
+
if (mode === 'fill-lending')
|
|
950
|
+
lending.add(items.at(-1).index);
|
|
951
|
+
const printed = new Map();
|
|
952
|
+
path.each((child, index) => {
|
|
953
|
+
if (child.node.type === 'JSXText')
|
|
954
|
+
return;
|
|
955
|
+
printed.set(index, print(undefined, lending.has(index) ? lends : undefined));
|
|
956
|
+
}, 'astroChildren');
|
|
957
|
+
for (const item of items) {
|
|
958
|
+
if (item.words === null)
|
|
959
|
+
item.doc = printed.get(item.index) ?? '';
|
|
960
|
+
}
|
|
785
961
|
const parts = [''];
|
|
786
962
|
const append = (content) => parts.push([parts.pop(), content]);
|
|
787
963
|
const separate = (separator) => {
|
|
@@ -789,26 +965,41 @@ function printChildren(path, options, print) {
|
|
|
789
965
|
parts.push(separator, '');
|
|
790
966
|
};
|
|
791
967
|
for (const [position, item] of items.entries()) {
|
|
792
|
-
if (position > 0)
|
|
793
|
-
|
|
968
|
+
if (position > 0) {
|
|
969
|
+
if (lenders.has(position)) {
|
|
970
|
+
parts.push(softline$2, '');
|
|
971
|
+
append('>');
|
|
972
|
+
}
|
|
973
|
+
else
|
|
974
|
+
separate(separatorAt(position, false));
|
|
975
|
+
}
|
|
794
976
|
if (item.words === null) {
|
|
795
977
|
append(item.doc);
|
|
796
978
|
continue;
|
|
797
979
|
}
|
|
798
980
|
for (const [wordPosition, word] of item.words.entries()) {
|
|
799
981
|
if (wordPosition > 0)
|
|
800
|
-
separate(line);
|
|
982
|
+
separate(line$1);
|
|
801
983
|
append(word);
|
|
802
984
|
}
|
|
803
985
|
}
|
|
986
|
+
if (suffix)
|
|
987
|
+
append(suffix);
|
|
804
988
|
const body = fill(parts);
|
|
805
|
-
if (isRoot)
|
|
989
|
+
if (isRoot || mode === 'fill' || mode === 'fill-lending')
|
|
806
990
|
return body;
|
|
807
|
-
|
|
991
|
+
const content = [
|
|
992
|
+
indent$2([separatorAt(0, true) ?? '', body]),
|
|
993
|
+
separatorAt(items.length, true) ?? '',
|
|
994
|
+
];
|
|
995
|
+
if (mode === 'loose')
|
|
996
|
+
return content;
|
|
997
|
+
return group$2(content, { shouldBreak: forcesBreak(container) });
|
|
808
998
|
}
|
|
809
999
|
|
|
810
|
-
const { group, hardline: hardline$1, indent, join } = doc.builders;
|
|
811
|
-
const { replaceEndOfLine: replaceEndOfLine$1 } = doc.utils;
|
|
1000
|
+
const { group: group$1, hardline: hardline$1, indent: indent$1, join, softline: softline$1 } = doc.builders;
|
|
1001
|
+
const { mapDoc, replaceEndOfLine: replaceEndOfLine$1 } = doc.utils;
|
|
1002
|
+
const escapeQuotes = (value) => mapDoc(value, (part) => (typeof part === 'string' ? part.replaceAll('"', '"') : part));
|
|
812
1003
|
const styleParsers = {
|
|
813
1004
|
css: 'css',
|
|
814
1005
|
scss: 'scss',
|
|
@@ -846,6 +1037,20 @@ function inferParserByTypeAttribute(type) {
|
|
|
846
1037
|
return 'babel-ts';
|
|
847
1038
|
}
|
|
848
1039
|
}
|
|
1040
|
+
function inferScriptParser(node) {
|
|
1041
|
+
const processed = attributesOf(node).every((attribute) => attribute.type === 'JSXAttribute' && attribute.name.name === 'src');
|
|
1042
|
+
if (processed)
|
|
1043
|
+
return 'babel-ts';
|
|
1044
|
+
return inferParserByTypeAttribute(attributeStringValue(node, 'type'));
|
|
1045
|
+
}
|
|
1046
|
+
function styleAttributeValue(node) {
|
|
1047
|
+
if (!node.astroStyleAttribute)
|
|
1048
|
+
return null;
|
|
1049
|
+
const value = node.value;
|
|
1050
|
+
if (value?.type !== 'Literal' || typeof value.value !== 'string')
|
|
1051
|
+
return null;
|
|
1052
|
+
return value.value.trim() === '' ? null : value.value;
|
|
1053
|
+
}
|
|
849
1054
|
function contentOf(node, options) {
|
|
850
1055
|
const start = node.openingElement.end;
|
|
851
1056
|
const end = node.closingElement?.start ?? node.end;
|
|
@@ -854,7 +1059,7 @@ function contentOf(node, options) {
|
|
|
854
1059
|
function wrapContent(print, content, isEmpty) {
|
|
855
1060
|
return [
|
|
856
1061
|
print('openingElement'),
|
|
857
|
-
indent([
|
|
1062
|
+
indent$1([hardline$1, content]),
|
|
858
1063
|
isEmpty ? '' : hardline$1,
|
|
859
1064
|
print('closingElement'),
|
|
860
1065
|
];
|
|
@@ -887,6 +1092,20 @@ function embed(path, options) {
|
|
|
887
1092
|
'---',
|
|
888
1093
|
];
|
|
889
1094
|
}
|
|
1095
|
+
if (node.type === 'JSXAttribute' && options.astroCompressHTML !== 'jsx') {
|
|
1096
|
+
const style = styleAttributeValue(node);
|
|
1097
|
+
if (style !== null) {
|
|
1098
|
+
return async (textToDoc) => {
|
|
1099
|
+
const declarations = await textToDoc(decodeQuoteEntities(style), {
|
|
1100
|
+
...options,
|
|
1101
|
+
parser: 'css',
|
|
1102
|
+
__isHTMLStyleAttribute: true,
|
|
1103
|
+
});
|
|
1104
|
+
const value = escapeQuotes(declarations);
|
|
1105
|
+
return ['style="', group$1([indent$1([softline$1, value]), softline$1]), '"'];
|
|
1106
|
+
};
|
|
1107
|
+
}
|
|
1108
|
+
}
|
|
890
1109
|
if (node.type !== 'JSXElement')
|
|
891
1110
|
return estree.embed(path, options);
|
|
892
1111
|
const tag = tagNameOf(node);
|
|
@@ -897,7 +1116,7 @@ function embed(path, options) {
|
|
|
897
1116
|
if (tag === 'script') {
|
|
898
1117
|
if (isEmpty)
|
|
899
1118
|
return estree.embed(path, options);
|
|
900
|
-
const parser =
|
|
1119
|
+
const parser = inferScriptParser(node);
|
|
901
1120
|
return async (textToDoc, print) => wrapContent(print, await surfacingErrors(textToDoc, source, { ...options, parser }), false);
|
|
902
1121
|
}
|
|
903
1122
|
if (tag === 'style') {
|
|
@@ -922,10 +1141,10 @@ function embed(path, options) {
|
|
|
922
1141
|
return estree.embed(path, options);
|
|
923
1142
|
}
|
|
924
1143
|
function printVerbatim(source) {
|
|
925
|
-
return (_textToDoc, print) => group([print('openingElement'), replaceEndOfLine$1(source), print('closingElement')]);
|
|
1144
|
+
return (_textToDoc, print) => group$1([print('openingElement'), replaceEndOfLine$1(source), print('closingElement')]);
|
|
926
1145
|
}
|
|
927
1146
|
|
|
928
|
-
const { hardline } = doc.builders;
|
|
1147
|
+
const { group, hardline, indent, line, softline } = doc.builders;
|
|
929
1148
|
const { replaceEndOfLine } = doc.utils;
|
|
930
1149
|
function printDoctype(value) {
|
|
931
1150
|
const trimmed = value.trim();
|
|
@@ -978,6 +1197,18 @@ function printAttribute(path, options, print) {
|
|
|
978
1197
|
return ['{', print(['value', 'expression']), '}'];
|
|
979
1198
|
if (node.astroBacktick)
|
|
980
1199
|
return [name, '=', print(['value', 'expression'])];
|
|
1200
|
+
if (options.astroCompressHTML !== 'jsx' &&
|
|
1201
|
+
node.astroSrcsetAttribute &&
|
|
1202
|
+
value?.type === 'Literal' &&
|
|
1203
|
+
typeof value.value === 'string' &&
|
|
1204
|
+
value.value.trim() !== '') {
|
|
1205
|
+
try {
|
|
1206
|
+
return ['srcset="', printSrcset(value.value), '"'];
|
|
1207
|
+
}
|
|
1208
|
+
catch {
|
|
1209
|
+
return ['srcset="', value.value.replaceAll('"', '"'), '"'];
|
|
1210
|
+
}
|
|
1211
|
+
}
|
|
981
1212
|
const expression = value?.type === 'JSXExpressionContainer' ? value.expression : null;
|
|
982
1213
|
if (options.astroAllowShorthand &&
|
|
983
1214
|
expression?.type === 'Identifier' &&
|
|
@@ -986,15 +1217,82 @@ function printAttribute(path, options, print) {
|
|
|
986
1217
|
}
|
|
987
1218
|
return null;
|
|
988
1219
|
}
|
|
1220
|
+
function printBreakableOpeningTag(path, options, print) {
|
|
1221
|
+
const node = path.node;
|
|
1222
|
+
const attributes = node.attributes;
|
|
1223
|
+
if (attributes.length !== 1)
|
|
1224
|
+
return null;
|
|
1225
|
+
const value = attributes[0].value;
|
|
1226
|
+
if (value?.type !== 'Literal' || typeof value.value !== 'string')
|
|
1227
|
+
return null;
|
|
1228
|
+
if (value.value.includes('\n'))
|
|
1229
|
+
return null;
|
|
1230
|
+
const end = node.selfClosing
|
|
1231
|
+
? options.bracketSameLine
|
|
1232
|
+
? [' />']
|
|
1233
|
+
: [line, '/>']
|
|
1234
|
+
: options.bracketSameLine
|
|
1235
|
+
? ['>']
|
|
1236
|
+
: [softline, '>'];
|
|
1237
|
+
return group(['<', print('name'), indent([line, print(['attributes', 0])]), ...end]);
|
|
1238
|
+
}
|
|
1239
|
+
function printWithDanglingBrackets(path, print, lending) {
|
|
1240
|
+
const node = path.node;
|
|
1241
|
+
const children = node.astroChildren;
|
|
1242
|
+
if (!children?.length || !node.closingElement)
|
|
1243
|
+
return null;
|
|
1244
|
+
if (swallowsEdgeWhitespace(node))
|
|
1245
|
+
return null;
|
|
1246
|
+
if (startsWithSpace(children[0]) || endsWithSpace(children.at(-1)))
|
|
1247
|
+
return null;
|
|
1248
|
+
const opening = print('openingElement');
|
|
1249
|
+
if (opening.type !== 'group' || !Array.isArray(opening.contents))
|
|
1250
|
+
return null;
|
|
1251
|
+
const contents = opening.contents.filter((part) => part !== '');
|
|
1252
|
+
if (contents.at(-1) !== '>')
|
|
1253
|
+
return null;
|
|
1254
|
+
const withoutBracket = contents.slice(0, -1);
|
|
1255
|
+
if (withoutBracket.at(-1)?.type === 'line')
|
|
1256
|
+
withoutBracket.pop();
|
|
1257
|
+
const tag = jsxNameOf(node.closingElement.name);
|
|
1258
|
+
if (tag === null)
|
|
1259
|
+
return null;
|
|
1260
|
+
const head = { ...opening, contents: withoutBracket };
|
|
1261
|
+
const shouldBreak = forcesBreak(node);
|
|
1262
|
+
if (isSelfClosing(children.at(-1)) && !children.at(-1).astroIgnored) {
|
|
1263
|
+
const lentBody = print(['children', 0], { mode: 'fill-lending' });
|
|
1264
|
+
return group([head, indent([softline, '>', lentBody]), line, '/>', '</', tag, lending ? '' : '>'], { shouldBreak });
|
|
1265
|
+
}
|
|
1266
|
+
const body = print(['children', 0], { mode: 'fill', suffix: ['</', tag] });
|
|
1267
|
+
return group([head, indent([softline, '>', body]), lending ? '' : [softline, '>']], {
|
|
1268
|
+
shouldBreak,
|
|
1269
|
+
});
|
|
1270
|
+
}
|
|
1271
|
+
const isSelfClosing = (node) => node.type === 'JSXElement' && !node.closingElement;
|
|
1272
|
+
function withoutSelfClosingMarker(printed) {
|
|
1273
|
+
if (Array.isArray(printed)) {
|
|
1274
|
+
return printed.at(-1) === ' />' ? printed.slice(0, -1) : printed;
|
|
1275
|
+
}
|
|
1276
|
+
const tag = printed;
|
|
1277
|
+
if (tag.type !== 'group' || !Array.isArray(tag.contents))
|
|
1278
|
+
return printed;
|
|
1279
|
+
if (tag.contents.at(-1) === ' />')
|
|
1280
|
+
return { ...tag, contents: tag.contents.slice(0, -1) };
|
|
1281
|
+
if (tag.contents.at(-1) !== '/>')
|
|
1282
|
+
return printed;
|
|
1283
|
+
return { ...tag, contents: tag.contents.slice(0, -2) };
|
|
1284
|
+
}
|
|
1285
|
+
const startsWithSpace = (child) => child.type === 'JSXText' && /^[\t\n\f\r ]/.test(String(child.raw ?? ''));
|
|
1286
|
+
const endsWithSpace = (child) => child.type === 'JSXText' && /[\t\n\f\r ]$/.test(String(child.raw ?? ''));
|
|
989
1287
|
function unwrapFragmentIndent(printed) {
|
|
990
|
-
const
|
|
991
|
-
if (
|
|
1288
|
+
const fragment = printed;
|
|
1289
|
+
if (fragment.type !== 'group')
|
|
992
1290
|
return printed;
|
|
993
|
-
if (
|
|
994
|
-
const states =
|
|
995
|
-
return { ...
|
|
1291
|
+
if (fragment.expandedStates) {
|
|
1292
|
+
const states = fragment.expandedStates.map(unwrapFragmentIndent);
|
|
1293
|
+
return { ...fragment, contents: states[0], expandedStates: states };
|
|
996
1294
|
}
|
|
997
|
-
const parts =
|
|
1295
|
+
const parts = fragment.contents;
|
|
998
1296
|
if (!Array.isArray(parts) || parts.length !== 4)
|
|
999
1297
|
return printed;
|
|
1000
1298
|
const indented = parts[1];
|
|
@@ -1013,8 +1311,9 @@ const printer = {
|
|
|
1013
1311
|
},
|
|
1014
1312
|
print(path, options, print, args) {
|
|
1015
1313
|
const node = path.node;
|
|
1016
|
-
if (node[ownChildren])
|
|
1017
|
-
return path.callParent(() => printChildren(path, options, print));
|
|
1314
|
+
if (node[ownChildren]) {
|
|
1315
|
+
return path.callParent(() => printChildren(path, options, print, args ?? {}));
|
|
1316
|
+
}
|
|
1018
1317
|
if (node[synthetic])
|
|
1019
1318
|
return '';
|
|
1020
1319
|
if (node.astroIgnored) {
|
|
@@ -1027,6 +1326,25 @@ const printer = {
|
|
|
1027
1326
|
if (attribute)
|
|
1028
1327
|
return attribute;
|
|
1029
1328
|
}
|
|
1329
|
+
if (node.type === 'JSXOpeningElement' && options.astroCompressHTML !== 'jsx') {
|
|
1330
|
+
const opening = printBreakableOpeningTag(path, options, print);
|
|
1331
|
+
if (opening)
|
|
1332
|
+
return opening;
|
|
1333
|
+
}
|
|
1334
|
+
if (node.type === 'JSXElement' && args === lends && isSelfClosing(node)) {
|
|
1335
|
+
return withoutSelfClosingMarker(print('openingElement'));
|
|
1336
|
+
}
|
|
1337
|
+
if (node.type === 'JSXElement' && node.astroChildren && !opensRawSubtree(node)) {
|
|
1338
|
+
const dangling = printWithDanglingBrackets(path, print, args === lends);
|
|
1339
|
+
if (dangling)
|
|
1340
|
+
return dangling;
|
|
1341
|
+
const tag = jsxNameOf(node.closingElement.name);
|
|
1342
|
+
return group([
|
|
1343
|
+
print('openingElement'),
|
|
1344
|
+
print(['children', 0], { mode: 'loose' }),
|
|
1345
|
+
args === lends && tag !== null ? ['</', tag] : print('closingElement'),
|
|
1346
|
+
], { shouldBreak: forcesBreak(node) });
|
|
1347
|
+
}
|
|
1030
1348
|
if (node.type === 'JSXElement' &&
|
|
1031
1349
|
node.closingElement &&
|
|
1032
1350
|
node.children.length > 0 &&
|