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