espolar 0.4.0 → 0.5.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.d.ts CHANGED
@@ -85,24 +85,29 @@ interface MappingDataOptions<Data> {
85
85
  }
86
86
  type MappingDataUndefinedOptions = { [K in keyof MappingDataOptions<0>]?: undefined };
87
87
  type PrintOptions<Data> = PrintOptionsBase<Data> & ([Data] extends [undefined] ? MappingDataUndefinedOptions : MappingDataOptions<Data>);
88
+ interface WriteNodeOptions {
89
+ noLeadingComment?: boolean;
90
+ noTrailingComment?: boolean;
91
+ }
88
92
  interface PrinterContext<Data = any> {
89
93
  readonly options: PrintOptions<Data>;
90
94
  readonly source: string;
91
95
  readonly generatedOffset: number;
92
96
  write(text: string): void;
93
97
  writeMapped(text: string, sourceStart: number, sourceEnd: number, data?: Data): void;
94
- writeNode(node: AST.Node | null | undefined): void;
98
+ writeNode(node: AST.Node | null | undefined, options?: WriteNodeOptions): void;
95
99
  writeNodeList(nodes: readonly (AST.Node | null)[], separator: string): void;
96
100
  writeExpressionListWithCommaSep(nodes: readonly (AST.Expression | AST.SpreadElement | null)[]): void;
97
101
  /**
98
- * Write `nodes` with "newline" separator, but if the node is ranged and either:
99
- * - it is the first node with `lastRangeEnd` provided, or
100
- * - the previous adjacent node is ranged too,
101
- * Then the source text ranging between the two adjacent nodes will be preserved instead of printing a newline character.
102
+ * Write `nodes` with "newline" separator, but if for node either:
103
+ * - it is the first or the last node, ranged, and `listRange` is also provided,
104
+ * - two adjacent nodes are both ranged,
105
+ * Then the source text ranging between the two adjacent nodes/boundaries will be preserved
106
+ * instead of printing a newline character.
102
107
  * @param nodes
103
108
  * @param lastRangeEnd
104
109
  */
105
- writeNodeListWithNewLineSep(nodes: readonly (AST.ProgramStatement | AST.ClassElement)[], lastRangeEnd?: number): void;
110
+ writeNodeListWithNewLineSep(nodes: readonly (AST.ProgramStatement | AST.ClassElement)[], listRange?: SourceRange): void;
106
111
  writeSource(start: number, end: number, data?: Data): void;
107
112
  writePreservedNode(node: AST.Node): void;
108
113
  appendMapping(sourceRange: SourceRange, generatedStart: number, generatedEnd: number, data?: Data): void;
package/dist/index.js CHANGED
@@ -278,7 +278,12 @@ const defaultPrinters = {
278
278
  TSIntrinsicKeyword: printKeywordType
279
279
  };
280
280
  function printProgram(program, context) {
281
- context.writeNodeListWithNewLineSep(program.body, program.range?.[0]);
281
+ let listRange;
282
+ if (program.range) listRange = {
283
+ start: program.range[0],
284
+ end: program.range[1]
285
+ };
286
+ context.writeNodeListWithNewLineSep(program.body, listRange);
282
287
  }
283
288
  function canStartExpressionStatement(node) {
284
289
  let lhs;
@@ -357,11 +362,12 @@ function printBlockStatement(block, context) {
357
362
  const body = block.body;
358
363
  context.write("{");
359
364
  if (body.length > 0) {
360
- let lastRangeEnd;
361
- if (block.range) lastRangeEnd = block.range[0] + 1;
362
- else context.write("\n");
363
- context.writeNodeListWithNewLineSep(body, lastRangeEnd);
364
- context.write("\n");
365
+ let listRange;
366
+ if (block.range) listRange = {
367
+ start: block.range[0] + 1,
368
+ end: block.range[1] - 1
369
+ };
370
+ context.writeNodeListWithNewLineSep(body, listRange);
365
371
  }
366
372
  context.write("}");
367
373
  }
@@ -879,11 +885,12 @@ function printClassBody(node, context) {
879
885
  context.write("{");
880
886
  const body = node.body;
881
887
  if (body.length > 0) {
882
- let lastRangeEnd;
883
- if (node.range) lastRangeEnd = node.range[0] + 1;
884
- else context.write("\n");
885
- context.writeNodeListWithNewLineSep(body, lastRangeEnd);
886
- context.write("\n");
888
+ let listRange;
889
+ if (node.range) listRange = {
890
+ start: node.range[0] + 1,
891
+ end: node.range[1] - 1
892
+ };
893
+ context.writeNodeListWithNewLineSep(body, listRange);
887
894
  }
888
895
  context.write("}");
889
896
  }
@@ -891,11 +898,12 @@ function printStaticBlock(node, context) {
891
898
  context.write("static {");
892
899
  const body = node.body;
893
900
  if (body.length > 0) {
894
- let lastRangeEnd;
895
- if (node.range) lastRangeEnd = node.range[0] + 1;
896
- else context.write("\n");
897
- context.writeNodeListWithNewLineSep(body, lastRangeEnd);
898
- context.write("\n");
901
+ let listRange;
902
+ if (node.range) listRange = {
903
+ start: node.range[0] + 1,
904
+ end: node.range[1] - 1
905
+ };
906
+ context.writeNodeListWithNewLineSep(body, listRange);
899
907
  }
900
908
  context.write("}");
901
909
  }
@@ -1439,11 +1447,13 @@ function printTSModuleDeclaration(node, context) {
1439
1447
  }
1440
1448
  function printTSModuleBlock(node, context) {
1441
1449
  context.write("{");
1442
- let lastRangeEnd;
1443
- if (node.range) lastRangeEnd = node.range[0] + 1;
1444
- else context.write("\n");
1445
- context.writeNodeListWithNewLineSep(node.body, lastRangeEnd);
1446
- context.write("\n}");
1450
+ let listRange;
1451
+ if (node.range) listRange = {
1452
+ start: node.range[0] + 1,
1453
+ end: node.range[1] - 1
1454
+ };
1455
+ context.writeNodeListWithNewLineSep(node.body, listRange);
1456
+ context.write("}");
1447
1457
  }
1448
1458
  function printTSDeclareFunction(node, context) {
1449
1459
  context.write("declare ");
@@ -1587,6 +1597,7 @@ function createPrinterContext(options) {
1587
1597
  };
1588
1598
  const context = {
1589
1599
  options,
1600
+ _skipLeadingComment: false,
1590
1601
  source: options.source,
1591
1602
  get generatedOffset() {
1592
1603
  return generatedOffset;
@@ -1605,7 +1616,7 @@ function createPrinterContext(options) {
1605
1616
  end: sourceEnd
1606
1617
  }, generatedStart, generatedOffset, data ?? getMappingData(null));
1607
1618
  },
1608
- writeNode(node) {
1619
+ writeNode(node, writeOpt = {}) {
1609
1620
  if (!node) return;
1610
1621
  const range = getNodeRange(node);
1611
1622
  const untouchedRet = isUntouched(node);
@@ -1617,13 +1628,17 @@ function createPrinterContext(options) {
1617
1628
  }
1618
1629
  const printer = printers[node.type];
1619
1630
  if (!printer) throw new Error(`No printer registered for node type ${node.type}`);
1620
- const leadingComments = options.getLeadingComments?.(node);
1621
- if (leadingComments) for (const comment of leadingComments) writeComment(comment, context);
1631
+ if (!writeOpt.noLeadingComment) {
1632
+ const leadingComments = options.getLeadingComments?.(node);
1633
+ if (leadingComments && !context._skipLeadingComment) for (const comment of leadingComments) writeComment(comment, context);
1634
+ }
1622
1635
  const generatedStart = generatedOffset;
1623
1636
  printer(node, context);
1624
1637
  const generatedEnd = generatedOffset;
1625
- const trailingComments = options.getTrailingComments?.(node);
1626
- if (trailingComments) for (const comment of trailingComments) writeComment(comment, context);
1638
+ if (!writeOpt.noTrailingComment) {
1639
+ const trailingComments = options.getTrailingComments?.(node);
1640
+ if (trailingComments) for (const comment of trailingComments) writeComment(comment, context);
1641
+ }
1627
1642
  const lastMappingGeneratedEnd = mappings.at(-1)?.generatedEnd ?? 0;
1628
1643
  if (range && lastMappingGeneratedEnd <= generatedStart) appendMapping(range, generatedStart, generatedEnd, getMappingData(node));
1629
1644
  },
@@ -1655,17 +1670,30 @@ function createPrinterContext(options) {
1655
1670
  needsSeparator = true;
1656
1671
  }
1657
1672
  },
1658
- writeNodeListWithNewLineSep(nodes, lastRangeEnd) {
1659
- let wroteNode = false;
1660
- for (const node of nodes) {
1673
+ writeNodeListWithNewLineSep(nodes, parentRange) {
1674
+ let lastRangeEnd;
1675
+ let trailingSepEnd;
1676
+ if (parentRange) {
1677
+ lastRangeEnd = parentRange.start;
1678
+ trailingSepEnd = parentRange.end;
1679
+ }
1680
+ for (let i = 0; i < nodes.length; i++) {
1681
+ const node = nodes[i];
1661
1682
  const range = getNodeRange(node);
1662
- if (lastRangeEnd !== void 0 && range && range.start >= lastRangeEnd) context.writeSource(lastRangeEnd, range.start, getMappingData(null));
1663
- else if (wroteNode) context.write("\n");
1664
- context.writeNode(node);
1665
- wroteNode = true;
1683
+ let noLeadingComment = false;
1684
+ let noTrailingComment = i < nodes.length - 1 ? true : range !== void 0 && parentRange !== void 0;
1685
+ if (lastRangeEnd !== void 0 && range && range.start >= lastRangeEnd) {
1686
+ context.writeSource(lastRangeEnd, range.start, getMappingData(null));
1687
+ noLeadingComment = true;
1688
+ } else if (i > 0) context.write("\n");
1689
+ context.writeNode(node, {
1690
+ noLeadingComment,
1691
+ noTrailingComment
1692
+ });
1666
1693
  if (range) lastRangeEnd = range.end;
1667
1694
  else lastRangeEnd = void 0;
1668
1695
  }
1696
+ if (trailingSepEnd !== void 0 && lastRangeEnd !== void 0) context.writeSource(lastRangeEnd, trailingSepEnd, getMappingData(null));
1669
1697
  },
1670
1698
  writeSource(start, end, data) {
1671
1699
  if (end < start) return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "espolar",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "type": "module",
5
5
  "types": "./dist/index.d.ts",
6
6
  "exports": {
package/src/api.ts CHANGED
@@ -41,6 +41,11 @@ export type PrintOptions<Data> = PrintOptionsBase<Data> &
41
41
  ? MappingDataUndefinedOptions
42
42
  : MappingDataOptions<Data>);
43
43
 
44
+ export interface WriteNodeOptions {
45
+ noLeadingComment?: boolean;
46
+ noTrailingComment?: boolean;
47
+ }
48
+
44
49
  export interface PrinterContext<Data = any> {
45
50
  readonly options: PrintOptions<Data>;
46
51
  readonly source: string;
@@ -52,22 +57,23 @@ export interface PrinterContext<Data = any> {
52
57
  sourceEnd: number,
53
58
  data?: Data,
54
59
  ): void;
55
- writeNode(node: AST.Node | null | undefined): void;
60
+ writeNode(node: AST.Node | null | undefined, options?: WriteNodeOptions): void;
56
61
  writeNodeList(nodes: readonly (AST.Node | null)[], separator: string): void;
57
62
  writeExpressionListWithCommaSep(
58
63
  nodes: readonly (AST.Expression | AST.SpreadElement | null)[],
59
64
  ): void;
60
65
  /**
61
- * Write `nodes` with "newline" separator, but if the node is ranged and either:
62
- * - it is the first node with `lastRangeEnd` provided, or
63
- * - the previous adjacent node is ranged too,
64
- * Then the source text ranging between the two adjacent nodes will be preserved instead of printing a newline character.
66
+ * Write `nodes` with "newline" separator, but if for node either:
67
+ * - it is the first or the last node, ranged, and `listRange` is also provided,
68
+ * - two adjacent nodes are both ranged,
69
+ * Then the source text ranging between the two adjacent nodes/boundaries will be preserved
70
+ * instead of printing a newline character.
65
71
  * @param nodes
66
72
  * @param lastRangeEnd
67
73
  */
68
74
  writeNodeListWithNewLineSep(
69
75
  nodes: readonly (AST.ProgramStatement | AST.ClassElement)[],
70
- lastRangeEnd?: number,
76
+ listRange?: SourceRange,
71
77
  ): void;
72
78
  writeSource(start: number, end: number, data?: Data): void;
73
79
  writePreservedNode(node: AST.Node): void;
package/src/printer.ts CHANGED
@@ -22,6 +22,7 @@ import {
22
22
  interface InternalPrinterContext extends PrinterContext<any> {
23
23
  // make typescript happy about complex types
24
24
  options: any;
25
+ _skipLeadingComment: boolean;
25
26
  result(): PrintResult<any>;
26
27
  }
27
28
 
@@ -97,6 +98,7 @@ function createPrinterContext<Data>(
97
98
 
98
99
  const context: InternalPrinterContext = {
99
100
  options: options,
101
+ _skipLeadingComment: false,
100
102
  source: options.source,
101
103
  get generatedOffset() {
102
104
  return generatedOffset;
@@ -121,7 +123,7 @@ function createPrinterContext<Data>(
121
123
  data ?? getMappingData(null),
122
124
  );
123
125
  },
124
- writeNode(node) {
126
+ writeNode(node, writeOpt = {}) {
125
127
  if (!node) {
126
128
  return;
127
129
  }
@@ -150,10 +152,12 @@ function createPrinterContext<Data>(
150
152
  throw new Error(`No printer registered for node type ${node.type}`);
151
153
  }
152
154
 
153
- const leadingComments = options.getLeadingComments?.(node);
154
- if (leadingComments) {
155
- for (const comment of leadingComments) {
156
- writeComment(comment, context);
155
+ if (!writeOpt.noLeadingComment) {
156
+ const leadingComments = options.getLeadingComments?.(node);
157
+ if (leadingComments && !context._skipLeadingComment) {
158
+ for (const comment of leadingComments) {
159
+ writeComment(comment, context);
160
+ }
157
161
  }
158
162
  }
159
163
 
@@ -161,12 +165,15 @@ function createPrinterContext<Data>(
161
165
  printer(node, context);
162
166
  const generatedEnd = generatedOffset;
163
167
 
164
- const trailingComments = options.getTrailingComments?.(node);
165
- if (trailingComments) {
166
- for (const comment of trailingComments) {
167
- writeComment(comment, context);
168
+ if (!writeOpt.noTrailingComment) {
169
+ const trailingComments = options.getTrailingComments?.(node);
170
+ if (trailingComments) {
171
+ for (const comment of trailingComments) {
172
+ writeComment(comment, context);
173
+ }
168
174
  }
169
175
  }
176
+
170
177
  // If children nodes don't emit any mapping but the parent node itself
171
178
  // can produce mapping, add that mapping
172
179
  const lastMappingGeneratedEnd = mappings.at(-1)?.generatedEnd ?? 0;
@@ -220,27 +227,44 @@ function createPrinterContext<Data>(
220
227
  needsSeparator = true;
221
228
  }
222
229
  },
223
- writeNodeListWithNewLineSep(nodes, lastRangeEnd) {
224
- let wroteNode = false;
225
- for (const node of nodes) {
230
+ writeNodeListWithNewLineSep(nodes, parentRange) {
231
+ let lastRangeEnd: number | undefined;
232
+ let trailingSepEnd: number | undefined;
233
+ if (parentRange) {
234
+ lastRangeEnd = parentRange.start;
235
+ trailingSepEnd = parentRange.end;
236
+ }
237
+ for (let i = 0; i < nodes.length; i++) {
238
+ const node = nodes[i];
226
239
  const range = getNodeRange(node);
240
+ let noLeadingComment = false;
241
+ let noTrailingComment =
242
+ i < nodes.length - 1
243
+ ? true
244
+ : range !== undefined && parentRange !== undefined;
227
245
  if (
228
246
  lastRangeEnd !== undefined &&
229
247
  range &&
230
248
  range.start >= lastRangeEnd
231
249
  ) {
232
250
  context.writeSource(lastRangeEnd, range.start, getMappingData(null));
233
- } else if (wroteNode) {
251
+ noLeadingComment = true;
252
+ } else if (i > 0) {
234
253
  context.write("\n");
235
254
  }
236
- context.writeNode(node);
237
- wroteNode = true;
255
+ context.writeNode(node, {
256
+ noLeadingComment,
257
+ noTrailingComment,
258
+ });
238
259
  if (range) {
239
260
  lastRangeEnd = range.end;
240
261
  } else {
241
262
  lastRangeEnd = undefined;
242
263
  }
243
264
  }
265
+ if (trailingSepEnd !== undefined && lastRangeEnd !== undefined) {
266
+ context.writeSource(lastRangeEnd, trailingSepEnd, getMappingData(null));
267
+ }
244
268
  },
245
269
  writeSource(start, end, data) {
246
270
  if (end < start) {
package/src/printers.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import type { PrinterContext, Printers } from "./api.ts";
2
+ import type { SourceRange } from "./mappings.ts";
2
3
  import type { AST, AST_NODE_TYPES, Comment } from "./types.ts";
3
4
 
4
5
  /**
@@ -432,7 +433,14 @@ export const defaultPrinters = {
432
433
  // JS – Statements
433
434
 
434
435
  function printProgram(program: AST.Program, context: PrinterContext): void {
435
- context.writeNodeListWithNewLineSep(program.body, program.range?.[0]);
436
+ let listRange: SourceRange | undefined;
437
+ if (program.range) {
438
+ listRange = {
439
+ start: program.range[0],
440
+ end: program.range[1],
441
+ };
442
+ }
443
+ context.writeNodeListWithNewLineSep(program.body, listRange);
436
444
  }
437
445
 
438
446
  function canStartExpressionStatement(
@@ -557,14 +565,14 @@ function printBlockStatement(
557
565
  const body = block.body;
558
566
  context.write("{");
559
567
  if (body.length > 0) {
560
- let lastRangeEnd: number | undefined;
568
+ let listRange: SourceRange | undefined;
561
569
  if (block.range) {
562
- lastRangeEnd = block.range[0] + 1;
563
- } else {
564
- context.write("\n");
570
+ listRange = {
571
+ start: block.range[0] + 1,
572
+ end: block.range[1] - 1,
573
+ };
565
574
  }
566
- context.writeNodeListWithNewLineSep(body, lastRangeEnd);
567
- context.write("\n");
575
+ context.writeNodeListWithNewLineSep(body, listRange);
568
576
  }
569
577
  context.write("}");
570
578
  }
@@ -1477,14 +1485,14 @@ function printClassBody(node: AST.ClassBody, context: PrinterContext): void {
1477
1485
  context.write("{");
1478
1486
  const body = node.body;
1479
1487
  if (body.length > 0) {
1480
- let lastRangeEnd: number | undefined;
1488
+ let listRange: SourceRange | undefined;
1481
1489
  if (node.range) {
1482
- lastRangeEnd = node.range[0] + 1;
1483
- } else {
1484
- context.write("\n");
1490
+ listRange = {
1491
+ start: node.range[0] + 1,
1492
+ end: node.range[1] - 1,
1493
+ };
1485
1494
  }
1486
- context.writeNodeListWithNewLineSep(body, lastRangeEnd);
1487
- context.write("\n");
1495
+ context.writeNodeListWithNewLineSep(body, listRange);
1488
1496
  }
1489
1497
  context.write("}");
1490
1498
  }
@@ -1496,14 +1504,14 @@ function printStaticBlock(
1496
1504
  context.write("static {");
1497
1505
  const body = node.body;
1498
1506
  if (body.length > 0) {
1499
- let lastRangeEnd: number | undefined;
1507
+ let listRange: SourceRange | undefined;
1500
1508
  if (node.range) {
1501
- lastRangeEnd = node.range[0] + 1;
1502
- } else {
1503
- context.write("\n");
1509
+ listRange = {
1510
+ start: node.range[0] + 1,
1511
+ end: node.range[1] - 1,
1512
+ };
1504
1513
  }
1505
- context.writeNodeListWithNewLineSep(body, lastRangeEnd);
1506
- context.write("\n");
1514
+ context.writeNodeListWithNewLineSep(body, listRange);
1507
1515
  }
1508
1516
  context.write("}");
1509
1517
  }
@@ -2543,14 +2551,15 @@ function printTSModuleBlock(
2543
2551
  context: PrinterContext,
2544
2552
  ): void {
2545
2553
  context.write("{");
2546
- let lastRangeEnd: number | undefined;
2554
+ let listRange: SourceRange | undefined;
2547
2555
  if (node.range) {
2548
- lastRangeEnd = node.range[0] + 1;
2549
- } else {
2550
- context.write("\n");
2556
+ listRange = {
2557
+ start: node.range[0] + 1,
2558
+ end: node.range[1] - 1,
2559
+ };
2551
2560
  }
2552
- context.writeNodeListWithNewLineSep(node.body, lastRangeEnd);
2553
- context.write("\n}");
2561
+ context.writeNodeListWithNewLineSep(node.body, listRange);
2562
+ context.write("}");
2554
2563
  }
2555
2564
 
2556
2565
  function printTSDeclareFunction(