mirror of
https://github.com/hanzoai/babel.git
synced 2026-09-24 16:56:45 +00:00
1697 lines
47 KiB
JavaScript
1697 lines
47 KiB
JavaScript
import { parse, parseExpression } from "@babel/parser";
|
|
import * as t from "@babel/types";
|
|
import fs from "node:fs";
|
|
import path from "node:path";
|
|
import fixtures from "@babel/helper-fixtures";
|
|
import { TraceMap, originalPositionFor } from "@jridgewell/trace-mapping";
|
|
import { commonJS } from "$repo-utils";
|
|
import { encode } from "@jridgewell/sourcemap-codec";
|
|
|
|
import generate from "../lib/index.js";
|
|
|
|
const { __dirname } = commonJS(import.meta.url);
|
|
|
|
describe("generation", function () {
|
|
it("multiple sources", function () {
|
|
const sources = {
|
|
"a.js": "function hi (msg) { console.log(msg); }\n",
|
|
"b.js": "hi('hello');\n",
|
|
};
|
|
const parsed = Object.keys(sources).reduce(function (_parsed, filename) {
|
|
_parsed[filename] = parse(sources[filename], {
|
|
sourceFilename: filename,
|
|
});
|
|
return _parsed;
|
|
}, {});
|
|
|
|
const combinedAst = {
|
|
type: "File",
|
|
program: {
|
|
type: "Program",
|
|
sourceType: "module",
|
|
body: [].concat(
|
|
parsed["a.js"].program.body,
|
|
parsed["b.js"].program.body,
|
|
),
|
|
},
|
|
};
|
|
|
|
const generated = generate(combinedAst, { sourceMaps: true }, sources);
|
|
|
|
expect(generated.map).toMatchInlineSnapshot(`
|
|
{
|
|
"file": undefined,
|
|
"ignoreList": [],
|
|
"mappings": "AAAA,SAAS,EAAE,CAAE,GAAG,EAAE;EAAE,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC;AAAE;ACAtC,EAAE,CAAC,OAAO,CAAC",
|
|
"names": [],
|
|
"rangeMappings": undefined,
|
|
"sourceRoot": undefined,
|
|
"sources": [
|
|
"a.js",
|
|
"b.js",
|
|
],
|
|
"sourcesContent": [
|
|
"function hi (msg) { console.log(msg); }
|
|
",
|
|
"hi('hello');
|
|
",
|
|
],
|
|
"version": 3,
|
|
}
|
|
`);
|
|
|
|
expect(generated.rawMappings).toMatchInlineSnapshot(`
|
|
[
|
|
{
|
|
"generated": {
|
|
"column": 0,
|
|
"line": 1,
|
|
},
|
|
"name": undefined,
|
|
"original": {
|
|
"column": 0,
|
|
"line": 1,
|
|
},
|
|
"source": "a.js",
|
|
},
|
|
{
|
|
"generated": {
|
|
"column": 9,
|
|
"line": 1,
|
|
},
|
|
"name": undefined,
|
|
"original": {
|
|
"column": 9,
|
|
"line": 1,
|
|
},
|
|
"source": "a.js",
|
|
},
|
|
{
|
|
"generated": {
|
|
"column": 11,
|
|
"line": 1,
|
|
},
|
|
"name": undefined,
|
|
"original": {
|
|
"column": 11,
|
|
"line": 1,
|
|
},
|
|
"source": "a.js",
|
|
},
|
|
{
|
|
"generated": {
|
|
"column": 12,
|
|
"line": 1,
|
|
},
|
|
"name": undefined,
|
|
"original": {
|
|
"column": 13,
|
|
"line": 1,
|
|
},
|
|
"source": "a.js",
|
|
},
|
|
{
|
|
"generated": {
|
|
"column": 15,
|
|
"line": 1,
|
|
},
|
|
"name": undefined,
|
|
"original": {
|
|
"column": 16,
|
|
"line": 1,
|
|
},
|
|
"source": "a.js",
|
|
},
|
|
{
|
|
"generated": {
|
|
"column": 17,
|
|
"line": 1,
|
|
},
|
|
"name": undefined,
|
|
"original": {
|
|
"column": 18,
|
|
"line": 1,
|
|
},
|
|
"source": "a.js",
|
|
},
|
|
{
|
|
"generated": {
|
|
"column": 2,
|
|
"line": 2,
|
|
},
|
|
"name": undefined,
|
|
"original": {
|
|
"column": 20,
|
|
"line": 1,
|
|
},
|
|
"source": "a.js",
|
|
},
|
|
{
|
|
"generated": {
|
|
"column": 9,
|
|
"line": 2,
|
|
},
|
|
"name": undefined,
|
|
"original": {
|
|
"column": 27,
|
|
"line": 1,
|
|
},
|
|
"source": "a.js",
|
|
},
|
|
{
|
|
"generated": {
|
|
"column": 10,
|
|
"line": 2,
|
|
},
|
|
"name": undefined,
|
|
"original": {
|
|
"column": 28,
|
|
"line": 1,
|
|
},
|
|
"source": "a.js",
|
|
},
|
|
{
|
|
"generated": {
|
|
"column": 13,
|
|
"line": 2,
|
|
},
|
|
"name": undefined,
|
|
"original": {
|
|
"column": 31,
|
|
"line": 1,
|
|
},
|
|
"source": "a.js",
|
|
},
|
|
{
|
|
"generated": {
|
|
"column": 14,
|
|
"line": 2,
|
|
},
|
|
"name": undefined,
|
|
"original": {
|
|
"column": 32,
|
|
"line": 1,
|
|
},
|
|
"source": "a.js",
|
|
},
|
|
{
|
|
"generated": {
|
|
"column": 17,
|
|
"line": 2,
|
|
},
|
|
"name": undefined,
|
|
"original": {
|
|
"column": 35,
|
|
"line": 1,
|
|
},
|
|
"source": "a.js",
|
|
},
|
|
{
|
|
"generated": {
|
|
"column": 18,
|
|
"line": 2,
|
|
},
|
|
"name": undefined,
|
|
"original": {
|
|
"column": 36,
|
|
"line": 1,
|
|
},
|
|
"source": "a.js",
|
|
},
|
|
{
|
|
"generated": {
|
|
"column": 0,
|
|
"line": 3,
|
|
},
|
|
"name": undefined,
|
|
"original": {
|
|
"column": 38,
|
|
"line": 1,
|
|
},
|
|
"source": "a.js",
|
|
},
|
|
{
|
|
"generated": {
|
|
"column": 0,
|
|
"line": 4,
|
|
},
|
|
"name": undefined,
|
|
"original": {
|
|
"column": 0,
|
|
"line": 1,
|
|
},
|
|
"source": "b.js",
|
|
},
|
|
{
|
|
"generated": {
|
|
"column": 2,
|
|
"line": 4,
|
|
},
|
|
"name": undefined,
|
|
"original": {
|
|
"column": 2,
|
|
"line": 1,
|
|
},
|
|
"source": "b.js",
|
|
},
|
|
{
|
|
"generated": {
|
|
"column": 3,
|
|
"line": 4,
|
|
},
|
|
"name": undefined,
|
|
"original": {
|
|
"column": 3,
|
|
"line": 1,
|
|
},
|
|
"source": "b.js",
|
|
},
|
|
{
|
|
"generated": {
|
|
"column": 10,
|
|
"line": 4,
|
|
},
|
|
"name": undefined,
|
|
"original": {
|
|
"column": 10,
|
|
"line": 1,
|
|
},
|
|
"source": "b.js",
|
|
},
|
|
{
|
|
"generated": {
|
|
"column": 11,
|
|
"line": 4,
|
|
},
|
|
"name": undefined,
|
|
"original": {
|
|
"column": 11,
|
|
"line": 1,
|
|
},
|
|
"source": "b.js",
|
|
},
|
|
]
|
|
`);
|
|
|
|
expect(generated.code).toBe(
|
|
"function hi(msg) {\n console.log(msg);\n}\nhi('hello');",
|
|
);
|
|
});
|
|
|
|
it("identifierName", function () {
|
|
const code = "function foo() { bar; }\n";
|
|
|
|
const ast = parse(code, { filename: "inline" }).program;
|
|
const fn = ast.body[0];
|
|
|
|
const id = fn.id;
|
|
id.name += "2";
|
|
id.loc.identifierName = "foo";
|
|
|
|
const id2 = fn.body.body[0].expression;
|
|
id2.name += "2";
|
|
id2.loc.identifierName = "bar";
|
|
|
|
const generated = generate(
|
|
ast,
|
|
{
|
|
filename: "inline",
|
|
sourceFileName: "inline",
|
|
sourceMaps: true,
|
|
},
|
|
code,
|
|
);
|
|
|
|
expect(generated).toMatchInlineSnapshot(`
|
|
{
|
|
"code": "function foo2() {
|
|
bar2;
|
|
}",
|
|
"decodedMap": {
|
|
"file": undefined,
|
|
"ignoreList": [],
|
|
"mappings": [
|
|
[
|
|
[
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
],
|
|
[
|
|
9,
|
|
0,
|
|
0,
|
|
9,
|
|
0,
|
|
],
|
|
[
|
|
13,
|
|
0,
|
|
0,
|
|
12,
|
|
0,
|
|
],
|
|
[
|
|
14,
|
|
0,
|
|
0,
|
|
12,
|
|
],
|
|
[
|
|
16,
|
|
0,
|
|
0,
|
|
15,
|
|
],
|
|
],
|
|
[
|
|
[
|
|
2,
|
|
0,
|
|
0,
|
|
17,
|
|
1,
|
|
],
|
|
[
|
|
6,
|
|
0,
|
|
0,
|
|
20,
|
|
],
|
|
],
|
|
[
|
|
[
|
|
0,
|
|
0,
|
|
0,
|
|
22,
|
|
],
|
|
],
|
|
],
|
|
"names": [
|
|
"foo",
|
|
"bar",
|
|
],
|
|
"rangeMappings": undefined,
|
|
"sourceRoot": undefined,
|
|
"sources": [
|
|
"inline",
|
|
],
|
|
"sourcesContent": [
|
|
"function foo() { bar; }
|
|
",
|
|
],
|
|
"version": 3,
|
|
},
|
|
"map": {
|
|
"file": undefined,
|
|
"ignoreList": [],
|
|
"mappings": "AAAA,SAASA,IAAGA,CAAA,EAAG;EAAEC,IAAG;AAAE",
|
|
"names": [
|
|
"foo",
|
|
"bar",
|
|
],
|
|
"rangeMappings": undefined,
|
|
"sourceRoot": undefined,
|
|
"sources": [
|
|
"inline",
|
|
],
|
|
"sourcesContent": [
|
|
"function foo() { bar; }
|
|
",
|
|
],
|
|
"version": 3,
|
|
},
|
|
"rawMappings": [
|
|
{
|
|
"generated": {
|
|
"column": 0,
|
|
"line": 1,
|
|
},
|
|
"name": undefined,
|
|
"original": {
|
|
"column": 0,
|
|
"line": 1,
|
|
},
|
|
"source": "inline",
|
|
},
|
|
{
|
|
"generated": {
|
|
"column": 9,
|
|
"line": 1,
|
|
},
|
|
"name": "foo",
|
|
"original": {
|
|
"column": 9,
|
|
"line": 1,
|
|
},
|
|
"source": "inline",
|
|
},
|
|
{
|
|
"generated": {
|
|
"column": 13,
|
|
"line": 1,
|
|
},
|
|
"name": "foo",
|
|
"original": {
|
|
"column": 12,
|
|
"line": 1,
|
|
},
|
|
"source": "inline",
|
|
},
|
|
{
|
|
"generated": {
|
|
"column": 14,
|
|
"line": 1,
|
|
},
|
|
"name": undefined,
|
|
"original": {
|
|
"column": 12,
|
|
"line": 1,
|
|
},
|
|
"source": "inline",
|
|
},
|
|
{
|
|
"generated": {
|
|
"column": 16,
|
|
"line": 1,
|
|
},
|
|
"name": undefined,
|
|
"original": {
|
|
"column": 15,
|
|
"line": 1,
|
|
},
|
|
"source": "inline",
|
|
},
|
|
{
|
|
"generated": {
|
|
"column": 2,
|
|
"line": 2,
|
|
},
|
|
"name": "bar",
|
|
"original": {
|
|
"column": 17,
|
|
"line": 1,
|
|
},
|
|
"source": "inline",
|
|
},
|
|
{
|
|
"generated": {
|
|
"column": 6,
|
|
"line": 2,
|
|
},
|
|
"name": undefined,
|
|
"original": {
|
|
"column": 20,
|
|
"line": 1,
|
|
},
|
|
"source": "inline",
|
|
},
|
|
{
|
|
"generated": {
|
|
"column": 0,
|
|
"line": 3,
|
|
},
|
|
"name": undefined,
|
|
"original": {
|
|
"column": 22,
|
|
"line": 1,
|
|
},
|
|
"source": "inline",
|
|
},
|
|
],
|
|
}
|
|
`);
|
|
});
|
|
|
|
it("newline in template literal", () => {
|
|
const code = "`before\n\nafter`;";
|
|
const ast = parse(code, { filename: "inline" }).program;
|
|
const generated = generate(
|
|
ast,
|
|
{
|
|
filename: "inline",
|
|
sourceFileName: "inline",
|
|
sourceMaps: true,
|
|
},
|
|
code,
|
|
);
|
|
|
|
const consumer = new TraceMap(generated.map);
|
|
const loc = originalPositionFor(consumer, { line: 2, column: 1 });
|
|
expect(loc).toMatchObject({
|
|
column: 0,
|
|
line: 2,
|
|
});
|
|
});
|
|
|
|
it("newline in string literal", () => {
|
|
const code = "'before\\\n\\\nafter';";
|
|
const ast = parse(code, { filename: "inline" }).program;
|
|
const generated = generate(
|
|
ast,
|
|
{
|
|
filename: "inline",
|
|
sourceFileName: "inline",
|
|
sourceMaps: true,
|
|
},
|
|
code,
|
|
);
|
|
|
|
const consumer = new TraceMap(generated.map);
|
|
const loc = originalPositionFor(consumer, { line: 2, column: 1 });
|
|
expect(loc).toMatchObject({
|
|
column: 0,
|
|
line: 2,
|
|
});
|
|
});
|
|
|
|
it("lazy source map generation", function () {
|
|
const code = "function hi (msg) { console.log(msg); }\n";
|
|
|
|
const ast = parse(code, { filename: "a.js" }).program;
|
|
const generated = generate(ast, {
|
|
sourceFileName: "a.js",
|
|
sourceMaps: true,
|
|
});
|
|
|
|
expect(Array.isArray(generated.rawMappings)).toBe(true);
|
|
|
|
expect(
|
|
Object.getOwnPropertyDescriptor(generated, "map"),
|
|
).not.toHaveProperty("value");
|
|
|
|
expect(generated).toHaveProperty("map");
|
|
expect(typeof generated.map).toBe("object");
|
|
});
|
|
|
|
it("wraps around infer inside an array type", () => {
|
|
const type = t.tsArrayType(
|
|
t.tsInferType(t.tsTypeParameter(null, null, t.identifier("T"))),
|
|
);
|
|
|
|
const output = generate(type).code;
|
|
expect(output).toBe("(infer T)[]");
|
|
});
|
|
|
|
it("should not deduplicate comments with same start index", () => {
|
|
const code1 = "/*#__PURE__*/ a();";
|
|
const code2 = "/*#__PURE__*/ b();";
|
|
|
|
const ast1 = parse(code1).program;
|
|
const ast2 = parse(code2).program;
|
|
|
|
const ast = t.program([...ast1.body, ...ast2.body]);
|
|
|
|
expect(generate(ast).code).toBe("/*#__PURE__*/a();\n/*#__PURE__*/b();");
|
|
});
|
|
|
|
it("comments with null or undefined loc", () => {
|
|
const code = "/*#__PURE__*/ /*#__PURE__*/";
|
|
|
|
const ast = parse(code);
|
|
|
|
ast.comments[0].loc = null;
|
|
ast.comments[1].loc = undefined;
|
|
|
|
expect(generate(ast).code).toBe("/*#__PURE__*/\n/*#__PURE__*/");
|
|
});
|
|
|
|
it("comments without loc", () => {
|
|
const ast = parse(
|
|
`
|
|
import {
|
|
Attribute,
|
|
AttributeSDKType
|
|
}
|
|
from "../../base/v1beta1/attribute";
|
|
import {
|
|
Rpc
|
|
}
|
|
from "../../../helpers";
|
|
import * as _m0 from "protobufjs/minimal";
|
|
import {
|
|
MsgSignProviderAttributes,
|
|
MsgSignProviderAttributesSDKType,
|
|
MsgSignProviderAttributesResponse,
|
|
MsgSignProviderAttributesResponseSDKType,
|
|
MsgDeleteProviderAttributes,
|
|
MsgDeleteProviderAttributesSDKType,
|
|
MsgDeleteProviderAttributesResponse,
|
|
MsgDeleteProviderAttributesResponseSDKType
|
|
}
|
|
from "./audit";
|
|
/** Msg defines the provider Msg service */
|
|
export interface Msg {
|
|
/** SignProviderAttributes defines a method that signs provider attributes */
|
|
signProviderAttributes(request: MsgSignProviderAttributes): Promise < MsgSignProviderAttributesResponse > ;
|
|
/** DeleteProviderAttributes defines a method that deletes provider attributes */
|
|
deleteProviderAttributes(request: MsgDeleteProviderAttributes): Promise < MsgDeleteProviderAttributesResponse > ;
|
|
}
|
|
export class MsgClientImpl implements Msg {
|
|
private readonly rpc: Rpc;
|
|
constructor(rpc: Rpc) {
|
|
this.rpc = rpc;
|
|
}
|
|
/* SignProviderAttributes defines a method that signs provider attributes */
|
|
signProviderAttributes = async(request: MsgSignProviderAttributes): Promise < MsgSignProviderAttributesResponse > => {
|
|
const data = MsgSignProviderAttributes.encode(request).finish();
|
|
const promise = this.rpc.request("akash.audit.v1beta1.Msg", "SignProviderAttributes", data);
|
|
return promise.then(data => MsgSignProviderAttributesResponse.decode(new _m0.Reader(data)));
|
|
};
|
|
/* DeleteProviderAttributes defines a method that deletes provider attributes */
|
|
deleteProviderAttributes = async(request: MsgDeleteProviderAttributes): Promise < MsgDeleteProviderAttributesResponse > => {
|
|
const data = MsgDeleteProviderAttributes.encode(request).finish();
|
|
const promise = this.rpc.request("akash.audit.v1beta1.Msg", "DeleteProviderAttributes", data);
|
|
return promise.then(data => MsgDeleteProviderAttributesResponse.decode(new _m0.Reader(data)));
|
|
};
|
|
}
|
|
`,
|
|
{ sourceType: "module", plugins: ["typescript"] },
|
|
);
|
|
|
|
for (const comment of ast.comments) {
|
|
comment.loc = undefined;
|
|
}
|
|
|
|
expect(generate(ast).code).toMatchInlineSnapshot(`
|
|
"import { Attribute, AttributeSDKType } from "../../base/v1beta1/attribute";
|
|
import { Rpc } from "../../../helpers";
|
|
import * as _m0 from "protobufjs/minimal";
|
|
import { MsgSignProviderAttributes, MsgSignProviderAttributesSDKType, MsgSignProviderAttributesResponse, MsgSignProviderAttributesResponseSDKType, MsgDeleteProviderAttributes, MsgDeleteProviderAttributesSDKType, MsgDeleteProviderAttributesResponse, MsgDeleteProviderAttributesResponseSDKType } from "./audit";
|
|
/** Msg defines the provider Msg service */
|
|
export interface Msg {
|
|
/** SignProviderAttributes defines a method that signs provider attributes */
|
|
signProviderAttributes(request: MsgSignProviderAttributes): Promise<MsgSignProviderAttributesResponse>;
|
|
/** DeleteProviderAttributes defines a method that deletes provider attributes */
|
|
deleteProviderAttributes(request: MsgDeleteProviderAttributes): Promise<MsgDeleteProviderAttributesResponse>;
|
|
}
|
|
export class MsgClientImpl implements Msg {
|
|
private readonly rpc: Rpc;
|
|
constructor(rpc: Rpc) {
|
|
this.rpc = rpc;
|
|
}
|
|
/* SignProviderAttributes defines a method that signs provider attributes */
|
|
signProviderAttributes = async (request: MsgSignProviderAttributes): Promise<MsgSignProviderAttributesResponse> => {
|
|
const data = MsgSignProviderAttributes.encode(request).finish();
|
|
const promise = this.rpc.request("akash.audit.v1beta1.Msg", "SignProviderAttributes", data);
|
|
return promise.then(data => MsgSignProviderAttributesResponse.decode(new _m0.Reader(data)));
|
|
};
|
|
/* DeleteProviderAttributes defines a method that deletes provider attributes */
|
|
deleteProviderAttributes = async (request: MsgDeleteProviderAttributes): Promise<MsgDeleteProviderAttributesResponse> => {
|
|
const data = MsgDeleteProviderAttributes.encode(request).finish();
|
|
const promise = this.rpc.request("akash.audit.v1beta1.Msg", "DeleteProviderAttributes", data);
|
|
return promise.then(data => MsgDeleteProviderAttributesResponse.decode(new _m0.Reader(data)));
|
|
};
|
|
}"
|
|
`);
|
|
});
|
|
|
|
it("comments without loc2", () => {
|
|
const ast = parse(
|
|
`
|
|
(function (_templateFactory) {
|
|
"use strict";
|
|
|
|
const template = (0, _templateFactory.createTemplateFactory)(
|
|
/*{{somevalue}}*/
|
|
{
|
|
"id": null,
|
|
"block": "[[[1,[34,0]]],[],false,[\\"somevalue\\"]]",
|
|
"moduleName": "(unknown template module)",
|
|
"isStrictMode": false
|
|
});
|
|
});
|
|
|
|
const template = (0, _templateFactory.createTemplateFactory)(
|
|
/*
|
|
{{somevalue}}
|
|
*/
|
|
{
|
|
"id": null,
|
|
"block": "[[[1,[34,0]]],[],false,[\\"somevalue\\"]]",
|
|
"moduleName": "(unknown template module)",
|
|
"isStrictMode": false
|
|
});
|
|
`,
|
|
{ sourceType: "module" },
|
|
);
|
|
|
|
for (const comment of ast.comments) {
|
|
comment.loc = undefined;
|
|
}
|
|
|
|
expect(generate(ast).code).toMatchInlineSnapshot(`
|
|
"(function (_templateFactory) {
|
|
"use strict";
|
|
|
|
const template = (0, _templateFactory.createTemplateFactory)(
|
|
/*{{somevalue}}*/
|
|
{
|
|
"id": null,
|
|
"block": "[[[1,[34,0]]],[],false,[\\"somevalue\\"]]",
|
|
"moduleName": "(unknown template module)",
|
|
"isStrictMode": false
|
|
});
|
|
});
|
|
const template = (0, _templateFactory.createTemplateFactory)(
|
|
/*
|
|
{{somevalue}}
|
|
*/
|
|
{
|
|
"id": null,
|
|
"block": "[[[1,[34,0]]],[],false,[\\"somevalue\\"]]",
|
|
"moduleName": "(unknown template module)",
|
|
"isStrictMode": false
|
|
});"
|
|
`);
|
|
});
|
|
|
|
it("comments without loc3", () => {
|
|
const ast = parse(
|
|
`
|
|
/** This describes how the endpoint is implemented when the lease is deployed */
|
|
export enum Endpoint_Kind {
|
|
/** SHARED_HTTP - Describes an endpoint that becomes a Kubernetes Ingress */
|
|
SHARED_HTTP = 0,
|
|
/** RANDOM_PORT - Describes an endpoint that becomes a Kubernetes NodePort */
|
|
RANDOM_PORT = 1,
|
|
UNRECOGNIZED = -1,
|
|
}
|
|
`,
|
|
{ sourceType: "module", plugins: ["typescript"] },
|
|
);
|
|
|
|
for (const comment of ast.comments) {
|
|
comment.loc = undefined;
|
|
}
|
|
|
|
expect(generate(ast).code).toMatchInlineSnapshot(`
|
|
"/** This describes how the endpoint is implemented when the lease is deployed */
|
|
export enum Endpoint_Kind {
|
|
/** SHARED_HTTP - Describes an endpoint that becomes a Kubernetes Ingress */
|
|
SHARED_HTTP = 0,
|
|
/** RANDOM_PORT - Describes an endpoint that becomes a Kubernetes NodePort */
|
|
RANDOM_PORT = 1,
|
|
UNRECOGNIZED = -1
|
|
}"
|
|
`);
|
|
});
|
|
|
|
it("comments without node.loc", () => {
|
|
const ast = parse(
|
|
`
|
|
(function (_templateFactory) {
|
|
"use strict";
|
|
|
|
const template = (0, _templateFactory.createTemplateFactory)(
|
|
/*{{somevalue}}*/
|
|
{
|
|
"id": null,
|
|
"block": "[[[1,[34,0]]],[],false,[\\"somevalue\\"]]",
|
|
"moduleName": "(unknown template module)",
|
|
"isStrictMode": false
|
|
});
|
|
});
|
|
|
|
const template = (0, _templateFactory.createTemplateFactory)(
|
|
/*
|
|
{{somevalue}}
|
|
*/
|
|
{
|
|
"id": null,
|
|
"block": "[[[1,[34,0]]],[],false,[\\"somevalue\\"]]",
|
|
"moduleName": "(unknown template module)",
|
|
"isStrictMode": false
|
|
});
|
|
`,
|
|
{ sourceType: "module" },
|
|
);
|
|
|
|
const ast2 = t.cloneNode(ast, true, true);
|
|
|
|
for (let i = 0; i < ast.comments.length; i++) {
|
|
ast2.comments[i].loc = ast.comments[i].loc;
|
|
}
|
|
|
|
expect(generate(ast2).code).toMatchInlineSnapshot(`
|
|
"(function (_templateFactory) {
|
|
"use strict";
|
|
|
|
const template = (0, _templateFactory.createTemplateFactory)(
|
|
/*{{somevalue}}*/
|
|
{
|
|
"id": null,
|
|
"block": "[[[1,[34,0]]],[],false,[\\"somevalue\\"]]",
|
|
"moduleName": "(unknown template module)",
|
|
"isStrictMode": false
|
|
});
|
|
});
|
|
const template = (0, _templateFactory.createTemplateFactory)(
|
|
/*
|
|
{{somevalue}}
|
|
*/
|
|
{
|
|
"id": null,
|
|
"block": "[[[1,[34,0]]],[],false,[\\"somevalue\\"]]",
|
|
"moduleName": "(unknown template module)",
|
|
"isStrictMode": false
|
|
});"
|
|
`);
|
|
});
|
|
|
|
it("inputSourceMap without sourcesContent", () => {
|
|
const ast = parse("var t = x => x * x;");
|
|
|
|
expect(
|
|
generate(ast, {
|
|
sourceMaps: true,
|
|
inputSourceMap: {
|
|
version: 3,
|
|
names: ["t", "x"],
|
|
sources: ["source-maps/arrow-function/input.js"],
|
|
mappings:
|
|
"AAAA,IAAIA,CAAC,GAAG,SAAJA,CAACA,CAAGC,CAAC;EAAA,OAAIA,CAAC,GAAGA,CAAC;AAAA",
|
|
},
|
|
}).map,
|
|
).toMatchInlineSnapshot(`
|
|
{
|
|
"file": undefined,
|
|
"ignoreList": [],
|
|
"mappings": "AAAA,IAAI,CAAC,GAAG,SAAJ,CAAC",
|
|
"names": [],
|
|
"rangeMappings": undefined,
|
|
"sourceRoot": undefined,
|
|
"sources": [
|
|
"source-maps/arrow-function/input.js",
|
|
],
|
|
"sourcesContent": [
|
|
undefined,
|
|
],
|
|
"version": 3,
|
|
}
|
|
`);
|
|
});
|
|
|
|
it("should not throw when loc.column === 0 with inputSourceMap", () => {
|
|
const ast = parseExpression("a(\n)");
|
|
|
|
ast.loc.end.column = 0;
|
|
|
|
expect(
|
|
generate(ast, {
|
|
sourceMaps: true,
|
|
inputSourceMap: {
|
|
version: 3,
|
|
names: [],
|
|
sources: ["input.js"],
|
|
// [ generatedCodeColumn, sourceIndex, sourceCodeLine, sourceCodeColumn, nameIndex ]
|
|
mappings: encode([[0, 0, 1, 0]]),
|
|
},
|
|
}).rawMappings,
|
|
).toMatchInlineSnapshot(`
|
|
[
|
|
{
|
|
"generated": {
|
|
"column": 0,
|
|
"line": 1,
|
|
},
|
|
"name": undefined,
|
|
"original": {
|
|
"column": 0,
|
|
"line": 1,
|
|
},
|
|
"source": "input.js",
|
|
},
|
|
{
|
|
"generated": {
|
|
"column": 2,
|
|
"line": 1,
|
|
},
|
|
"name": undefined,
|
|
"original": undefined,
|
|
"source": undefined,
|
|
},
|
|
]
|
|
`);
|
|
});
|
|
|
|
it("source maps should emit names for renamed identifiers", () => {
|
|
const input = `
|
|
let a = 1;
|
|
let b = 2;
|
|
function c() {}
|
|
function d() {}
|
|
class C {
|
|
#e() {};
|
|
#f() {};
|
|
}
|
|
`;
|
|
const ast = parse(input);
|
|
ast.program.body[0].declarations[0].id.name = "x";
|
|
ast.program.body[2].id.name = "y";
|
|
ast.program.body[4].body.body[0].key.id.name = "z";
|
|
|
|
const out = generate(
|
|
ast,
|
|
{ sourceMaps: true, sourceFileName: "input.js" },
|
|
input,
|
|
);
|
|
|
|
expect(out.code).toMatchInlineSnapshot(`
|
|
"let x = 1;
|
|
let b = 2;
|
|
function y() {}
|
|
function d() {}
|
|
class C {
|
|
#z() {}
|
|
#f() {}
|
|
}"
|
|
`);
|
|
expect(out.map).toMatchInlineSnapshot(`
|
|
{
|
|
"file": undefined,
|
|
"ignoreList": [],
|
|
"mappings": "AACM,IAAIA,CAAC,GAAG,CAAC;AACT,IAAI,CAAC,GAAG,CAAC;AACT,SAASC,CAACA,CAAA,EAAG,CAAC;AACd,SAAS,CAAC,GAAG,CAAC;AACd,MAAM,CAAC,CAAC;EACN,CAACC,CAACC,CAAA,EAAG,CAAC;EACN,CAAC,CAAC,GAAG,CAAC;AACR",
|
|
"names": [
|
|
"a",
|
|
"c",
|
|
"e",
|
|
"#e",
|
|
],
|
|
"rangeMappings": undefined,
|
|
"sourceRoot": undefined,
|
|
"sources": [
|
|
"input.js",
|
|
],
|
|
"sourcesContent": [
|
|
"
|
|
let a = 1;
|
|
let b = 2;
|
|
function c() {}
|
|
function d() {}
|
|
class C {
|
|
#e() {};
|
|
#f() {};
|
|
}
|
|
",
|
|
],
|
|
"version": 3,
|
|
}
|
|
`);
|
|
});
|
|
});
|
|
|
|
describe("programmatic generation", function () {
|
|
it("should add parenthesis when NullishCoalescing is used along with ||", function () {
|
|
// https://github.com/babel/babel/issues/10260
|
|
const nullishCoalesce = t.logicalExpression(
|
|
"??",
|
|
t.logicalExpression("||", t.identifier("a"), t.identifier("b")),
|
|
t.identifier("c"),
|
|
);
|
|
const output = generate(nullishCoalesce).code;
|
|
expect(output).toBe(`(a || b) ?? c`);
|
|
});
|
|
|
|
it("should add parenthesis when NullishCoalesing is used with &&", function () {
|
|
const nullishCoalesce = t.logicalExpression(
|
|
"??",
|
|
t.identifier("a"),
|
|
t.logicalExpression(
|
|
"&&",
|
|
t.identifier("b"),
|
|
t.logicalExpression("&&", t.identifier("c"), t.identifier("d")),
|
|
),
|
|
);
|
|
const output = generate(nullishCoalesce).code;
|
|
expect(output).toBe(`a ?? (b && c && d)`);
|
|
});
|
|
|
|
it("numeric member expression", function () {
|
|
// Should not generate `0.foo`
|
|
const mem = t.memberExpression(
|
|
t.numericLiteral(60702),
|
|
t.identifier("foo"),
|
|
);
|
|
new Function(generate(mem).code);
|
|
});
|
|
|
|
it("nested if statements needs block", function () {
|
|
const ifStatement = t.ifStatement(
|
|
t.stringLiteral("top cond"),
|
|
t.whileStatement(
|
|
t.stringLiteral("while cond"),
|
|
t.ifStatement(
|
|
t.stringLiteral("nested"),
|
|
t.expressionStatement(t.numericLiteral(1)),
|
|
),
|
|
),
|
|
t.expressionStatement(t.stringLiteral("alt")),
|
|
);
|
|
|
|
const ast = parse(generate(ifStatement).code);
|
|
expect(ast.program.body[0].consequent.type).toBe("BlockStatement");
|
|
});
|
|
|
|
it("prints directives in block with empty body", function () {
|
|
const blockStatement = t.blockStatement(
|
|
[],
|
|
[t.directive(t.directiveLiteral("use strict"))],
|
|
);
|
|
|
|
const output = generate(blockStatement).code;
|
|
expect(output).toBe(`{
|
|
"use strict";
|
|
}`);
|
|
});
|
|
|
|
it("flow object indentation", function () {
|
|
const objectStatement = t.objectTypeAnnotation([
|
|
t.objectTypeProperty(t.identifier("bar"), t.stringTypeAnnotation()),
|
|
]);
|
|
|
|
const output = generate(objectStatement).code;
|
|
expect(output).toBe(`{
|
|
bar: string
|
|
}`);
|
|
});
|
|
|
|
it("flow object exact", function () {
|
|
const objectStatement = t.objectTypeAnnotation(
|
|
[t.objectTypeProperty(t.identifier("bar"), t.stringTypeAnnotation())],
|
|
undefined,
|
|
undefined,
|
|
undefined,
|
|
true,
|
|
);
|
|
|
|
const output = generate(objectStatement).code;
|
|
expect(output).toBe(`{|
|
|
bar: string
|
|
|}`);
|
|
});
|
|
|
|
it("flow object indentation with empty leading ObjectTypeProperty", function () {
|
|
const objectStatement = t.objectTypeAnnotation(
|
|
[],
|
|
[
|
|
t.objectTypeIndexer(
|
|
t.identifier("key"),
|
|
t.anyTypeAnnotation(),
|
|
t.numberTypeAnnotation(),
|
|
),
|
|
],
|
|
);
|
|
|
|
const output = generate(objectStatement).code;
|
|
|
|
expect(output).toBe(`{
|
|
[key: any]: number
|
|
}`);
|
|
});
|
|
|
|
it("flow interface with nullish extends", () => {
|
|
const interfaceDeclaration = t.interfaceDeclaration(
|
|
t.identifier("A"),
|
|
undefined,
|
|
undefined,
|
|
t.objectTypeAnnotation([]),
|
|
);
|
|
const output = generate(interfaceDeclaration).code;
|
|
expect(output).toBe("interface A {}");
|
|
});
|
|
|
|
it("flow function type annotation with no parent", () => {
|
|
const functionTypeAnnotation = t.functionTypeAnnotation(
|
|
null,
|
|
[],
|
|
null,
|
|
t.voidTypeAnnotation(),
|
|
);
|
|
const output = generate(functionTypeAnnotation).code;
|
|
expect(output).toBe("() => void");
|
|
});
|
|
|
|
it("generate a child node with retainLines", () => {
|
|
const node = parse("a;\n\nexpect(a).toMatchInlineSnapshot(`[1, 2]`\n);")
|
|
.program.body[1].expression;
|
|
|
|
expect(node.type).toBe("CallExpression");
|
|
|
|
expect(generate(node, { retainLines: true }).code).toMatchInlineSnapshot(`
|
|
"
|
|
|
|
expect(a).toMatchInlineSnapshot(\`[1, 2]\`
|
|
)"
|
|
`);
|
|
|
|
node.loc.end.line = node.loc.start.line;
|
|
|
|
expect(generate(node, { retainLines: true }).code).toMatchInlineSnapshot(`
|
|
"
|
|
|
|
expect(a).toMatchInlineSnapshot(\`[1, 2]\`)"
|
|
`);
|
|
});
|
|
|
|
describe("directives", function () {
|
|
it("preserves escapes", function () {
|
|
const directive = t.directive(
|
|
t.directiveLiteral(String.raw`us\x65 strict`),
|
|
);
|
|
const output = generate(directive).code;
|
|
|
|
expect(output).toBe(String.raw`"us\x65 strict";`);
|
|
});
|
|
|
|
it("preserves escapes in minified output", function () {
|
|
// https://github.com/babel/babel/issues/4767
|
|
|
|
const directive = t.directive(t.directiveLiteral(String.raw`foo\n\t\r`));
|
|
const output = generate(directive, { minified: true }).code;
|
|
|
|
expect(output).toBe(String.raw`"foo\n\t\r";`);
|
|
});
|
|
|
|
it("unescaped single quote", function () {
|
|
const directive = t.directive(t.directiveLiteral(String.raw`'\'\"`));
|
|
const output = generate(directive).code;
|
|
|
|
expect(output).toBe(String.raw`"'\'\"";`);
|
|
});
|
|
|
|
it("unescaped double quote", function () {
|
|
const directive = t.directive(t.directiveLiteral(String.raw`"\'\"`));
|
|
const output = generate(directive).code;
|
|
|
|
expect(output).toBe(String.raw`'"\'\"';`);
|
|
});
|
|
|
|
it("unescaped single and double quotes together throw", function () {
|
|
const directive = t.directive(t.directiveLiteral(String.raw`'"`));
|
|
|
|
expect(() => {
|
|
generate(directive);
|
|
}).toThrow();
|
|
});
|
|
|
|
it("preserves single quotes if not minified", function () {
|
|
const directive = parse("'use strict';").program.directives[0];
|
|
const output = generate(directive).code;
|
|
|
|
expect(output).toBe("'use strict';");
|
|
});
|
|
|
|
it("converts single quotes to double quotes if minified", function () {
|
|
const directive = parse("'use strict';").program.directives[0];
|
|
const output = generate(directive, { minified: true }).code;
|
|
|
|
expect(output).toBe('"use strict";');
|
|
});
|
|
});
|
|
|
|
describe("typescript generate parentheses if necessary", function () {
|
|
it("wraps around union for array", () => {
|
|
const typeStatement = t.tsArrayType(
|
|
t.tsUnionType([
|
|
t.tsIntersectionType([t.tsNumberKeyword(), t.tsBooleanKeyword()]),
|
|
t.tsNullKeyword(),
|
|
]),
|
|
);
|
|
const output = generate(typeStatement).code;
|
|
expect(output).toBe("(number & boolean | null)[]");
|
|
});
|
|
it("wraps around intersection for array", () => {
|
|
const typeStatement = t.tsArrayType(
|
|
t.tsIntersectionType([t.tsNumberKeyword(), t.tsBooleanKeyword()]),
|
|
);
|
|
const output = generate(typeStatement).code;
|
|
expect(output).toBe("(number & boolean)[]");
|
|
});
|
|
it("wraps around optional type", () => {
|
|
const typeStatement = t.tsOptionalType(
|
|
t.tsIntersectionType([t.tsNumberKeyword(), t.tsBooleanKeyword()]),
|
|
);
|
|
const output = generate(typeStatement).code;
|
|
expect(output).toBe("(number & boolean)?");
|
|
});
|
|
});
|
|
|
|
describe("object expressions", () => {
|
|
it("not wrapped in parentheses when standalone", () => {
|
|
const objectExpression = t.objectExpression([]);
|
|
const output = generate(objectExpression).code;
|
|
expect(output).toBe("{}");
|
|
});
|
|
|
|
it("wrapped in parentheses in expression statement", () => {
|
|
const expressionStatement = t.expressionStatement(t.objectExpression([]));
|
|
const output = generate(expressionStatement).code;
|
|
expect(output).toBe("({});");
|
|
});
|
|
|
|
it("wrapped in parentheses in arrow function", () => {
|
|
const arrowFunctionExpression = t.arrowFunctionExpression(
|
|
[],
|
|
t.objectExpression([]),
|
|
);
|
|
const output = generate(arrowFunctionExpression).code;
|
|
expect(output).toBe("() => ({})");
|
|
});
|
|
|
|
it("not wrapped in parentheses in conditional", () => {
|
|
const conditionalExpression = t.conditionalExpression(
|
|
t.objectExpression([]),
|
|
t.booleanLiteral(true),
|
|
t.booleanLiteral(false),
|
|
);
|
|
const output = generate(conditionalExpression).code;
|
|
expect(output).toBe("{} ? true : false");
|
|
});
|
|
|
|
it("wrapped in parentheses in conditional in expression statement", () => {
|
|
const expressionStatement = t.expressionStatement(
|
|
t.conditionalExpression(
|
|
t.objectExpression([]),
|
|
t.booleanLiteral(true),
|
|
t.booleanLiteral(false),
|
|
),
|
|
);
|
|
const output = generate(expressionStatement).code;
|
|
expect(output).toBe("({}) ? true : false;");
|
|
});
|
|
|
|
it("wrapped in parentheses in conditional in arrow function", () => {
|
|
const arrowFunctionExpression = t.arrowFunctionExpression(
|
|
[],
|
|
t.conditionalExpression(
|
|
t.objectExpression([]),
|
|
t.booleanLiteral(true),
|
|
t.booleanLiteral(false),
|
|
),
|
|
);
|
|
const output = generate(arrowFunctionExpression).code;
|
|
expect(output).toBe("() => ({}) ? true : false");
|
|
});
|
|
|
|
it("not wrapped in parentheses in binary expression", () => {
|
|
const binaryExpression = t.binaryExpression(
|
|
"+",
|
|
t.objectExpression([]),
|
|
t.numericLiteral(1),
|
|
);
|
|
const output = generate(binaryExpression).code;
|
|
expect(output).toBe("{} + 1");
|
|
});
|
|
|
|
it("wrapped in parentheses in binary expression in expression statement", () => {
|
|
const expressionStatement = t.expressionStatement(
|
|
t.binaryExpression("+", t.objectExpression([]), t.numericLiteral(1)),
|
|
);
|
|
const output = generate(expressionStatement).code;
|
|
expect(output).toBe("({}) + 1;");
|
|
});
|
|
|
|
it("wrapped in parentheses in binary expression in arrow function", () => {
|
|
const arrowFunctionExpression = t.arrowFunctionExpression(
|
|
[],
|
|
t.binaryExpression("+", t.objectExpression([]), t.numericLiteral(1)),
|
|
);
|
|
const output = generate(arrowFunctionExpression).code;
|
|
expect(output).toBe("() => ({}) + 1");
|
|
});
|
|
|
|
it("not wrapped in parentheses in sequence expression", () => {
|
|
const sequenceExpression = t.sequenceExpression([
|
|
t.objectExpression([]),
|
|
t.numericLiteral(1),
|
|
]);
|
|
const output = generate(sequenceExpression).code;
|
|
expect(output).toBe("{}, 1");
|
|
});
|
|
|
|
it("wrapped in parentheses in sequence expression in expression statement", () => {
|
|
const expressionStatement = t.expressionStatement(
|
|
t.sequenceExpression([t.objectExpression([]), t.numericLiteral(1)]),
|
|
);
|
|
const output = generate(expressionStatement).code;
|
|
expect(output).toBe("({}), 1;");
|
|
});
|
|
|
|
it("wrapped in parentheses in sequence expression in arrow function", () => {
|
|
const arrowFunctionExpression = t.arrowFunctionExpression(
|
|
[],
|
|
t.sequenceExpression([t.objectExpression([]), t.numericLiteral(1)]),
|
|
);
|
|
const output = generate(arrowFunctionExpression).code;
|
|
expect(output).toBe("() => ({}, 1)");
|
|
});
|
|
});
|
|
|
|
describe("function expressions", () => {
|
|
it("not wrapped in parentheses when standalone", () => {
|
|
const functionExpression = t.functionExpression(
|
|
null,
|
|
[],
|
|
t.blockStatement([]),
|
|
);
|
|
const output = generate(functionExpression).code;
|
|
expect(output).toBe("function () {}");
|
|
});
|
|
|
|
it("wrapped in parentheses in expression statement", () => {
|
|
const expressionStatement = t.expressionStatement(
|
|
t.functionExpression(null, [], t.blockStatement([])),
|
|
);
|
|
const output = generate(expressionStatement).code;
|
|
expect(output).toBe("(function () {});");
|
|
});
|
|
|
|
it("wrapped in parentheses in export default declaration", () => {
|
|
const exportDefaultDeclaration = t.exportDefaultDeclaration(
|
|
t.functionExpression(null, [], t.blockStatement([])),
|
|
);
|
|
const output = generate(exportDefaultDeclaration).code;
|
|
expect(output).toBe("export default (function () {});");
|
|
});
|
|
});
|
|
|
|
describe("class expressions", () => {
|
|
it("not wrapped in parentheses when standalone", () => {
|
|
const classExpression = t.classExpression(null, null, t.classBody([]));
|
|
const output = generate(classExpression).code;
|
|
expect(output).toBe("class {}");
|
|
});
|
|
|
|
it("wrapped in parentheses in expression statement", () => {
|
|
const expressionStatement = t.expressionStatement(
|
|
t.classExpression(null, null, t.classBody([])),
|
|
);
|
|
const output = generate(expressionStatement).code;
|
|
expect(output).toBe("(class {});");
|
|
});
|
|
|
|
it("wrapped in parentheses in export default declaration", () => {
|
|
const exportDefaultDeclaration = t.exportDefaultDeclaration(
|
|
t.classExpression(null, null, t.classBody([])),
|
|
);
|
|
const output = generate(exportDefaultDeclaration).code;
|
|
expect(output).toBe("export default (class {});");
|
|
});
|
|
});
|
|
|
|
describe("jsescOption.minimal", () => {
|
|
const string = t.stringLiteral("\u8868\u683C_\u526F\u672C");
|
|
|
|
it("true", () => {
|
|
const output = generate(string, { jsescOption: { minimal: true } }).code;
|
|
expect(output).toBe(`"表格_副本"`);
|
|
});
|
|
|
|
it("false", () => {
|
|
const output = generate(string, { jsescOption: { minimal: false } }).code;
|
|
expect(output).toBe(`"\\u8868\\u683C_\\u526F\\u672C"`);
|
|
});
|
|
|
|
it("default", () => {
|
|
const output = generate(string).code;
|
|
|
|
expect(output).toBe(`"表格_副本"`);
|
|
});
|
|
});
|
|
|
|
describe("typescript interface declaration", () => {
|
|
it("empty extends array", () => {
|
|
const tsInterfaceDeclaration = t.tsInterfaceDeclaration(
|
|
t.identifier("A"),
|
|
undefined,
|
|
[],
|
|
t.tsInterfaceBody([]),
|
|
);
|
|
const output = generate(tsInterfaceDeclaration).code;
|
|
expect(output).toBe("interface A {}");
|
|
});
|
|
});
|
|
|
|
describe("identifier let", () => {
|
|
it("detects open bracket from non-optional OptionalMemberExpression", () => {
|
|
const ast = parse(`for (let?.[x];;);`, {
|
|
sourceType: "script",
|
|
strictMode: "false",
|
|
});
|
|
ast.program.body[0].init.optional = false;
|
|
const output = generate(ast).code;
|
|
expect(output).toBe("for ((let)[x];;);");
|
|
});
|
|
});
|
|
|
|
describe("should print inner comments even if there are no suitable inner locations", () => {
|
|
it("atomic node", () => {
|
|
const id = t.identifier("foo");
|
|
id.innerComments = [{ type: "CommentBlock", value: "foo" }];
|
|
expect(generate(id).code).toMatchInlineSnapshot(`"foo /*foo*/"`);
|
|
});
|
|
|
|
it("node without inner locations", () => {
|
|
const expr = t.binaryExpression(
|
|
"+",
|
|
t.numericLiteral(1),
|
|
t.numericLiteral(2),
|
|
);
|
|
expr.innerComments = [{ type: "CommentBlock", value: "foo" }];
|
|
expect(generate(expr).code).toMatchInlineSnapshot(`"1 + 2 /*foo*/"`);
|
|
});
|
|
|
|
it("comment skipped in arrow function because of newlines", () => {
|
|
const arrow = t.arrowFunctionExpression(
|
|
[t.identifier("x"), t.identifier("y")],
|
|
t.identifier("z"),
|
|
);
|
|
arrow.innerComments = [
|
|
{ type: "CommentBlock", value: "foo" },
|
|
{ type: "CommentBlock", value: "new\nline" },
|
|
];
|
|
expect(generate(arrow).code).toMatchInlineSnapshot(`
|
|
"(x, y) /*foo*/ => z
|
|
/*new
|
|
line*/"
|
|
`);
|
|
});
|
|
});
|
|
|
|
it("comment in arrow function with return type", () => {
|
|
const arrow = t.arrowFunctionExpression(
|
|
[t.identifier("x"), t.identifier("y")],
|
|
t.identifier("z"),
|
|
);
|
|
arrow.returnType = t.tsTypeAnnotation(t.tsAnyKeyword());
|
|
arrow.returnType.trailingComments = [
|
|
{ type: "CommentBlock", value: "foo" },
|
|
// This comment is dropped. There is no way to safely print it
|
|
// as a trailingComment of the return type.
|
|
{ type: "CommentBlock", value: "new\nline" },
|
|
];
|
|
expect(generate(arrow).code).toMatchInlineSnapshot(
|
|
`"(x, y): any /*foo*/ => z"`,
|
|
);
|
|
});
|
|
|
|
it("multi-line leading comment after return", () => {
|
|
const val = t.identifier("val");
|
|
val.leadingComments = [{ type: "CommentBlock", value: "new\nline" }];
|
|
expect(generate(t.returnStatement(val)).code).toMatch(`return (
|
|
/*new
|
|
line*/
|
|
val
|
|
);`);
|
|
});
|
|
|
|
it("multi-line leading comment after return 2", () => {
|
|
const ast = parse(
|
|
`return (
|
|
/*new
|
|
line*/ val);`,
|
|
{
|
|
allowReturnOutsideFunction: true,
|
|
},
|
|
);
|
|
// Remove `parenthesized`
|
|
ast.program.body[0].argument.extra = null;
|
|
expect(generate(ast).code).toMatchInlineSnapshot(`
|
|
"return (
|
|
/*new
|
|
line*/
|
|
val
|
|
);"
|
|
`);
|
|
});
|
|
|
|
it("multi-line leading comment after return compact", () => {
|
|
const val = t.identifier("val");
|
|
val.leadingComments = [{ type: "CommentBlock", value: "new\nline" }];
|
|
expect(
|
|
generate(t.returnStatement(val), {
|
|
compact: true,
|
|
}).code,
|
|
).toMatchInlineSnapshot(`
|
|
"return(/*new
|
|
line*/val);"
|
|
`);
|
|
});
|
|
|
|
it("multi-line leading comment after return concise", () => {
|
|
const val = t.identifier("val");
|
|
val.leadingComments = [{ type: "CommentBlock", value: "new\nline" }];
|
|
expect(
|
|
generate(t.returnStatement(val), {
|
|
concise: true,
|
|
}).code,
|
|
).toMatchInlineSnapshot(`
|
|
"return ( /*new
|
|
line*/ val );"
|
|
`);
|
|
});
|
|
|
|
it("correctly indenting when `retainLines`", () => {
|
|
const ast = parse(
|
|
`
|
|
export const App = () => {
|
|
return (
|
|
/**
|
|
* First
|
|
*/
|
|
2
|
|
);
|
|
};
|
|
|
|
/**
|
|
* Second
|
|
*/`,
|
|
{
|
|
sourceType: "module",
|
|
},
|
|
);
|
|
|
|
expect(generate(ast, { retainLines: true }).code).toMatchInlineSnapshot(`
|
|
"
|
|
export const App = () => {
|
|
return (
|
|
/**
|
|
* First
|
|
*/
|
|
2);
|
|
|
|
};
|
|
|
|
/**
|
|
* Second
|
|
*/"
|
|
`);
|
|
});
|
|
});
|
|
|
|
const suites = fixtures(new URL("./fixtures", import.meta.url));
|
|
|
|
afterEach(() => {
|
|
jest.restoreAllMocks();
|
|
});
|
|
|
|
suites.forEach(function (testSuite) {
|
|
describe("generation/" + testSuite.title, function () {
|
|
testSuite.tests.forEach(function (task) {
|
|
const testFn = task.disabled ? it.skip : it;
|
|
|
|
testFn(
|
|
task.title,
|
|
|
|
function () {
|
|
const expected = task.expect;
|
|
const actual = task.actual;
|
|
const actualCode = actual.code;
|
|
|
|
if (actualCode) {
|
|
const parserOpts = {
|
|
filename: actual.loc,
|
|
plugins: task.options.plugins || [],
|
|
strictMode: task.options.strictMode === false ? false : true,
|
|
sourceType: "module",
|
|
sourceMaps: !!task.sourceMap,
|
|
...task.options.parserOpts,
|
|
};
|
|
const actualAst = parse(actualCode, parserOpts);
|
|
const options = {
|
|
sourceFileName: path.relative(__dirname, actual.loc),
|
|
...task.options,
|
|
sourceMaps: task.sourceMap ? true : task.options.sourceMaps,
|
|
};
|
|
|
|
const run = () => {
|
|
return generate(actualAst, options, actualCode);
|
|
};
|
|
|
|
const throwMsg = options.throws;
|
|
if (throwMsg) {
|
|
expect(() => run()).toThrow(
|
|
throwMsg === true ? undefined : throwMsg,
|
|
);
|
|
} else {
|
|
jest.spyOn(console, "warn").mockImplementation(() => {});
|
|
|
|
const result = run();
|
|
|
|
if (
|
|
options.warns &&
|
|
(!process.env.IS_PUBLISH || !options.noWarnInPublishBuild)
|
|
) {
|
|
expect(console.warn).toHaveBeenCalledWith(
|
|
expect.stringContaining(options.warns),
|
|
);
|
|
} else {
|
|
expect(console.warn).not.toHaveBeenCalled();
|
|
}
|
|
|
|
if (options.sourceMaps) {
|
|
try {
|
|
expect(result.map).toEqual(task.sourceMap);
|
|
} catch (e) {
|
|
if (!process.env.OVERWRITE && task.sourceMap) throw e;
|
|
console.log(`Updated test file: ${task.sourceMapFile.loc}`);
|
|
fs.writeFileSync(
|
|
task.sourceMapFile.loc,
|
|
JSON.stringify(result.map, null, 2),
|
|
);
|
|
}
|
|
}
|
|
|
|
if (
|
|
!expected.code &&
|
|
result.code &&
|
|
fs.statSync(path.dirname(expected.loc)).isDirectory() &&
|
|
!process.env.CI
|
|
) {
|
|
console.log(`New test file created: ${expected.loc}`);
|
|
fs.writeFileSync(expected.loc, result.code);
|
|
} else {
|
|
try {
|
|
expect(result.code).toBe(expected.code);
|
|
if (!options.expectedReParseError) {
|
|
expect(() => {
|
|
parse(result.code, parserOpts);
|
|
}).not.toThrow();
|
|
}
|
|
} catch (e) {
|
|
if (!process.env.OVERWRITE) throw e;
|
|
console.log(`Updated test file: ${expected.loc}`);
|
|
fs.writeFileSync(expected.loc, result.code);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
);
|
|
});
|
|
});
|
|
});
|