prettier-plugin-astro 0.0.10 → 0.1.0-next.0

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 CHANGED
@@ -2,44 +2,27 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- var parser = require('@astrojs/parser');
5
+ var makeSynchronous = require('make-synchronous');
6
6
  var _doc = require('prettier/doc');
7
7
  var sassFormatter = require('sass-formatter');
8
- var prettier = require('prettier');
9
8
 
10
9
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
11
10
 
11
+ var makeSynchronous__default = /*#__PURE__*/_interopDefaultLegacy(makeSynchronous);
12
12
  var _doc__default = /*#__PURE__*/_interopDefaultLegacy(_doc);
13
13
 
14
- const parse = (text) => parser.parse(text);
15
-
16
- const options = {
17
- astroSortOrder: {
18
- since: '0.0.1',
19
- category: 'Astro',
20
- type: 'choice',
21
- default: 'markup | styles',
22
- description: 'Sort order for markup, scripts, and styles',
23
- choices: [
24
- {
25
- value: 'markup | styles',
26
- description: 'markup | styles',
27
- },
28
- {
29
- value: 'styles | markup',
30
- description: 'styles | markup',
31
- },
32
- ],
33
- },
34
- astroAllowShorthand: {
35
- since: '0.0.10',
36
- category: 'Astro',
37
- type: 'boolean',
38
- default: true,
39
- description: 'Enable/disable attribute shorthand if attribute name and expression are the same',
40
- },
41
- };
42
- const parseSortOrder = (sortOrder) => sortOrder.split(' | ');
14
+ const parseSync = makeSynchronous__default["default"](async (source) => {
15
+ const dynamicImport = new Function('file', 'return import(file)');
16
+ const { parse } = await dynamicImport('@astrojs/compiler');
17
+ try {
18
+ const { ast } = await parse(source);
19
+ return ast;
20
+ }
21
+ catch (e) {
22
+ console.error(e);
23
+ }
24
+ });
25
+ const parse = (text) => parseSync(text);
43
26
 
44
27
  const blockElementsT = [
45
28
  'address',
@@ -75,70 +58,48 @@ const blockElementsT = [
75
58
  'section',
76
59
  'table',
77
60
  'ul',
61
+ 'title',
62
+ 'html',
78
63
  ];
79
64
  const blockElements = [...blockElementsT];
80
65
  const selfClosingTags = ['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source', 'track', 'wbr'];
81
66
 
67
+ const serializeSync = makeSynchronous__default["default"](async (node) => {
68
+ const dynamicImport = new Function('file', 'return import(file)');
69
+ const { serialize } = await dynamicImport('@astrojs/compiler/utils');
70
+ try {
71
+ return await serialize(node);
72
+ }
73
+ catch (e) {
74
+ console.error(e);
75
+ }
76
+ });
77
+ const serialize = (node) => serializeSync(node);
78
+
82
79
  const formattableAttributes = [];
83
- const rootNodeKeys = new Set(['html', 'css', 'module']);
84
- const isASTNode = (node) => typeof node === 'object' && Object.keys(node).filter((key) => rootNodeKeys.has(key)).length === rootNodeKeys.size;
85
80
  const isEmptyTextNode = (node) => {
86
- return !!node && node.type === 'Text' && getUnencodedText(node).trim() === '';
81
+ return !!node && node.type === 'text' && getUnencodedText(node).trim() === '';
87
82
  };
88
83
  const isPreTagContent = (path) => {
89
84
  if (!path || !path.stack || !Array.isArray(path.stack))
90
85
  return false;
91
- return path.stack.some((node) => (node.type === 'Element' && node.name.toLowerCase() === 'pre') || (node.type === 'Attribute' && !formattableAttributes.includes(node.name)));
86
+ return path.stack.some((node) => (node.type === 'element' && node.name.toLowerCase() === 'pre') || (node.type === 'attribute' && !formattableAttributes.includes(node.name)));
92
87
  };
93
- function isLoneMustacheTag(node) {
94
- return node !== true && node.length === 1 && node[0].type === 'MustacheTag';
95
- }
96
- function isAttributeShorthand(node) {
97
- return node !== true && node.length === 1 && node[0].type === 'AttributeShorthand';
98
- }
99
- function isOrCanBeConvertedToShorthand(node, opts) {
100
- if (!opts.astroAllowShorthand)
101
- return false;
102
- if (isAttributeShorthand(node.value)) {
103
- return true;
104
- }
105
- if (isLoneMustacheTag(node.value)) {
106
- const expression = node.value[0].expression;
107
- return expression.codeChunks[0] === node.name;
108
- }
109
- return false;
110
- }
111
88
  function getText(node, opts) {
112
- return opts.originalText.slice(opts.locStart(node), opts.locEnd(node));
89
+ var _a, _b, _c;
90
+ return opts.originalText.slice(((_a = node.position) === null || _a === void 0 ? void 0 : _a.start.offset) + 1, (_c = (_b = node.position) === null || _b === void 0 ? void 0 : _b.end) === null || _c === void 0 ? void 0 : _c.offset);
113
91
  }
114
92
  function getUnencodedText(node) {
115
- return node.raw || node.data;
93
+ return node.value;
116
94
  }
117
- function replaceEndOfLineWith(text, replacement) {
118
- const parts = [];
119
- for (const part of text.split('\n')) {
120
- if (parts.length > 0) {
121
- parts.push(replacement);
122
- }
123
- if (part.endsWith('\r')) {
124
- parts.push(part.slice(0, -1));
125
- }
126
- else {
127
- parts.push(part);
128
- }
129
- }
130
- return parts;
131
- }
132
- function printRaw(node, originalText, stripLeadingAndTrailingNewline = false) {
95
+ function printRaw(node, stripLeadingAndTrailingNewline = false) {
133
96
  if (!isNodeWithChildren(node)) {
134
97
  return '';
135
98
  }
136
99
  if (node.children.length === 0) {
137
100
  return '';
138
101
  }
139
- const firstChild = node.children[0];
140
- const lastChild = node.children[node.children.length - 1];
141
- let raw = originalText.substring(firstChild.start, lastChild.end);
102
+ let raw = node.children.reduce((prev, curr) => prev + serialize(curr), '');
142
103
  if (!stripLeadingAndTrailingNewline) {
143
104
  return raw;
144
105
  }
@@ -157,10 +118,10 @@ function isNodeWithChildren(node) {
157
118
  return node && Array.isArray(node.children);
158
119
  }
159
120
  function isInlineElement(path, opts, node) {
160
- return node && node.type === 'Element' && !isBlockElement(node, opts) && !isPreTagContent(path);
121
+ return node && node.type === 'element' && !isBlockElement(node, opts) && !isPreTagContent(path);
161
122
  }
162
123
  function isBlockElement(node, opts) {
163
- return node && node.type === 'Element' && opts.htmlWhitespaceSensitivity !== 'strict' && (opts.htmlWhitespaceSensitivity === 'ignore' || blockElements.includes(node.name));
124
+ return node && node.type === 'element' && opts.htmlWhitespaceSensitivity !== 'strict' && (opts.htmlWhitespaceSensitivity === 'ignore' || blockElements.includes(node.name));
164
125
  }
165
126
  function isTextNodeStartingWithLinebreak(node, nrLines = 1) {
166
127
  return startsWithLinebreak(getUnencodedText(node), nrLines);
@@ -172,10 +133,10 @@ function endsWithLinebreak(text, nrLines = 1) {
172
133
  return new RegExp(`(\\n[\\t\\f\\r ]*){${nrLines}}$`).test(text);
173
134
  }
174
135
  function isTextNodeStartingWithWhitespace(node) {
175
- return node.type === 'Text' && /^\s/.test(getUnencodedText(node));
136
+ return node.type === 'text' && /^\s/.test(getUnencodedText(node));
176
137
  }
177
138
  function isTextNodeEndingWithWhitespace(node) {
178
- return node.type === 'Text' && /\s$/.test(getUnencodedText(node));
139
+ return node.type === 'text' && /\s$/.test(getUnencodedText(node));
179
140
  }
180
141
  function forceIntoExpression(statement) {
181
142
  return `(${statement}\n)`;
@@ -205,8 +166,7 @@ function shouldHugEnd(node, opts) {
205
166
  if (children.length === 0) {
206
167
  return true;
207
168
  }
208
- const lastChild = children[children.length - 1];
209
- return !isTextNodeEndingWithWhitespace(lastChild);
169
+ return false;
210
170
  }
211
171
  function canOmitSoftlineBeforeClosingTag(path, opts) {
212
172
  return isLastChildWithinParentBlockElement(path, opts);
@@ -224,179 +184,49 @@ function isLastChildWithinParentBlockElement(path, opts) {
224
184
  return lastChild === path.getNode();
225
185
  }
226
186
  function trimTextNodeLeft(node) {
227
- node.raw = node.raw && node.raw.trimLeft();
228
- node.data = node.data && node.data.trimLeft();
187
+ node.value = node.value && node.value.trimStart();
229
188
  }
230
189
  function trimTextNodeRight(node) {
231
- node.raw = node.raw && node.raw.trimRight();
232
- node.data = node.data && node.data.trimRight();
233
- }
234
- function findLastIndex(isMatch, items) {
235
- for (let i = items.length - 1; i >= 0; i--) {
236
- if (isMatch(items[i], i)) {
237
- return i;
238
- }
239
- }
240
- return -1;
241
- }
242
- function trimChildren(children) {
243
- let firstNonEmptyNode = children.findIndex((n) => !isEmptyTextNode(n));
244
- firstNonEmptyNode = firstNonEmptyNode === -1 ? children.length - 1 : firstNonEmptyNode;
245
- let lastNonEmptyNode = findLastIndex((n, idx) => {
246
- return !isEmptyTextNode(n);
247
- }, children);
248
- lastNonEmptyNode = lastNonEmptyNode === -1 ? 0 : lastNonEmptyNode;
249
- for (let i = 0; i <= firstNonEmptyNode; i++) {
250
- const n = children[i];
251
- if (isTextNode(n)) {
252
- trimTextNodeLeft(n);
253
- }
254
- }
255
- for (let i = children.length - 1; i >= lastNonEmptyNode; i--) {
256
- const n = children[i];
257
- if (isTextNode(n)) {
258
- trimTextNodeRight(n);
259
- }
260
- }
261
- }
262
- function isHardline(docToCheck) {
263
- return docToCheck === prettier.doc.builders.hardline || deepEqual(docToCheck, prettier.doc.builders.hardline);
264
- }
265
- function deepEqual(x, y) {
266
- if (x === y) {
267
- return true;
268
- }
269
- else if (typeof x == 'object' && x != null && typeof y == 'object' && y != null) {
270
- if (Object.keys(x).length != Object.keys(y).length)
271
- return false;
272
- for (var prop in x) {
273
- if (Object.prototype.hasOwnProperty.call(y, prop)) {
274
- if (!deepEqual(x[prop], y[prop]))
275
- return false;
190
+ node.value = node.value && node.value.trimEnd();
191
+ }
192
+ function manualDedent(input) {
193
+ let result = '';
194
+ for (var i = 0; i < input.length; i++) {
195
+ result += input[i]
196
+ .replace(/\\\n[ \t]*/g, '')
197
+ .replace(/\\`/g, '`');
198
+ if (i < (arguments.length <= 1 ? 0 : arguments.length - 1)) {
199
+ result += arguments.length <= i + 1 ? undefined : arguments[i + 1];
200
+ }
201
+ }
202
+ const lines = result.split('\n');
203
+ let mindent = null;
204
+ lines.forEach(function (l) {
205
+ var m = l.match(/^(\s+)\S+/);
206
+ if (m) {
207
+ var indent = m[1].length;
208
+ if (!mindent) {
209
+ mindent = indent;
276
210
  }
277
211
  else {
278
- return false;
279
- }
280
- }
281
- return true;
282
- }
283
- else {
284
- return false;
285
- }
286
- }
287
- function isLine(docToCheck) {
288
- return (isHardline(docToCheck) ||
289
- (typeof docToCheck === 'object' && isDocCommand(docToCheck) && docToCheck.type === 'line') ||
290
- (typeof docToCheck === 'object' && isDocCommand(docToCheck) && docToCheck.type === 'concat' && docToCheck.parts.every(isLine)));
291
- }
292
- function isEmptyDoc(doc) {
293
- if (typeof doc === 'string') {
294
- return doc.length === 0;
295
- }
296
- if (Array.isArray(doc)) {
297
- return doc.length === 0;
298
- }
299
- return false;
300
- }
301
- function trim(docs, isWhitespace) {
302
- trimLeft(docs, isWhitespace);
303
- trimRight(docs, isWhitespace);
304
- return docs;
305
- }
306
- function trimLeft(group, isWhitespace) {
307
- let firstNonWhitespace = group.findIndex((doc) => !isEmptyDoc(doc) && !isWhitespace(doc));
308
- if (firstNonWhitespace < 0 && group.length) {
309
- firstNonWhitespace = group.length;
310
- }
311
- if (firstNonWhitespace > 0) {
312
- const removed = group.splice(0, firstNonWhitespace);
313
- if (removed.every(isEmptyDoc)) {
314
- return trimLeft(group, isWhitespace);
315
- }
316
- }
317
- else {
318
- const parts = getParts(group[0]);
319
- if (parts) {
320
- return trimLeft(parts, isWhitespace);
321
- }
322
- }
323
- }
324
- function trimRight(group, isWhitespace) {
325
- let lastNonWhitespace = group.length ? findLastIndex((doc) => !isEmptyDoc(doc) && !isWhitespace(doc), group) : 0;
326
- if (lastNonWhitespace < group.length - 1) {
327
- const removed = group.splice(lastNonWhitespace + 1);
328
- if (removed.every(isEmptyDoc)) {
329
- return trimRight(group, isWhitespace);
330
- }
331
- }
332
- else {
333
- const parts = getParts(group[group.length - 1]);
334
- if (parts) {
335
- return trimRight(parts, isWhitespace);
336
- }
337
- }
338
- }
339
- function getParts(doc) {
340
- if (typeof doc === 'object') {
341
- if (Array.isArray(doc)) {
342
- return doc;
343
- }
344
- if (doc.type === 'fill' || doc.type === 'concat') {
345
- return doc.parts;
346
- }
347
- if (doc.type === 'group') {
348
- return getParts(doc.contents);
349
- }
350
- }
351
- }
352
- function attachCommentsHTML(node) {
353
- if (!isNodeWithChildren(node) || !node.children.some(({ type }) => type === 'Comment'))
354
- return;
355
- const nodesToRemove = [];
356
- for (let n = 0; n < node.children.length - 1; n++) {
357
- if (!node.children[n])
358
- continue;
359
- if (node.children[n].type === 'Comment') {
360
- let next = n + 1;
361
- while (isEmptyTextNode(node.children[next])) {
362
- nodesToRemove.push(next);
363
- next++;
212
+ mindent = Math.min(mindent, indent);
364
213
  }
365
- prettier.util.addLeadingComment(node.children[next], node.children[n]);
366
214
  }
367
- }
368
- nodesToRemove.reverse();
369
- nodesToRemove.forEach((index) => {
370
- node.children.splice(index, 1);
371
215
  });
372
- }
373
- function dedent$1(input) {
374
- let minTabSize = Infinity;
375
- let result = input;
376
- result = result.replace(/\r\n/g, '\n');
377
- let char = '';
378
- for (const line of result.split('\n')) {
379
- if (!line)
380
- continue;
381
- if (line[0] && /^[^\s]/.test(line[0])) {
382
- minTabSize = 0;
383
- break;
384
- }
385
- const match = line.match(/^(\s+)\S+/);
386
- if (match) {
387
- if (match[1] && !char)
388
- char = match[1][0];
389
- if (match[1].length < minTabSize)
390
- minTabSize = match[1].length;
391
- }
392
- }
393
- if (minTabSize > 0 && Number.isFinite(minTabSize)) {
394
- result = result.replace(new RegExp(`^${new Array(minTabSize + 1).join(char)}`, 'gm'), '');
216
+ if (mindent !== null) {
217
+ (function () {
218
+ var m = mindent;
219
+ result = lines
220
+ .map(function (l) {
221
+ return l[0] === ' ' ? l.slice(m) : l;
222
+ })
223
+ .join('\n');
224
+ })();
395
225
  }
396
226
  return {
397
- tabSize: minTabSize === Infinity ? 0 : minTabSize,
398
- char,
399
- result,
227
+ result: result
228
+ .trim()
229
+ .replace(/\\n/g, '\n'),
400
230
  };
401
231
  }
402
232
  function getMarkdownName(script) {
@@ -423,123 +253,27 @@ function getMarkdownName(script) {
423
253
  return new Set(['Markdown']);
424
254
  }
425
255
  function isTextNode(node) {
426
- return node.type === 'Text';
427
- }
428
- function isDocCommand(doc) {
429
- if (typeof doc === 'string')
430
- return false;
431
- if (Array.isArray(doc))
432
- return false;
433
- return true;
434
- }
435
- function isInsideQuotedAttribute(path) {
436
- const stack = path.stack;
437
- return stack.some((node) => node.type === 'Attribute' && !isLoneMustacheTag(node.value));
256
+ return node.type === 'text';
438
257
  }
439
258
 
440
259
  const { builders: { breakParent, dedent, fill, group, hardline, indent, join, line, literalline, softline }, utils: { removeLines, stripTrailingHardline }, } = _doc__default["default"];
441
- function printTopLevelParts(node, path, opts, print) {
442
- let docs = [];
443
- const normalize = (doc) => [stripTrailingHardline(doc), hardline];
444
- if (node.module) {
445
- const subDoc = normalize(path.call(print, 'module'));
446
- docs.push(subDoc);
447
- }
448
- for (const section of parseSortOrder(opts.astroSortOrder)) {
449
- switch (section) {
450
- case 'markup': {
451
- const subDoc = path.call(print, 'html');
452
- if (!isEmptyDoc(subDoc))
453
- docs.push(normalize(subDoc));
454
- break;
455
- }
456
- case 'styles': {
457
- const subDoc = path.call(print, 'css');
458
- if (!isEmptyDoc(subDoc))
459
- docs.push(normalize(subDoc));
460
- break;
461
- }
462
- }
463
- }
464
- return join(softline, docs);
465
- }
466
- function printAttributeNodeValue(path, print, quotes, node) {
467
- const valueDocs = path.map((childPath) => childPath.call(print), 'value');
468
- if (!quotes || !formattableAttributes.includes(node.name)) {
469
- return valueDocs;
470
- }
471
- else {
472
- return indent(group(trim(valueDocs, isLine)));
473
- }
474
- }
475
- function printJS(path, print, name, { forceSingleQuote, forceSingleLine }) {
476
- path.getValue()[name].isJS = true;
477
- path.getValue()[name].forceSingleQuote = forceSingleQuote;
478
- path.getValue()[name].forceSingleLine = forceSingleLine;
479
- return path.call(print, name);
480
- }
481
260
  function printComment(commentPath, options) {
482
261
  return commentPath;
483
262
  }
484
263
  function print(path, opts, print) {
485
- var _a, _b;
486
264
  const node = path.getValue();
487
- const isMarkdownSubDoc = opts.parentParser === 'markdown';
488
265
  if (!node) {
489
266
  return '';
490
267
  }
491
268
  if (typeof node === 'string') {
492
269
  return node;
493
270
  }
494
- if (Array.isArray(node)) {
495
- return path.map((childPath) => childPath.call(print));
496
- }
497
- if (isASTNode(node)) {
498
- return printTopLevelParts(node, path, opts, print);
499
- }
500
- if (!isPreTagContent(path) && !isMarkdownSubDoc) {
501
- attachCommentsHTML(node);
502
- }
503
271
  switch (node.type) {
504
- case 'Fragment': {
505
- const text = getText(node, opts);
506
- if (text.length === 0) {
507
- return '';
508
- }
509
- if (!isNodeWithChildren(node) || node.children.every(isEmptyTextNode))
510
- return '';
511
- if (isMarkdownSubDoc) {
512
- if (isEmptyTextNode(node.children[0]))
513
- node.children.shift();
514
- }
515
- const hasInlineComponent = node.children.filter((x) => x.type === 'InlineComponent').length > 0;
516
- if (text.indexOf('{') === -1 && !hasInlineComponent) {
517
- node.__isRawHTML = true;
518
- node.content = text;
519
- return path.call(print);
520
- }
521
- if (!isPreTagContent(path)) {
522
- trimChildren(node.children);
523
- const output = trim([path.map(print, 'children')], (n) => isLine(n) ||
524
- (typeof n === 'string' && n.trim() === '') ||
525
- n === breakParent);
526
- if (output.every((doc) => isEmptyDoc(doc))) {
527
- return '';
528
- }
529
- return group([...output, hardline]);
530
- }
531
- else {
532
- return group(path.map(print, 'children'));
533
- }
272
+ case 'root': {
273
+ return [stripTrailingHardline(path.map(print, 'children')), hardline];
534
274
  }
535
- case 'Text': {
275
+ case 'text': {
536
276
  const rawText = getUnencodedText(node);
537
- if (isPreTagContent(path)) {
538
- if (((_a = path.getParentNode()) === null || _a === void 0 ? void 0 : _a.type) === 'Attribute') {
539
- return replaceEndOfLineWith(rawText, literalline);
540
- }
541
- return rawText;
542
- }
543
277
  if (isEmptyTextNode(node)) {
544
278
  const hasWhiteSpace = rawText.trim().length < getUnencodedText(node).length;
545
279
  const hasOneOrMoreNewlines = /\n/.test(getUnencodedText(node));
@@ -557,37 +291,20 @@ function print(path, opts, print) {
557
291
  }
558
292
  return fill(splitTextToDocs(node));
559
293
  }
560
- case 'Element':
561
- case 'InlineComponent':
562
- case 'Slot': {
563
- const isEmpty = (_b = node.children) === null || _b === void 0 ? void 0 : _b.every((child) => isEmptyTextNode(child));
564
- const isSelfClosingTag = isEmpty && (node.type !== 'Element' || selfClosingTags.indexOf(node.name) !== -1);
565
- const attributes = path.map(print, 'attributes');
566
- if (isSelfClosingTag) {
567
- return group(['<', node.name, indent(group(attributes)), line, `/>`]);
294
+ case 'component':
295
+ case 'fragment':
296
+ case 'element': {
297
+ let isEmpty;
298
+ if (!node.children) {
299
+ isEmpty = true;
568
300
  }
569
- try {
570
- if (node.name.toLowerCase() === '!doctype') {
571
- const attributesWithLowercaseHTML = attributes.map((attribute) => {
572
- if (typeof attribute === 'string')
573
- return attribute;
574
- if (isDocCommand(attribute))
575
- return attribute;
576
- attribute = attribute.map((attrValue) => {
577
- if (typeof attrValue !== 'string')
578
- return attrValue;
579
- if (attrValue.toLowerCase() === 'html') {
580
- attrValue = attrValue.toLowerCase();
581
- }
582
- return attrValue;
583
- });
584
- return attribute;
585
- });
586
- return group(['<', node.name.toUpperCase(), ...attributesWithLowercaseHTML, `>`]);
587
- }
301
+ else {
302
+ isEmpty = node.children.every((child) => isEmptyTextNode(child));
588
303
  }
589
- catch (e) {
590
- console.warn(`error ${e} in the doctype printing`);
304
+ const isSelfClosingTag = isEmpty && (node.type !== 'element' || selfClosingTags.indexOf(node.name) !== -1);
305
+ const attributes = node.attributes ? path.map(print, 'attributes') : [];
306
+ if (isSelfClosingTag) {
307
+ return group(['<', node.name, indent(group(attributes)), line, `/>`]);
591
308
  }
592
309
  if (node.children) {
593
310
  const children = node.children;
@@ -598,7 +315,6 @@ function print(path, opts, print) {
598
315
  let hugStart = shouldHugStart(node, opts);
599
316
  let hugEnd = shouldHugEnd(node, opts);
600
317
  let body;
601
- const isMarkdownComponent = node.type === 'InlineComponent' && opts.__astro && opts.__astro.markdownName && opts.__astro.markdownName.has(node.name) && isNodeWithChildren(node);
602
318
  if (isEmpty) {
603
319
  body =
604
320
  isInlineElement(path, opts, node) && node.children.length && isTextNodeStartingWithWhitespace(node.children[0]) && !isPreTagContent(path)
@@ -606,15 +322,8 @@ function print(path, opts, print) {
606
322
  :
607
323
  () => softline;
608
324
  }
609
- else if (isMarkdownComponent) {
610
- const text = node.children.map(getUnencodedText).join('').trim();
611
- node.children = [{ start: firstChild.start, end: lastChild.end - 2, type: 'Text', data: text, raw: text, __isRawMarkdown: true }];
612
- body = () => path.map(print, 'children');
613
- hugStart = false;
614
- hugEnd = false;
615
- }
616
325
  else if (isPreTagContent(path)) {
617
- body = () => printRaw(node, opts.originalText);
326
+ body = () => printRaw(node);
618
327
  }
619
328
  else if (isInlineElement(path, opts, node) && !isPreTagContent(path)) {
620
329
  body = () => path.map(print, 'children');
@@ -632,10 +341,6 @@ function print(path, opts, print) {
632
341
  noHugSeparatorStart = '';
633
342
  noHugSeparatorEnd = '';
634
343
  }
635
- else if (isMarkdownComponent) {
636
- noHugSeparatorStart = softline;
637
- noHugSeparatorEnd = softline;
638
- }
639
344
  else {
640
345
  let didSetEndSeparator = false;
641
346
  if (!hugStart && firstChild && isTextNode(firstChild)) {
@@ -651,7 +356,7 @@ function print(path, opts, print) {
651
356
  }
652
357
  if (!hugEnd && lastChild && isTextNode(lastChild)) {
653
358
  if (isInlineElement(path, opts, node) && !didSetEndSeparator) {
654
- noHugSeparatorEnd = line;
359
+ noHugSeparatorEnd = softline;
655
360
  }
656
361
  trimTextNodeRight(lastChild);
657
362
  }
@@ -667,47 +372,35 @@ function print(path, opts, print) {
667
372
  }
668
373
  return group([...openingTag, '>', indent([noHugSeparatorStart, body()]), noHugSeparatorEnd, `</${node.name}>`]);
669
374
  }
375
+ return '';
376
+ }
377
+ case 'attribute': {
378
+ const name = node.name.trim();
379
+ const quote = opts.singleQuote ? "'" : '"';
380
+ switch (node.kind) {
381
+ case 'empty':
382
+ return [line, name];
383
+ case 'expression':
384
+ return '';
385
+ case 'quoted':
386
+ return [line, name, '=', quote, node.value, quote];
387
+ case 'shorthand':
388
+ return [line, '{', name, '}'];
389
+ case 'spread':
390
+ return [line, '{...', name, '}'];
391
+ case 'template-literal':
392
+ return [line, name, '=', '`', node.value, '`'];
393
+ }
394
+ return '';
670
395
  }
671
- case 'AttributeShorthand': {
672
- return node.expression.name;
396
+ case 'directive': {
397
+ return [line, node.name];
673
398
  }
674
- case 'Attribute': {
675
- if (isOrCanBeConvertedToShorthand(node, opts)) {
676
- return [line, '{', node.name, '}'];
677
- }
678
- else {
679
- if (node.value === true) {
680
- return [line, node.name];
681
- }
682
- const quotes = !isLoneMustacheTag(node.value);
683
- const attrNodeValue = printAttributeNodeValue(path, print, quotes, node);
684
- if (quotes) {
685
- return [line, node.name, '=', '"', attrNodeValue, '"'];
686
- }
687
- else {
688
- return [line, node.name, '=', attrNodeValue];
689
- }
690
- }
399
+ case 'doctype': {
400
+ return ['<!DOCTYPE html>', hardline];
691
401
  }
692
- case 'Expression':
693
- return [];
694
- case 'MustacheTag':
695
- return [
696
- '{',
697
- printJS(path, print, 'expression', {
698
- forceSingleLine: isInsideQuotedAttribute(path),
699
- forceSingleQuote: opts.jsxSingleQuote,
700
- }),
701
- '}',
702
- ];
703
- case 'Comment':
402
+ case 'comment':
704
403
  return ['<!--', getUnencodedText(node), '-->'];
705
- case 'CodeSpan':
706
- return getUnencodedText(node);
707
- case 'CodeFence': {
708
- console.debug(node);
709
- return [node.metadata, hardline, node.data, hardline, '```', hardline];
710
- }
711
404
  default: {
712
405
  throw new Error(`Unhandled node type "${node.type}"!`);
713
406
  }
@@ -732,66 +425,62 @@ function splitTextToDocs(node) {
732
425
  return docs;
733
426
  }
734
427
  function expressionParser(text, parsers, opts) {
735
- const ast = parsers.babel(text, parsers, opts);
428
+ const ast = parsers.babel(text, opts);
736
429
  return { ...ast, program: ast.program.body[0].expression };
737
430
  }
431
+ let markdownComponentName = new Set();
738
432
  function embed(path, print, textToDoc, opts) {
739
433
  if (!opts.__astro)
740
434
  opts.__astro = {};
741
435
  const node = path.getValue();
742
436
  if (!node)
743
437
  return null;
744
- if (node.__isRawMarkdown) {
745
- const docs = textToDoc(getUnencodedText(node), { ...opts, parser: 'markdown' });
746
- return stripTrailingHardline(docs);
747
- }
748
- if (node.type === 'Script' && !opts.__astro.markdownName) {
749
- opts.__astro.markdownName = getMarkdownName(node.content);
750
- }
751
- if (node.isJS) {
752
- try {
753
- const embeddedopts = {
754
- parser: expressionParser,
755
- };
756
- if (node.forceSingleQuote) {
757
- embeddedopts.singleQuote = true;
758
- }
759
- const docs = textToDoc(forceIntoExpression(getText(node, opts)), embeddedopts);
760
- return node.forceSingleLine ? removeLines(docs) : docs;
761
- }
762
- catch (e) {
763
- return getText(node, opts);
764
- }
765
- }
766
- if (node.type === 'Script' && node.context === 'setup') {
767
- return group(['---', hardline, textToDoc(node.content, { ...opts, parser: 'typescript' }), '---', hardline]);
768
- }
769
- if (isTextNode(node)) {
770
- const parent = path.getParentNode();
771
- if (parent && parent.type === 'Element' && parent.name === 'script') {
772
- const formatttedScript = textToDoc(node.data, { ...opts, parser: 'typescript' });
773
- if (typeof formatttedScript === 'string')
774
- return formatttedScript;
775
- if (isDocCommand(formatttedScript))
776
- return formatttedScript;
777
- return group(formatttedScript[0]);
778
- }
779
- }
780
- if (node.type === 'Style' || (node.type === 'Element' && node.name === 'style')) {
781
- let styleTagContent = '';
782
- if (node.type === 'Style') {
783
- styleTagContent = node.content.styles;
784
- }
785
- else if (node.children) {
786
- const children = node.children[0];
787
- styleTagContent = getUnencodedText(children);
438
+ if (node.type === 'expression') {
439
+ const textContent = getText(node, opts);
440
+ let content;
441
+ if (node.children.length === 1) {
442
+ content = textContent;
788
443
  }
444
+ else {
445
+ content = textToDoc(textContent, { ...opts, parser: 'babel-ts', semi: false });
446
+ content = stripTrailingHardline(content);
447
+ }
448
+ return [
449
+ '{',
450
+ content,
451
+ '}',
452
+ ];
453
+ }
454
+ if (node.type === 'attribute' && node.kind === 'expression') {
455
+ const value = node.value.trim();
456
+ const name = node.name.trim();
457
+ let attrNodeValue = textToDoc(forceIntoExpression(value), { ...opts, parser: expressionParser, semi: false });
458
+ attrNodeValue = stripTrailingHardline(attrNodeValue);
459
+ if (name === value && opts.astroAllowShorthand) {
460
+ return [line, '{', attrNodeValue, '}'];
461
+ }
462
+ return [line, name, '=', '{', attrNodeValue, '}'];
463
+ }
464
+ if (node.type === 'frontmatter') {
465
+ markdownComponentName = getMarkdownName(node.value);
466
+ return [group(['---', hardline, textToDoc(node.value, { ...opts, parser: 'typescript' }), '---', hardline]), hardline];
467
+ }
468
+ if (node.type === 'element' && node.name === 'script') {
469
+ const scriptContent = node.children[0].value;
470
+ let formatttedScript = textToDoc(scriptContent, { ...opts, parser: 'typescript' });
471
+ formatttedScript = stripTrailingHardline(formatttedScript);
472
+ const attributes = node.attributes ? path.map(print, 'attributes') : [];
473
+ const openingTag = group(['<script', indent(group(attributes)), softline, '>']);
474
+ return [openingTag, indent([hardline, formatttedScript]), hardline, '</script>'];
475
+ }
476
+ if (node.type === 'element' && node.name === 'style') {
477
+ let styleTagContent = node.children[0].value.trim();
789
478
  const supportedStyleLangValues = ['css', 'scss', 'sass'];
790
479
  let parserLang = 'css';
791
- if ('attributes' in node) {
480
+ if (node.attributes) {
792
481
  const langAttribute = node.attributes.filter((x) => x.name === 'lang');
793
482
  if (langAttribute.length) {
794
- const styleLang = langAttribute[0].value[0].raw.toLowerCase();
483
+ const styleLang = langAttribute[0].value.toLowerCase();
795
484
  if (supportedStyleLangValues.includes(styleLang))
796
485
  parserLang = styleLang;
797
486
  }
@@ -800,13 +489,11 @@ function embed(path, print, textToDoc, opts) {
800
489
  case 'css':
801
490
  case 'scss': {
802
491
  let formattedStyles = textToDoc(styleTagContent, { ...opts, parser: parserLang });
803
- if (typeof formattedStyles === 'string')
804
- return formattedStyles;
805
- if (isDocCommand(formattedStyles))
806
- return formattedStyles;
807
- formattedStyles = formattedStyles[0];
808
- const attributes = path.map(print, 'attributes');
809
- const openingTag = group(['<style', indent(group(attributes)), softline, '>']);
492
+ formattedStyles = stripTrailingHardline(formattedStyles);
493
+ const attributes = node.attributes ? path.map(print, 'attributes') : [];
494
+ const directives = node.directives ? path.map(print, 'directives') : [];
495
+ const attrAndDirectives = directives.concat(attributes);
496
+ const openingTag = group(['<style', indent(group(attrAndDirectives)), softline, '>']);
810
497
  return [openingTag, indent([hardline, formattedStyles]), hardline, '</style>'];
811
498
  }
812
499
  case 'sass': {
@@ -816,17 +503,25 @@ function embed(path, print, textToDoc, opts) {
816
503
  insertSpaces: !opts.useTabs,
817
504
  lineEnding,
818
505
  };
819
- const { result: raw } = dedent$1(styleTagContent);
506
+ const { result: raw } = manualDedent(styleTagContent);
820
507
  let formattedSassIndented = sassFormatter.SassFormatter.Format(raw, sassOptions).trim();
821
508
  const formattedSass = join(hardline, formattedSassIndented.split('\n'));
822
- const attributes = path.map(print, 'attributes');
509
+ const attributes = node.attributes ? path.map(print, 'attributes') : [];
823
510
  const openingTag = group(['<style', indent(group(attributes)), softline, '>']);
824
511
  return [openingTag, indent(group([hardline, formattedSass])), hardline, '</style>'];
825
512
  }
826
513
  }
827
514
  }
828
- if (node.__isRawHTML) {
829
- return textToDoc(node.content, { ...opts, parser: 'html' });
515
+ if (node.type === 'component' && markdownComponentName.has(node.name)) {
516
+ let content = printRaw(node);
517
+ content = content.replace(/\r\n/g, '\n');
518
+ const contentArr = content.split('\n').map((s) => s.trimStart());
519
+ content = contentArr.join('\n');
520
+ let formatttedMarkdown = textToDoc(content, { ...opts, parser: 'markdown' });
521
+ formatttedMarkdown = stripTrailingHardline(formatttedMarkdown);
522
+ const attributes = path.map(print, 'attributes');
523
+ const openingTag = group([`<${node.name}`, indent(group(attributes)), softline, '>']);
524
+ return [openingTag, indent(group([hardline, formatttedMarkdown])), hardline, `</${node.name}>`];
830
525
  }
831
526
  return null;
832
527
  }
@@ -844,6 +539,33 @@ const printer = {
844
539
  hasPrettierIgnore,
845
540
  };
846
541
 
542
+ const options = {
543
+ astroSortOrder: {
544
+ since: '0.0.1',
545
+ category: 'Astro',
546
+ type: 'choice',
547
+ default: 'markup | styles',
548
+ description: 'Sort order for markup, scripts, and styles',
549
+ choices: [
550
+ {
551
+ value: 'markup | styles',
552
+ description: 'markup | styles',
553
+ },
554
+ {
555
+ value: 'styles | markup',
556
+ description: 'styles | markup',
557
+ },
558
+ ],
559
+ },
560
+ astroAllowShorthand: {
561
+ since: '0.0.10',
562
+ category: 'Astro',
563
+ type: 'boolean',
564
+ default: true,
565
+ description: 'Enable/disable attribute shorthand if attribute name and expression are the same',
566
+ },
567
+ };
568
+
847
569
  const languages = [
848
570
  {
849
571
  name: 'astro',