esrap 1.1.0 → 1.1.1

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/handlers.js +105 -44
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "esrap",
3
- "version": "1.1.0",
3
+ "version": "1.1.1",
4
4
  "description": "Parse in reverse",
5
5
  "repository": {
6
6
  "type": "git",
package/src/handlers.js CHANGED
@@ -30,21 +30,7 @@ export function handle(node, state) {
30
30
  const result = handler(node, state);
31
31
 
32
32
  if (node.leadingComments) {
33
- result.unshift(
34
- c(
35
- node.leadingComments
36
- .map((comment) =>
37
- comment.type === 'Block'
38
- ? `/*${comment.value}*/${
39
- /** @type {any} */ (comment).has_trailing_newline ? `\n${state.indent}` : ` `
40
- }`
41
- : `//${comment.value}${
42
- /** @type {any} */ (comment).has_trailing_newline ? `\n${state.indent}` : ` `
43
- }`
44
- )
45
- .join(``)
46
- )
47
- );
33
+ prepend_comments(result, node.leadingComments, state);
48
34
  }
49
35
 
50
36
  if (node.trailingComments) {
@@ -67,6 +53,29 @@ function c(content, node) {
67
53
  };
68
54
  }
69
55
 
56
+ /**
57
+ * @param {import('./types').Chunk[]} chunks
58
+ * @param {import('estree').Comment[]} comments
59
+ * @param {import('./types').State} state
60
+ */
61
+ function prepend_comments(chunks, comments, state) {
62
+ chunks.unshift(
63
+ c(
64
+ comments
65
+ .map((comment) =>
66
+ comment.type === 'Block'
67
+ ? `/*${comment.value}*/${
68
+ /** @type {any} */ (comment).has_trailing_newline ? `\n${state.indent}` : ` `
69
+ }`
70
+ : `//${comment.value}${
71
+ /** @type {any} */ (comment).has_trailing_newline ? `\n${state.indent}` : ` `
72
+ }`
73
+ )
74
+ .join(``)
75
+ )
76
+ );
77
+ }
78
+
70
79
  const OPERATOR_PRECEDENCE = {
71
80
  '||': 2,
72
81
  '&&': 3,
@@ -235,53 +244,105 @@ const join = (nodes, separator) => {
235
244
  return joined;
236
245
  };
237
246
 
247
+ const grouped_expression_types = [
248
+ 'ImportDeclaration',
249
+ 'VariableDeclaration',
250
+ 'ExportDefaultDeclaration',
251
+ 'ExportNamedDeclaration'
252
+ ];
253
+
238
254
  /**
239
255
  * @param {import('estree').Node[]} nodes
240
256
  * @param {import('./types').State} state
241
257
  */
242
258
  const handle_body = (nodes, state) => {
243
- const chunks = [];
259
+ /** @type {import('./types').Chunk[][][]} */
260
+ const groups = [];
244
261
 
245
- const body = nodes
246
- .filter((statement) => statement.type !== 'EmptyStatement')
247
- .map((statement) => {
248
- const chunks = handle(statement, {
249
- ...state,
250
- indent: state.indent
251
- });
262
+ /** @type {import('./types').Chunk[][]} */
263
+ let group = [];
252
264
 
253
- let add_newline = false;
265
+ let last_statement = /** @type {import('estree').Node} */ ({ type: 'EmptyStatement' });
254
266
 
255
- while (state.comments.length) {
256
- const comment = /** @type {import('estree').Comment} */ (state.comments.shift());
257
- const prefix = add_newline ? `\n${state.indent}` : ` `;
258
-
259
- chunks.push(
260
- c(
261
- comment.type === 'Block'
262
- ? `${prefix}/*${comment.value}*/`
263
- : `${prefix}//${comment.value}`
264
- )
265
- );
267
+ function flush() {
268
+ if (group.length > 0) {
269
+ groups.push(group);
270
+ group = [];
271
+ }
272
+ }
266
273
 
267
- add_newline = comment.type === 'Line';
268
- }
274
+ for (const statement of nodes) {
275
+ if (statement.type === 'EmptyStatement') continue;
269
276
 
270
- return chunks;
277
+ if (
278
+ (grouped_expression_types.includes(statement.type) ||
279
+ grouped_expression_types.includes(last_statement.type)) &&
280
+ last_statement.type !== statement.type
281
+ ) {
282
+ flush();
283
+ }
284
+
285
+ const leadingComments = statement.leadingComments;
286
+ delete statement.leadingComments;
287
+
288
+ const chunks = handle(statement, {
289
+ ...state,
290
+ indent: state.indent
271
291
  });
272
292
 
273
- let needed_padding = false;
293
+ // if a statement requires multiple lines, or it has a leading `/**` comment,
294
+ // we add blank lines around it
295
+ const standalone =
296
+ has_newline(chunks) ||
297
+ (leadingComments?.[0]?.type === 'Block' && leadingComments[0].value.startsWith('*'));
298
+
299
+ if (leadingComments && leadingComments.length > 0) {
300
+ prepend_comments(chunks, leadingComments, state);
301
+ flush();
302
+ }
303
+
304
+ let add_newline = false;
274
305
 
275
- for (let i = 0; i < body.length; i += 1) {
276
- const needs_padding = has_newline(body[i]);
306
+ while (state.comments.length) {
307
+ const comment = /** @type {import('estree').Comment} */ (state.comments.shift());
308
+ const prefix = add_newline ? `\n${state.indent}` : ` `;
309
+
310
+ chunks.push(
311
+ c(
312
+ comment.type === 'Block' ? `${prefix}/*${comment.value}*/` : `${prefix}//${comment.value}`
313
+ )
314
+ );
315
+
316
+ add_newline = comment.type === 'Line';
317
+ }
277
318
 
319
+ if (standalone) {
320
+ flush();
321
+ group.push(chunks);
322
+ flush();
323
+ } else {
324
+ group.push(chunks);
325
+ }
326
+
327
+ last_statement = statement;
328
+ }
329
+
330
+ flush();
331
+
332
+ const chunks = [];
333
+
334
+ for (let i = 0; i < groups.length; i += 1) {
278
335
  if (i > 0) {
279
- chunks.push(c(needs_padding || needed_padding ? `\n\n${state.indent}` : `\n${state.indent}`));
336
+ chunks.push(c(`\n\n${state.indent}`));
280
337
  }
281
338
 
282
- push_array(chunks, body[i]);
339
+ for (let j = 0; j < groups[i].length; j += 1) {
340
+ if (j > 0) {
341
+ chunks.push(c(`\n${state.indent}`));
342
+ }
283
343
 
284
- needed_padding = needs_padding;
344
+ push_array(chunks, groups[i][j]);
345
+ }
285
346
  }
286
347
 
287
348
  return chunks;