@ttsc/factory 0.18.4 → 0.19.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.
- package/lib/TsPrinter.d.ts +30 -0
- package/lib/TsPrinter.js +90 -24
- package/lib/TsPrinter.js.map +1 -1
- package/lib/TsPrinter.mjs +90 -24
- package/lib/TsPrinter.mjs.map +1 -1
- package/lib/ast/expressions/NoSubstitutionTemplateLiteral.d.ts +2 -0
- package/lib/ast/expressions/TemplateMiddle.d.ts +2 -0
- package/lib/ast/expressions/TemplateTail.d.ts +2 -0
- package/lib/factory/literals/createNoSubstitutionTemplateLiteral.d.ts +7 -4
- package/lib/factory/literals/createNoSubstitutionTemplateLiteral.js +7 -4
- package/lib/factory/literals/createNoSubstitutionTemplateLiteral.js.map +1 -1
- package/lib/factory/literals/createNoSubstitutionTemplateLiteral.mjs +7 -4
- package/lib/factory/literals/createNoSubstitutionTemplateLiteral.mjs.map +1 -1
- package/lib/factory/literals/createTemplateHead.d.ts +4 -3
- package/lib/factory/literals/createTemplateHead.js +4 -3
- package/lib/factory/literals/createTemplateHead.js.map +1 -1
- package/lib/factory/literals/createTemplateHead.mjs +4 -3
- package/lib/factory/literals/createTemplateHead.mjs.map +1 -1
- package/lib/factory/literals/createTemplateMiddle.d.ts +8 -4
- package/lib/factory/literals/createTemplateMiddle.js +8 -4
- package/lib/factory/literals/createTemplateMiddle.js.map +1 -1
- package/lib/factory/literals/createTemplateMiddle.mjs +8 -4
- package/lib/factory/literals/createTemplateMiddle.mjs.map +1 -1
- package/lib/factory/literals/createTemplateTail.d.ts +8 -4
- package/lib/factory/literals/createTemplateTail.js +8 -4
- package/lib/factory/literals/createTemplateTail.js.map +1 -1
- package/lib/factory/literals/createTemplateTail.mjs +8 -4
- package/lib/factory/literals/createTemplateTail.mjs.map +1 -1
- package/package.json +1 -1
- package/src/TsPrinter.ts +97 -26
- package/src/ast/expressions/NoSubstitutionTemplateLiteral.ts +3 -0
- package/src/ast/expressions/TemplateMiddle.ts +3 -0
- package/src/ast/expressions/TemplateTail.ts +3 -0
- package/src/factory/literals/createNoSubstitutionTemplateLiteral.ts +8 -4
- package/src/factory/literals/createTemplateHead.ts +4 -3
- package/src/factory/literals/createTemplateMiddle.ts +11 -5
- package/src/factory/literals/createTemplateTail.ts +11 -5
|
@@ -7,9 +7,10 @@ const make_1 = require("../internal/make");
|
|
|
7
7
|
* the leading backtick up to the first `${`.
|
|
8
8
|
*
|
|
9
9
|
* The `text` is the cooked content of that span. The optional `rawText` carries
|
|
10
|
-
* the source spelling before escape processing;
|
|
11
|
-
*
|
|
12
|
-
*
|
|
10
|
+
* the source spelling before escape processing; the printer emits it verbatim
|
|
11
|
+
* when present, and otherwise escapes the cooked `text` so it re-parses to the
|
|
12
|
+
* same value. A head is not a complete expression on its own, it is one piece
|
|
13
|
+
* of a larger template literal.
|
|
13
14
|
*
|
|
14
15
|
* The printer emits the opening backtick, the content, then the `${` that opens
|
|
15
16
|
* the first substitution. With `text` of `head`, this prints:
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createTemplateHead.js","sourceRoot":"","sources":["../../../src/factory/literals/createTemplateHead.ts"],"names":[],"mappings":";;;AACA,2CAAwC;AAExC
|
|
1
|
+
{"version":3,"file":"createTemplateHead.js","sourceRoot":"","sources":["../../../src/factory/literals/createTemplateHead.ts"],"names":[],"mappings":";;;AACA,2CAAwC;AAExC;;;;;;;;;;;;;;;;;;;;;GAqBG;AACI,MAAM,kBAAkB,GAAG,CAChC,IAAY,EACZ,OAAgB,EACF,EAAE,CAAC,IAAA,WAAI,EAAC,cAAc,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;AAH9C,QAAA,kBAAkB,GAAlB,kBAAkB,CAG4B"}
|
|
@@ -5,9 +5,10 @@ import { make } from '../internal/make.mjs';
|
|
|
5
5
|
* the leading backtick up to the first `${`.
|
|
6
6
|
*
|
|
7
7
|
* The `text` is the cooked content of that span. The optional `rawText` carries
|
|
8
|
-
* the source spelling before escape processing;
|
|
9
|
-
*
|
|
10
|
-
*
|
|
8
|
+
* the source spelling before escape processing; the printer emits it verbatim
|
|
9
|
+
* when present, and otherwise escapes the cooked `text` so it re-parses to the
|
|
10
|
+
* same value. A head is not a complete expression on its own, it is one piece
|
|
11
|
+
* of a larger template literal.
|
|
11
12
|
*
|
|
12
13
|
* The printer emits the opening backtick, the content, then the `${` that opens
|
|
13
14
|
* the first substitution. With `text` of `head`, this prints:
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createTemplateHead.mjs","sources":["../../../src/factory/literals/createTemplateHead.ts"],"sourcesContent":[null],"names":[],"mappings":";;AAGA
|
|
1
|
+
{"version":3,"file":"createTemplateHead.mjs","sources":["../../../src/factory/literals/createTemplateHead.ts"],"sourcesContent":[null],"names":[],"mappings":";;AAGA;;;;;;;;;;;;;;;;;;;;;AAqBG;MACU,kBAAkB,GAAG,CAChC,IAAY,EACZ,OAAgB,KACC,IAAI,CAAC,cAAc,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE;;;;"}
|
|
@@ -3,9 +3,12 @@ import type { TemplateMiddle } from "../../ast";
|
|
|
3
3
|
* Create a {@link TemplateMiddle}: a span of a template expression that sits
|
|
4
4
|
* between two substitutions, from one `}` to the next `${`.
|
|
5
5
|
*
|
|
6
|
-
* The `text` is the cooked content of that span.
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
* The `text` is the cooked content of that span. The optional `rawText` carries
|
|
7
|
+
* the source spelling before escape processing; the printer emits it verbatim
|
|
8
|
+
* when present, and otherwise escapes the cooked `text` so it re-parses to the
|
|
9
|
+
* same value. A middle span only appears in a template literal that has two or
|
|
10
|
+
* more substitutions, and it is one piece of that larger literal rather than a
|
|
11
|
+
* complete expression.
|
|
9
12
|
*
|
|
10
13
|
* The printer emits the closing `}` of the preceding substitution, the content,
|
|
11
14
|
* then the `${` that opens the next one. With `text` of `mid`, this prints:
|
|
@@ -16,6 +19,7 @@ import type { TemplateMiddle } from "../../ast";
|
|
|
16
19
|
*
|
|
17
20
|
* @author Jeongho Nam - https://github.com/samchon
|
|
18
21
|
* @param text The text.
|
|
22
|
+
* @param rawText The rawText.
|
|
19
23
|
* @returns The created node.
|
|
20
24
|
*/
|
|
21
|
-
export declare const createTemplateMiddle: (text: string) => TemplateMiddle;
|
|
25
|
+
export declare const createTemplateMiddle: (text: string, rawText?: string) => TemplateMiddle;
|
|
@@ -6,9 +6,12 @@ const make_1 = require("../internal/make");
|
|
|
6
6
|
* Create a {@link TemplateMiddle}: a span of a template expression that sits
|
|
7
7
|
* between two substitutions, from one `}` to the next `${`.
|
|
8
8
|
*
|
|
9
|
-
* The `text` is the cooked content of that span.
|
|
10
|
-
*
|
|
11
|
-
*
|
|
9
|
+
* The `text` is the cooked content of that span. The optional `rawText` carries
|
|
10
|
+
* the source spelling before escape processing; the printer emits it verbatim
|
|
11
|
+
* when present, and otherwise escapes the cooked `text` so it re-parses to the
|
|
12
|
+
* same value. A middle span only appears in a template literal that has two or
|
|
13
|
+
* more substitutions, and it is one piece of that larger literal rather than a
|
|
14
|
+
* complete expression.
|
|
12
15
|
*
|
|
13
16
|
* The printer emits the closing `}` of the preceding substitution, the content,
|
|
14
17
|
* then the `${` that opens the next one. With `text` of `mid`, this prints:
|
|
@@ -19,8 +22,9 @@ const make_1 = require("../internal/make");
|
|
|
19
22
|
*
|
|
20
23
|
* @author Jeongho Nam - https://github.com/samchon
|
|
21
24
|
* @param text The text.
|
|
25
|
+
* @param rawText The rawText.
|
|
22
26
|
* @returns The created node.
|
|
23
27
|
*/
|
|
24
|
-
const createTemplateMiddle = (text) => (0, make_1.make)("TemplateMiddle", { text });
|
|
28
|
+
const createTemplateMiddle = (text, rawText) => (0, make_1.make)("TemplateMiddle", { text, rawText });
|
|
25
29
|
exports.createTemplateMiddle = createTemplateMiddle;
|
|
26
30
|
//# sourceMappingURL=createTemplateMiddle.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createTemplateMiddle.js","sourceRoot":"","sources":["../../../src/factory/literals/createTemplateMiddle.ts"],"names":[],"mappings":";;;AACA,2CAAwC;AAExC
|
|
1
|
+
{"version":3,"file":"createTemplateMiddle.js","sourceRoot":"","sources":["../../../src/factory/literals/createTemplateMiddle.ts"],"names":[],"mappings":";;;AACA,2CAAwC;AAExC;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACI,MAAM,oBAAoB,GAAG,CAClC,IAAY,EACZ,OAAgB,EACA,EAAE,CAAC,IAAA,WAAI,EAAC,gBAAgB,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;AAHlD,QAAA,oBAAoB,GAApB,oBAAoB,CAG8B"}
|
|
@@ -4,9 +4,12 @@ import { make } from '../internal/make.mjs';
|
|
|
4
4
|
* Create a {@link TemplateMiddle}: a span of a template expression that sits
|
|
5
5
|
* between two substitutions, from one `}` to the next `${`.
|
|
6
6
|
*
|
|
7
|
-
* The `text` is the cooked content of that span.
|
|
8
|
-
*
|
|
9
|
-
*
|
|
7
|
+
* The `text` is the cooked content of that span. The optional `rawText` carries
|
|
8
|
+
* the source spelling before escape processing; the printer emits it verbatim
|
|
9
|
+
* when present, and otherwise escapes the cooked `text` so it re-parses to the
|
|
10
|
+
* same value. A middle span only appears in a template literal that has two or
|
|
11
|
+
* more substitutions, and it is one piece of that larger literal rather than a
|
|
12
|
+
* complete expression.
|
|
10
13
|
*
|
|
11
14
|
* The printer emits the closing `}` of the preceding substitution, the content,
|
|
12
15
|
* then the `${` that opens the next one. With `text` of `mid`, this prints:
|
|
@@ -17,9 +20,10 @@ import { make } from '../internal/make.mjs';
|
|
|
17
20
|
*
|
|
18
21
|
* @author Jeongho Nam - https://github.com/samchon
|
|
19
22
|
* @param text The text.
|
|
23
|
+
* @param rawText The rawText.
|
|
20
24
|
* @returns The created node.
|
|
21
25
|
*/
|
|
22
|
-
const createTemplateMiddle = (text) => make("TemplateMiddle", { text });
|
|
26
|
+
const createTemplateMiddle = (text, rawText) => make("TemplateMiddle", { text, rawText });
|
|
23
27
|
|
|
24
28
|
export { createTemplateMiddle };
|
|
25
29
|
//# sourceMappingURL=createTemplateMiddle.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createTemplateMiddle.mjs","sources":["../../../src/factory/literals/createTemplateMiddle.ts"],"sourcesContent":[null],"names":[],"mappings":";;AAGA
|
|
1
|
+
{"version":3,"file":"createTemplateMiddle.mjs","sources":["../../../src/factory/literals/createTemplateMiddle.ts"],"sourcesContent":[null],"names":[],"mappings":";;AAGA;;;;;;;;;;;;;;;;;;;;;;AAsBG;MACU,oBAAoB,GAAG,CAClC,IAAY,EACZ,OAAgB,KACG,IAAI,CAAC,gBAAgB,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE;;;;"}
|
|
@@ -3,9 +3,12 @@ import type { TemplateTail } from "../../ast";
|
|
|
3
3
|
* Create a {@link TemplateTail}: the closing span of a template expression, from
|
|
4
4
|
* the last `}` to the trailing backtick.
|
|
5
5
|
*
|
|
6
|
-
* The `text` is the cooked content of that span.
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
* The `text` is the cooked content of that span. The optional `rawText` carries
|
|
7
|
+
* the source spelling before escape processing; the printer emits it verbatim
|
|
8
|
+
* when present, and otherwise escapes the cooked `text` so it re-parses to the
|
|
9
|
+
* same value. A tail closes a template literal that has at least one
|
|
10
|
+
* substitution, and it is one piece of that larger literal rather than a
|
|
11
|
+
* complete expression.
|
|
9
12
|
*
|
|
10
13
|
* The printer emits the closing `}` of the final substitution, the content,
|
|
11
14
|
* then the trailing backtick. With `text` of `tail`, this prints:
|
|
@@ -16,6 +19,7 @@ import type { TemplateTail } from "../../ast";
|
|
|
16
19
|
*
|
|
17
20
|
* @author Jeongho Nam - https://github.com/samchon
|
|
18
21
|
* @param text The text.
|
|
22
|
+
* @param rawText The rawText.
|
|
19
23
|
* @returns The created node.
|
|
20
24
|
*/
|
|
21
|
-
export declare const createTemplateTail: (text: string) => TemplateTail;
|
|
25
|
+
export declare const createTemplateTail: (text: string, rawText?: string) => TemplateTail;
|
|
@@ -6,9 +6,12 @@ const make_1 = require("../internal/make");
|
|
|
6
6
|
* Create a {@link TemplateTail}: the closing span of a template expression, from
|
|
7
7
|
* the last `}` to the trailing backtick.
|
|
8
8
|
*
|
|
9
|
-
* The `text` is the cooked content of that span.
|
|
10
|
-
*
|
|
11
|
-
*
|
|
9
|
+
* The `text` is the cooked content of that span. The optional `rawText` carries
|
|
10
|
+
* the source spelling before escape processing; the printer emits it verbatim
|
|
11
|
+
* when present, and otherwise escapes the cooked `text` so it re-parses to the
|
|
12
|
+
* same value. A tail closes a template literal that has at least one
|
|
13
|
+
* substitution, and it is one piece of that larger literal rather than a
|
|
14
|
+
* complete expression.
|
|
12
15
|
*
|
|
13
16
|
* The printer emits the closing `}` of the final substitution, the content,
|
|
14
17
|
* then the trailing backtick. With `text` of `tail`, this prints:
|
|
@@ -19,8 +22,9 @@ const make_1 = require("../internal/make");
|
|
|
19
22
|
*
|
|
20
23
|
* @author Jeongho Nam - https://github.com/samchon
|
|
21
24
|
* @param text The text.
|
|
25
|
+
* @param rawText The rawText.
|
|
22
26
|
* @returns The created node.
|
|
23
27
|
*/
|
|
24
|
-
const createTemplateTail = (text) => (0, make_1.make)("TemplateTail", { text });
|
|
28
|
+
const createTemplateTail = (text, rawText) => (0, make_1.make)("TemplateTail", { text, rawText });
|
|
25
29
|
exports.createTemplateTail = createTemplateTail;
|
|
26
30
|
//# sourceMappingURL=createTemplateTail.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createTemplateTail.js","sourceRoot":"","sources":["../../../src/factory/literals/createTemplateTail.ts"],"names":[],"mappings":";;;AACA,2CAAwC;AAExC
|
|
1
|
+
{"version":3,"file":"createTemplateTail.js","sourceRoot":"","sources":["../../../src/factory/literals/createTemplateTail.ts"],"names":[],"mappings":";;;AACA,2CAAwC;AAExC;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACI,MAAM,kBAAkB,GAAG,CAChC,IAAY,EACZ,OAAgB,EACF,EAAE,CAAC,IAAA,WAAI,EAAC,cAAc,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;AAH9C,QAAA,kBAAkB,GAAlB,kBAAkB,CAG4B"}
|
|
@@ -4,9 +4,12 @@ import { make } from '../internal/make.mjs';
|
|
|
4
4
|
* Create a {@link TemplateTail}: the closing span of a template expression, from
|
|
5
5
|
* the last `}` to the trailing backtick.
|
|
6
6
|
*
|
|
7
|
-
* The `text` is the cooked content of that span.
|
|
8
|
-
*
|
|
9
|
-
*
|
|
7
|
+
* The `text` is the cooked content of that span. The optional `rawText` carries
|
|
8
|
+
* the source spelling before escape processing; the printer emits it verbatim
|
|
9
|
+
* when present, and otherwise escapes the cooked `text` so it re-parses to the
|
|
10
|
+
* same value. A tail closes a template literal that has at least one
|
|
11
|
+
* substitution, and it is one piece of that larger literal rather than a
|
|
12
|
+
* complete expression.
|
|
10
13
|
*
|
|
11
14
|
* The printer emits the closing `}` of the final substitution, the content,
|
|
12
15
|
* then the trailing backtick. With `text` of `tail`, this prints:
|
|
@@ -17,9 +20,10 @@ import { make } from '../internal/make.mjs';
|
|
|
17
20
|
*
|
|
18
21
|
* @author Jeongho Nam - https://github.com/samchon
|
|
19
22
|
* @param text The text.
|
|
23
|
+
* @param rawText The rawText.
|
|
20
24
|
* @returns The created node.
|
|
21
25
|
*/
|
|
22
|
-
const createTemplateTail = (text) => make("TemplateTail", { text });
|
|
26
|
+
const createTemplateTail = (text, rawText) => make("TemplateTail", { text, rawText });
|
|
23
27
|
|
|
24
28
|
export { createTemplateTail };
|
|
25
29
|
//# sourceMappingURL=createTemplateTail.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createTemplateTail.mjs","sources":["../../../src/factory/literals/createTemplateTail.ts"],"sourcesContent":[null],"names":[],"mappings":";;AAGA
|
|
1
|
+
{"version":3,"file":"createTemplateTail.mjs","sources":["../../../src/factory/literals/createTemplateTail.ts"],"sourcesContent":[null],"names":[],"mappings":";;AAGA;;;;;;;;;;;;;;;;;;;;;;AAsBG;MACU,kBAAkB,GAAG,CAChC,IAAY,EACZ,OAAgB,KACC,IAAI,CAAC,cAAc,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE;;;;"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ttsc/factory",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.19.1",
|
|
4
4
|
"description": "Self-contained legacy-style TypeScript AST factory and printer for source code generation, surviving the TypeScript-Go (tsgo) migration. Zero dependencies, no `typescript` import.",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"exports": {
|
package/src/TsPrinter.ts
CHANGED
|
@@ -197,13 +197,31 @@ export class TsPrinter {
|
|
|
197
197
|
: "";
|
|
198
198
|
}
|
|
199
199
|
|
|
200
|
+
/**
|
|
201
|
+
* Whether a broken parameter list / binding pattern may append a synthetic
|
|
202
|
+
* trailing comma after its last element.
|
|
203
|
+
*
|
|
204
|
+
* A trailing comma after a rest element (`...rest`) is a syntax error (TS1013
|
|
205
|
+
* / V8 `SyntaxError`), and one after a trailing elision (`OmittedExpression`)
|
|
206
|
+
* is not cosmetic: `[a, ,]` parses to one more hole than `[a, ]`, so the flat
|
|
207
|
+
* and broken layouts of the same node would disagree. Call arguments and
|
|
208
|
+
* array / object literals are unaffected — a trailing comma after a spread is
|
|
209
|
+
* legal there.
|
|
210
|
+
*/
|
|
211
|
+
private listTrailingComma(nodes: readonly Node[]): boolean {
|
|
212
|
+
const last: Node | undefined = nodes[nodes.length - 1];
|
|
213
|
+
if (last === undefined) return true;
|
|
214
|
+
if (last.kind === "OmittedExpression") return false;
|
|
215
|
+
return !("dotDotDotToken" in last && last.dotDotDotToken !== undefined);
|
|
216
|
+
}
|
|
217
|
+
|
|
200
218
|
private params(params: readonly Node[]): Doc {
|
|
201
219
|
return this.delim(
|
|
202
220
|
"(",
|
|
203
221
|
params.map((p) => this.emit(p)),
|
|
204
222
|
")",
|
|
205
223
|
{
|
|
206
|
-
trailingComma:
|
|
224
|
+
trailingComma: this.listTrailingComma(params),
|
|
207
225
|
},
|
|
208
226
|
);
|
|
209
227
|
}
|
|
@@ -1156,13 +1174,13 @@ export class TsPrinter {
|
|
|
1156
1174
|
|
|
1157
1175
|
/* template literals */
|
|
1158
1176
|
case "TemplateHead":
|
|
1159
|
-
return concat(["`", node
|
|
1177
|
+
return concat(["`", templateText(node), "${"]);
|
|
1160
1178
|
case "TemplateMiddle":
|
|
1161
|
-
return concat(["}", node
|
|
1179
|
+
return concat(["}", templateText(node), "${"]);
|
|
1162
1180
|
case "TemplateTail":
|
|
1163
|
-
return concat(["}", node
|
|
1181
|
+
return concat(["}", templateText(node), "`"]);
|
|
1164
1182
|
case "NoSubstitutionTemplateLiteral":
|
|
1165
|
-
return concat(["`", node
|
|
1183
|
+
return concat(["`", templateText(node), "`"]);
|
|
1166
1184
|
|
|
1167
1185
|
/* template & misc expressions */
|
|
1168
1186
|
case "TemplateExpression":
|
|
@@ -1237,14 +1255,17 @@ export class TsPrinter {
|
|
|
1237
1255
|
"{",
|
|
1238
1256
|
node.elements.map((e) => this.emit(e)),
|
|
1239
1257
|
"}",
|
|
1240
|
-
{
|
|
1258
|
+
{
|
|
1259
|
+
space: true,
|
|
1260
|
+
trailingComma: this.listTrailingComma(node.elements),
|
|
1261
|
+
},
|
|
1241
1262
|
);
|
|
1242
1263
|
case "ArrayBindingPattern":
|
|
1243
1264
|
return this.delim(
|
|
1244
1265
|
"[",
|
|
1245
1266
|
node.elements.map((e) => this.emit(e)),
|
|
1246
1267
|
"]",
|
|
1247
|
-
{ trailingComma:
|
|
1268
|
+
{ trailingComma: this.listTrailingComma(node.elements) },
|
|
1248
1269
|
);
|
|
1249
1270
|
case "TypeAssertion":
|
|
1250
1271
|
return concat([
|
|
@@ -1618,13 +1639,30 @@ export class TsPrinter {
|
|
|
1618
1639
|
}
|
|
1619
1640
|
|
|
1620
1641
|
private newExpressionTarget(expression: Expression): Doc {
|
|
1621
|
-
return expression
|
|
1622
|
-
expression
|
|
1623
|
-
(expression
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1642
|
+
return this.newExpressionTargetNeedsParentheses(expression)
|
|
1643
|
+
? this.parenthesizedExpression(expression)
|
|
1644
|
+
: this.emit(expression);
|
|
1645
|
+
}
|
|
1646
|
+
|
|
1647
|
+
/**
|
|
1648
|
+
* Whether a `new` target must be parenthesized to keep its call arguments
|
|
1649
|
+
* from re-binding to the `new` — mirroring the legacy printer's
|
|
1650
|
+
* `parenthesizeExpressionOfNew`. A `new` target is grammatically a
|
|
1651
|
+
* `MemberExpression`, so a call anywhere on the target's left spine (not just
|
|
1652
|
+
* a direct one: `new (f().bar)()`, `new (a.b().c)()`) would otherwise
|
|
1653
|
+
* re-parse with the call's arguments consumed by the `new` — a different
|
|
1654
|
+
* program. Argument-less `new` on the spine is kept parenthesized for
|
|
1655
|
+
* continuity with the direct case, though this printer always prints an
|
|
1656
|
+
* argument list, which already disambiguates it.
|
|
1657
|
+
*/
|
|
1658
|
+
private newExpressionTargetNeedsParentheses(expression: Expression): boolean {
|
|
1659
|
+
if (!this.isLeftHandSideExpression(expression)) return true;
|
|
1660
|
+
const leftmost: Expression = this.leftmostExpression(expression, true);
|
|
1661
|
+
return (
|
|
1662
|
+
leftmost.kind === "CallExpression" ||
|
|
1663
|
+
leftmost.kind === "CallChain" ||
|
|
1664
|
+
(leftmost.kind === "NewExpression" && leftmost.arguments === undefined)
|
|
1665
|
+
);
|
|
1628
1666
|
}
|
|
1629
1667
|
|
|
1630
1668
|
private prefixUnaryOperand(operand: Expression, operator?: SyntaxKind): Doc {
|
|
@@ -1724,12 +1762,6 @@ export class TsPrinter {
|
|
|
1724
1762
|
this.binaryOperatorPrecedence(operator);
|
|
1725
1763
|
const operandPrecedence: ExpressionPrecedence =
|
|
1726
1764
|
this.expressionPrecedence(operand);
|
|
1727
|
-
if (
|
|
1728
|
-
!isLeftSide &&
|
|
1729
|
-
operand.kind === "ArrowFunction" &&
|
|
1730
|
-
operatorPrecedence > ExpressionPrecedence.Assignment
|
|
1731
|
-
)
|
|
1732
|
-
return true;
|
|
1733
1765
|
if (operandPrecedence < operatorPrecedence) return true;
|
|
1734
1766
|
if (operandPrecedence > operatorPrecedence) return false;
|
|
1735
1767
|
|
|
@@ -1755,6 +1787,8 @@ export class TsPrinter {
|
|
|
1755
1787
|
return ExpressionPrecedence.Comma;
|
|
1756
1788
|
case "YieldExpression":
|
|
1757
1789
|
return ExpressionPrecedence.Yield;
|
|
1790
|
+
case "ArrowFunction":
|
|
1791
|
+
return ExpressionPrecedence.Assignment;
|
|
1758
1792
|
case "ConditionalExpression":
|
|
1759
1793
|
return ExpressionPrecedence.Conditional;
|
|
1760
1794
|
case "BinaryExpression":
|
|
@@ -1802,6 +1836,7 @@ export class TsPrinter {
|
|
|
1802
1836
|
case "AwaitExpression":
|
|
1803
1837
|
case "ConditionalExpression":
|
|
1804
1838
|
case "YieldExpression":
|
|
1839
|
+
case "ArrowFunction":
|
|
1805
1840
|
return Associativity.Right;
|
|
1806
1841
|
case "BinaryExpression":
|
|
1807
1842
|
return this.binaryOperatorAssociativity(expression.operator);
|
|
@@ -1977,11 +2012,22 @@ export class TsPrinter {
|
|
|
1977
2012
|
);
|
|
1978
2013
|
}
|
|
1979
2014
|
|
|
1980
|
-
|
|
2015
|
+
/**
|
|
2016
|
+
* Walk to the expression's leftmost node — the one that starts its printed
|
|
2017
|
+
* text. With `stopAtCall`, calls terminate the walk instead of being walked
|
|
2018
|
+
* through, matching the legacy `getLeftmostExpression`'s
|
|
2019
|
+
* `stopAtCallExpressions` mode used by the `new`-target parenthesizer.
|
|
2020
|
+
*/
|
|
2021
|
+
private leftmostExpression(
|
|
2022
|
+
expression: Expression,
|
|
2023
|
+
stopAtCall: boolean = false,
|
|
2024
|
+
): Expression {
|
|
1981
2025
|
switch (expression.kind) {
|
|
1982
|
-
case "AsExpression":
|
|
1983
2026
|
case "CallExpression":
|
|
1984
2027
|
case "CallChain":
|
|
2028
|
+
if (stopAtCall) return expression;
|
|
2029
|
+
return this.leftmostExpression(expression.expression, stopAtCall);
|
|
2030
|
+
case "AsExpression":
|
|
1985
2031
|
case "ElementAccessExpression":
|
|
1986
2032
|
case "ElementAccessChain":
|
|
1987
2033
|
case "NonNullExpression":
|
|
@@ -1989,13 +2035,13 @@ export class TsPrinter {
|
|
|
1989
2035
|
case "PropertyAccessExpression":
|
|
1990
2036
|
case "PropertyAccessChain":
|
|
1991
2037
|
case "SatisfiesExpression":
|
|
1992
|
-
return this.leftmostExpression(expression.expression);
|
|
2038
|
+
return this.leftmostExpression(expression.expression, stopAtCall);
|
|
1993
2039
|
case "BinaryExpression":
|
|
1994
|
-
return this.leftmostExpression(expression.left);
|
|
2040
|
+
return this.leftmostExpression(expression.left, stopAtCall);
|
|
1995
2041
|
case "ConditionalExpression":
|
|
1996
|
-
return this.leftmostExpression(expression.condition);
|
|
2042
|
+
return this.leftmostExpression(expression.condition, stopAtCall);
|
|
1997
2043
|
case "TaggedTemplateExpression":
|
|
1998
|
-
return this.leftmostExpression(expression.tag);
|
|
2044
|
+
return this.leftmostExpression(expression.tag, stopAtCall);
|
|
1999
2045
|
default:
|
|
2000
2046
|
return expression;
|
|
2001
2047
|
}
|
|
@@ -2153,6 +2199,31 @@ export namespace TsPrinter {
|
|
|
2153
2199
|
}
|
|
2154
2200
|
}
|
|
2155
2201
|
|
|
2202
|
+
/**
|
|
2203
|
+
* Source text of a template span: `rawText` verbatim when the author provided
|
|
2204
|
+
* one (raw fidelity is theirs to own, mirroring the legacy TypeScript emitter),
|
|
2205
|
+
* otherwise the cooked `text` escaped for template context.
|
|
2206
|
+
*/
|
|
2207
|
+
const templateText = (node: { text: string; rawText?: string }): string =>
|
|
2208
|
+
typeof node.rawText === "string"
|
|
2209
|
+
? node.rawText
|
|
2210
|
+
: escapeTemplateText(node.text);
|
|
2211
|
+
|
|
2212
|
+
/**
|
|
2213
|
+
* Escape cooked text so it re-parses to the same cooked value inside a template
|
|
2214
|
+
* literal: backslashes, backticks, and `${` sequences (a `$` not followed by
|
|
2215
|
+
* `{` stays literal). CR and CRLF are escaped because the scanner normalizes
|
|
2216
|
+
* raw template line terminators to LF; a lone LF is legal template text and
|
|
2217
|
+
* stays literal.
|
|
2218
|
+
*/
|
|
2219
|
+
const escapeTemplateText = (text: string): string =>
|
|
2220
|
+
text
|
|
2221
|
+
.replace(/\\/g, "\\\\")
|
|
2222
|
+
.replace(/`/g, "\\`")
|
|
2223
|
+
.replace(/\$\{/g, "\\${")
|
|
2224
|
+
.replace(/\r\n/g, "\\r\\n")
|
|
2225
|
+
.replace(/\r/g, "\\r");
|
|
2226
|
+
|
|
2156
2227
|
const escapeString = (text: string, singleQuote?: boolean): string => {
|
|
2157
2228
|
const escaped: string = text
|
|
2158
2229
|
.replace(/\\/g, "\\\\")
|
|
@@ -5,9 +5,11 @@ import { make } from "../internal/make";
|
|
|
5
5
|
* Create a {@link NoSubstitutionTemplateLiteral}: a backtick template string
|
|
6
6
|
* with no `${...}` substitutions.
|
|
7
7
|
*
|
|
8
|
-
* The `text` is the
|
|
9
|
-
* placeholders, the whole literal is a single span
|
|
10
|
-
*
|
|
8
|
+
* The `text` is the cooked content between the backticks. Because there are no
|
|
9
|
+
* placeholders, the whole literal is a single span. The optional `rawText`
|
|
10
|
+
* carries the source spelling before escape processing; the printer emits it
|
|
11
|
+
* verbatim when present, and otherwise escapes the cooked `text` so it
|
|
12
|
+
* re-parses to the same value.
|
|
11
13
|
*
|
|
12
14
|
* With `text` of `hello`, this prints:
|
|
13
15
|
*
|
|
@@ -17,9 +19,11 @@ import { make } from "../internal/make";
|
|
|
17
19
|
*
|
|
18
20
|
* @author Jeongho Nam - https://github.com/samchon
|
|
19
21
|
* @param text The text.
|
|
22
|
+
* @param rawText The rawText.
|
|
20
23
|
* @returns The created node.
|
|
21
24
|
*/
|
|
22
25
|
export const createNoSubstitutionTemplateLiteral = (
|
|
23
26
|
text: string,
|
|
27
|
+
rawText?: string,
|
|
24
28
|
): NoSubstitutionTemplateLiteral =>
|
|
25
|
-
make("NoSubstitutionTemplateLiteral", { text });
|
|
29
|
+
make("NoSubstitutionTemplateLiteral", { text, rawText });
|
|
@@ -6,9 +6,10 @@ import { make } from "../internal/make";
|
|
|
6
6
|
* the leading backtick up to the first `${`.
|
|
7
7
|
*
|
|
8
8
|
* The `text` is the cooked content of that span. The optional `rawText` carries
|
|
9
|
-
* the source spelling before escape processing;
|
|
10
|
-
*
|
|
11
|
-
*
|
|
9
|
+
* the source spelling before escape processing; the printer emits it verbatim
|
|
10
|
+
* when present, and otherwise escapes the cooked `text` so it re-parses to the
|
|
11
|
+
* same value. A head is not a complete expression on its own, it is one piece
|
|
12
|
+
* of a larger template literal.
|
|
12
13
|
*
|
|
13
14
|
* The printer emits the opening backtick, the content, then the `${` that opens
|
|
14
15
|
* the first substitution. With `text` of `head`, this prints:
|
|
@@ -5,9 +5,12 @@ import { make } from "../internal/make";
|
|
|
5
5
|
* Create a {@link TemplateMiddle}: a span of a template expression that sits
|
|
6
6
|
* between two substitutions, from one `}` to the next `${`.
|
|
7
7
|
*
|
|
8
|
-
* The `text` is the cooked content of that span.
|
|
9
|
-
*
|
|
10
|
-
*
|
|
8
|
+
* The `text` is the cooked content of that span. The optional `rawText` carries
|
|
9
|
+
* the source spelling before escape processing; the printer emits it verbatim
|
|
10
|
+
* when present, and otherwise escapes the cooked `text` so it re-parses to the
|
|
11
|
+
* same value. A middle span only appears in a template literal that has two or
|
|
12
|
+
* more substitutions, and it is one piece of that larger literal rather than a
|
|
13
|
+
* complete expression.
|
|
11
14
|
*
|
|
12
15
|
* The printer emits the closing `}` of the preceding substitution, the content,
|
|
13
16
|
* then the `${` that opens the next one. With `text` of `mid`, this prints:
|
|
@@ -18,7 +21,10 @@ import { make } from "../internal/make";
|
|
|
18
21
|
*
|
|
19
22
|
* @author Jeongho Nam - https://github.com/samchon
|
|
20
23
|
* @param text The text.
|
|
24
|
+
* @param rawText The rawText.
|
|
21
25
|
* @returns The created node.
|
|
22
26
|
*/
|
|
23
|
-
export const createTemplateMiddle = (
|
|
24
|
-
|
|
27
|
+
export const createTemplateMiddle = (
|
|
28
|
+
text: string,
|
|
29
|
+
rawText?: string,
|
|
30
|
+
): TemplateMiddle => make("TemplateMiddle", { text, rawText });
|
|
@@ -5,9 +5,12 @@ import { make } from "../internal/make";
|
|
|
5
5
|
* Create a {@link TemplateTail}: the closing span of a template expression, from
|
|
6
6
|
* the last `}` to the trailing backtick.
|
|
7
7
|
*
|
|
8
|
-
* The `text` is the cooked content of that span.
|
|
9
|
-
*
|
|
10
|
-
*
|
|
8
|
+
* The `text` is the cooked content of that span. The optional `rawText` carries
|
|
9
|
+
* the source spelling before escape processing; the printer emits it verbatim
|
|
10
|
+
* when present, and otherwise escapes the cooked `text` so it re-parses to the
|
|
11
|
+
* same value. A tail closes a template literal that has at least one
|
|
12
|
+
* substitution, and it is one piece of that larger literal rather than a
|
|
13
|
+
* complete expression.
|
|
11
14
|
*
|
|
12
15
|
* The printer emits the closing `}` of the final substitution, the content,
|
|
13
16
|
* then the trailing backtick. With `text` of `tail`, this prints:
|
|
@@ -18,7 +21,10 @@ import { make } from "../internal/make";
|
|
|
18
21
|
*
|
|
19
22
|
* @author Jeongho Nam - https://github.com/samchon
|
|
20
23
|
* @param text The text.
|
|
24
|
+
* @param rawText The rawText.
|
|
21
25
|
* @returns The created node.
|
|
22
26
|
*/
|
|
23
|
-
export const createTemplateTail = (
|
|
24
|
-
|
|
27
|
+
export const createTemplateTail = (
|
|
28
|
+
text: string,
|
|
29
|
+
rawText?: string,
|
|
30
|
+
): TemplateTail => make("TemplateTail", { text, rawText });
|