@ttsc/factory 0.19.3 → 0.20.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 (56) hide show
  1. package/README.md +2 -0
  2. package/lib/TsPrinter.d.ts +124 -17
  3. package/lib/TsPrinter.js +414 -106
  4. package/lib/TsPrinter.js.map +1 -1
  5. package/lib/TsPrinter.mjs +413 -107
  6. package/lib/TsPrinter.mjs.map +1 -1
  7. package/lib/ast/expressions/Expression.d.ts +5 -1
  8. package/lib/ast/imports/ImportClause.d.ts +10 -2
  9. package/lib/ast/jsdoc/JSDocImportTag.d.ts +3 -0
  10. package/lib/ast/types/ImportTypeNode.d.ts +3 -0
  11. package/lib/factory/expressions/createComma.d.ts +3 -3
  12. package/lib/factory/expressions/createComma.js +3 -3
  13. package/lib/factory/expressions/createComma.mjs +3 -3
  14. package/lib/factory/imports/createImportClause.d.ts +9 -3
  15. package/lib/factory/imports/createImportClause.js +8 -3
  16. package/lib/factory/imports/createImportClause.js.map +1 -1
  17. package/lib/factory/imports/createImportClause.mjs +8 -3
  18. package/lib/factory/imports/createImportClause.mjs.map +1 -1
  19. package/lib/factory/jsdoc/createJSDocImportTag.d.ts +3 -2
  20. package/lib/factory/jsdoc/createJSDocImportTag.js +3 -1
  21. package/lib/factory/jsdoc/createJSDocImportTag.js.map +1 -1
  22. package/lib/factory/jsdoc/createJSDocImportTag.mjs +3 -1
  23. package/lib/factory/jsdoc/createJSDocImportTag.mjs.map +1 -1
  24. package/lib/factory/types/createImportTypeNode.d.ts +8 -2
  25. package/lib/factory/types/createImportTypeNode.js +13 -1
  26. package/lib/factory/types/createImportTypeNode.js.map +1 -1
  27. package/lib/factory/types/createImportTypeNode.mjs +13 -1
  28. package/lib/factory/types/createImportTypeNode.mjs.map +1 -1
  29. package/lib/internal/doc.d.ts +13 -0
  30. package/lib/internal/doc.js +31 -4
  31. package/lib/internal/doc.js.map +1 -1
  32. package/lib/internal/doc.mjs +30 -4
  33. package/lib/internal/doc.mjs.map +1 -1
  34. package/lib/syntax/NodeFlags.d.ts +6 -4
  35. package/lib/syntax/NodeFlags.js +6 -4
  36. package/lib/syntax/NodeFlags.js.map +1 -1
  37. package/lib/syntax/NodeFlags.mjs +6 -4
  38. package/lib/syntax/NodeFlags.mjs.map +1 -1
  39. package/lib/syntax/SyntaxKind.d.ts +2 -0
  40. package/lib/syntax/SyntaxKind.js +6 -0
  41. package/lib/syntax/SyntaxKind.js.map +1 -1
  42. package/lib/syntax/SyntaxKind.mjs +6 -0
  43. package/lib/syntax/SyntaxKind.mjs.map +1 -1
  44. package/package.json +1 -1
  45. package/src/TsPrinter.ts +489 -121
  46. package/src/ast/expressions/Expression.ts +8 -0
  47. package/src/ast/imports/ImportClause.ts +10 -2
  48. package/src/ast/jsdoc/JSDocImportTag.ts +4 -0
  49. package/src/ast/types/ImportTypeNode.ts +4 -0
  50. package/src/factory/expressions/createComma.ts +3 -3
  51. package/src/factory/imports/createImportClause.ts +12 -6
  52. package/src/factory/jsdoc/createJSDocImportTag.ts +5 -1
  53. package/src/factory/types/createImportTypeNode.ts +21 -3
  54. package/src/internal/doc.ts +30 -3
  55. package/src/syntax/NodeFlags.ts +6 -4
  56. package/src/syntax/SyntaxKind.ts +7 -0
package/README.md CHANGED
@@ -89,6 +89,8 @@ factory.createCallExpression(id("foo"), undefined, [a, b]); // foo(a, b)
89
89
  // )
90
90
  ```
91
91
 
92
+ `printWidth` picks a layout, never a meaning. The break-time trailing comma is dropped where it would change the program (after the rest element of a destructuring assignment target, or after an argument-list hole), and it is written in both layouts where it is a value (the hole in `["a", "b", ,]`). JSX children stay on one line whenever a break would delete a whitespace-only child or trim the significant edge space off a text child, so the same tree renders the same text at every width.
93
+
92
94
  ### Comments
93
95
 
94
96
  Attach leading / trailing comments with the legacy `ts.addSyntheticLeadingComment` family. The printer renders them in place — multi-line bodies re-indent with their node, so JSDoc on a nested member stays aligned.
@@ -54,23 +54,82 @@ export declare class TsPrinter {
54
54
  private statementBlock;
55
55
  private typeArguments;
56
56
  /**
57
- * Whether a broken parameter list / binding pattern may append a synthetic
58
- * trailing comma after its last element.
57
+ * Trailing-comma policy for a parameter list or binding pattern.
59
58
  *
60
- * A trailing comma after a rest element (`...rest`) is a syntax error (TS1013
61
- * / V8 `SyntaxError`), and one after a trailing elision (`OmittedExpression`)
62
- * is not cosmetic: `[a, ,]` parses to one more hole than `[a, ]`, so the flat
63
- * and broken layouts of the same node would disagree. Call arguments and
64
- * array / object literals are unaffected a trailing comma after a spread is
65
- * legal there.
59
+ * A comma the printer adds only because a group broke must never change
60
+ * whether the text parses, nor what it parses to. After a rest element
61
+ * (`...rest`) it changes the first: a trailing comma there is a syntax error
62
+ * (TS1013 / V8 `SyntaxError`). After a trailing elision it changes the
63
+ * second: `[a, ,]` has one more hole than `[a, ]`, so the flat and broken
64
+ * layouts of the same node would disagree. A binding pattern is the one place
65
+ * where dropping that hole is lossless, since a trailing hole binds nothing;
66
+ * {@link literalTrailingComma} materializes it instead, because in an array
67
+ * literal the hole is a value.
66
68
  */
67
69
  private listTrailingComma;
70
+ /**
71
+ * Trailing-comma policy for a call or `new` argument list.
72
+ *
73
+ * A trailing `OmittedExpression` prints as nothing, so the list already ends
74
+ * in the separator comma of its last real argument: `f(a, )`, which is what
75
+ * the legacy printer emits too and parses as one argument. Adding the break
76
+ * comma on top produces `f(a, ,)`, which is a syntax error. A trailing spread
77
+ * is unaffected — a comma after it is legal in an argument list.
78
+ */
79
+ private argsTrailingComma;
80
+ /**
81
+ * Trailing-comma policy for an array or object literal.
82
+ *
83
+ * Two positions make the comma load-bearing rather than cosmetic.
84
+ *
85
+ * A trailing elision is a **value**: the comma is the token that materializes
86
+ * the hole, so `["a", ]` has one element and `["a", ,]` has two. The legacy
87
+ * printer emits it in every layout, so this printer emits it in every layout
88
+ * too; leaving it to the break would make the same node mean different things
89
+ * at different widths.
90
+ *
91
+ * A destructuring **assignment target** is the same node kind as an rvalue
92
+ * literal, but ECMAScript forbids a comma after its `AssignmentRestElement` /
93
+ * `AssignmentRestProperty`: `[a, ...rest,] = source` is a syntax error, while
94
+ * the identical rvalue `[a, ...rest,]` is legal. Only the target position
95
+ * suppresses it, so the rvalue twin keeps its break comma.
96
+ */
97
+ private literalTrailingComma;
68
98
  private params;
69
99
  private args;
70
100
  private modifiers;
71
101
  private heritage;
102
+ /**
103
+ * Lay out a JSX element's or fragment's children.
104
+ *
105
+ * A line break between JSX children is not cosmetic. JSX deletes a
106
+ * whitespace-only text child that contains a newline and trims
107
+ * whitespace-carrying-a-newline off both edges of every other text child, so
108
+ * a break introduced only because the group did not fit changes what the
109
+ * component renders: `<div>Hello there, {name}!</div>` becomes `Hello
110
+ * there,NAME!`, and the separator in `<div>{a} {b}</div>` disappears
111
+ * outright.
112
+ *
113
+ * Children are therefore laid out across lines only when the break survives
114
+ * that transformation unchanged: every text child must carry non-whitespace
115
+ * content, must not begin or end with whitespace, and must not sit next to
116
+ * another text child, since inserting a newline between two of them would
117
+ * merge into one text with a space in the middle. Otherwise the children are
118
+ * emitted verbatim on one line, whatever `printWidth` says — width may choose
119
+ * a layout, never a meaning.
120
+ */
121
+ private jsxChildren;
122
+ private jsxChildrenMayBreak;
72
123
  private optType;
73
124
  private optBody;
125
+ /**
126
+ * @param assignmentTarget Whether `node` occupies destructuring
127
+ * assignment-target position, where an array or object literal is a pattern
128
+ * rather than a value. The flag is set by the assignment and `for…in` /
129
+ * `for…of` cases, forwarded by every node that is transparent to it (a
130
+ * spread, a property's initializer, a parenthesis, an `=` default), and
131
+ * dropped by every other node.
132
+ */
74
133
  private emit;
75
134
  /** Render a leading comment followed by its node separator. */
76
135
  private leadingComment;
@@ -85,21 +144,66 @@ export declare class TsPrinter {
85
144
  * re-associate — matching the legacy printer's parenthesizer rules.
86
145
  */
87
146
  private parenthesizedExpression;
147
+ /**
148
+ * The partial-emission wrapper carries transform provenance but emits no
149
+ * syntax of its own, so every grammar predicate must inspect its inner node.
150
+ */
151
+ private skipPartiallyEmittedExpressions;
88
152
  private expressionForDisallowedComma;
153
+ /**
154
+ * Emit an operand the grammar requires to be a `LeftHandSideExpression`,
155
+ * mirroring the legacy parenthesizer's
156
+ * `parenthesizeLeftSideOfAccess(expression, optionalChain)`.
157
+ *
158
+ * `optionalChain` is the **consuming** node's own chain-ness, not the
159
+ * operand's. An optional chain may be emitted bare only when the node
160
+ * consuming it continues the same chain: `a?.b?.()` is one chain, while
161
+ * `(a?.b)()` is a plain call on the chain's value. Emitting the second as
162
+ * `a?.b()` re-parses as the first, which stops throwing on a nullish head,
163
+ * and in `new`, tagged-template and decorator position it does not compile at
164
+ * all.
165
+ */
89
166
  private leftSideExpression;
167
+ /**
168
+ * Whether {@link leftSideExpression} wraps this operand.
169
+ *
170
+ * The legacy rule also parenthesizes an argument-less `new` here, because it
171
+ * prints `new X` bare and `new X.y` would re-parse with `y` on the target.
172
+ * This printer always emits the argument list, so `new X().y` already says
173
+ * what the tree says and needs no wrapper.
174
+ */
175
+ private leftSideNeedsParentheses;
176
+ private isOptionalChain;
90
177
  private newExpressionTarget;
91
178
  /**
92
179
  * Whether a `new` target must be parenthesized to keep its call arguments
93
180
  * from re-binding to the `new` — mirroring the legacy printer's
94
181
  * `parenthesizeExpressionOfNew`. A `new` target is grammatically a
95
- * `MemberExpression`, so a call anywhere on the target's left spine (not just
96
- * a direct one: `new (f().bar)()`, `new (a.b().c)()`) would otherwise
97
- * re-parse with the call's arguments consumed by the `new` — a different
98
- * program. Argument-less `new` on the spine is kept parenthesized for
99
- * continuity with the direct case, though this printer always prints an
100
- * argument list, which already disambiguates it.
182
+ * `MemberExpression`, so a call anywhere on the target's printed left spine
183
+ * (not just a direct one: `new (f().bar)()`, `new (a.b().c)()`) would
184
+ * otherwise re-parse with the call's arguments consumed by the `new` — a
185
+ * different program. Argument-less `new` on the spine is kept parenthesized
186
+ * for continuity with the direct case, though this printer always prints an
187
+ * argument list, which already disambiguates it. Anything else falls back to
188
+ * the shared left-side rule, which is what parenthesizes an optional-chain
189
+ * target (`new (a?.b)()`, TS1209 without it).
101
190
  */
102
191
  private newExpressionTargetNeedsParentheses;
192
+ /**
193
+ * The node whose own text opens `expression`'s printed form, or `undefined`
194
+ * when that text opens with a printer-inserted `(`.
195
+ *
196
+ * The legacy factory parenthesizes each operand as it builds the node, so its
197
+ * `getLeftmostExpression` walk halts on the resulting
198
+ * `ParenthesizedExpression`. This printer decides the same parentheses at
199
+ * emit time instead, so the walk has to ask {@link leftSideNeedsParentheses}
200
+ * the same question directly; otherwise `new` re-wraps a target whose call is
201
+ * already behind parentheses, and `new (f?.()).bar()` comes out as `new
202
+ * ((f?.()).bar)()`. Calls halt the walk, matching the legacy
203
+ * `stopAtCallExpressions` mode this predicate is the only user of.
204
+ */
205
+ private leftmostPrintedExpression;
206
+ private leftmostPrintedLeftSide;
103
207
  private prefixUnaryOperand;
104
208
  private postfixUnaryOperand;
105
209
  private conditionalCondition;
@@ -124,9 +228,12 @@ export declare class TsPrinter {
124
228
  private expressionNeedsExportDefaultParentheses;
125
229
  /**
126
230
  * Walk to the expression's leftmost node — the one that starts its printed
127
- * text. With `stopAtCall`, calls terminate the walk instead of being walked
128
- * through, matching the legacy `getLeftmostExpression`'s
129
- * `stopAtCallExpressions` mode used by the `new`-target parenthesizer.
231
+ * text matching the legacy `getLeftmostExpression`.
232
+ *
233
+ * Used by the statement, concise-body and export-default predicates, which
234
+ * ask only whether the text opens with a `function`, `class` or `{` token.
235
+ * The `new`-target predicate needs the printed left edge instead and uses
236
+ * {@link leftmostPrintedExpression}.
130
237
  */
131
238
  private leftmostExpression;
132
239
  private needsPrefixUnaryGap;