-
Notifications
You must be signed in to change notification settings - Fork 13
/
Copy pathvalid.test.ts
174 lines (157 loc) · 5.97 KB
/
valid.test.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
import { it, mock } from "node:test";
import assert from "node:assert";
import * as fs from "node:fs";
import { join } from "node:path";
import ts from "typescript";
import { casesDir, outputForInput, testFixture } from "./fixture/helpers.js";
import tsBlankSpace, { blankSourceFile } from "../src/index.ts";
for (const filename of fs.readdirSync(casesDir)) {
if (!filename.endsWith(".ts")) {
continue;
}
it(`fixture: ${filename}`, () => {
const input = join(casesDir, filename);
const output = outputForInput(input);
testFixture(input, output);
});
}
it("handles `=>` on new line", (t) => {
// In this case we can't only blank out the type annotation,
// as that would result in:
//
// [1].map((v)
//
// => [v])
//
// which is not a valid arrow function because ECMAScript
// doesn't allow a newline before the `=>` part of an arrow
const inputTs = [`[1].map((v)`, `:number[`, `]=>[v]);`].join("\n");
const onError = mock.fn();
const jsOutput = tsBlankSpace(inputTs, onError);
t.diagnostic(JSON.stringify(jsOutput));
assert.equal(onError.mock.callCount(), 0, "there should be no errors");
const inputLines = inputTs.split("\n");
const outputLines = inputTs.split("\n");
assert.equal(outputLines.length, inputLines.length, "Line numbers should not change");
assert(outputLines[0].includes("(v)"));
assert.equal(
outputLines[0].indexOf("(v)"),
inputLines[0].indexOf("(v)"),
"the position of `(v)` should not have moved within its line",
);
assert(outputLines[2].includes("[v]"));
assert.equal(
outputLines[2].indexOf("[v]"),
inputLines[2].indexOf("[v]"),
"the position of `[v]` should not have moved within its line",
);
const evaluatedCode = new Function(`return ${jsOutput}`)();
assert.deepEqual(evaluatedCode, [[1]], "evaluated JavaScript matches the semantics of the original TypeScript");
});
it("handles blanking surrogate pairs", () => {
const onError = mock.fn();
const tsInput = `function f(): "\ud83d\udca5" {}`;
const jsOutput = tsBlankSpace(tsInput, onError);
assert.equal(onError.mock.callCount(), 0, "there should be no errors");
assert.equal(jsOutput, "function f() {}");
assert.equal(jsOutput.length, tsInput.length);
});
it("handles default export", () => {
// TypeScript uses an `ExportAssignment` node for both
// `export default ...` and `export =`.
// The former is supported, the latter is an error.
const onError = mock.fn();
const tsInput = `
export default/**/1/**/;
`;
const jsOutput = tsBlankSpace(tsInput, onError);
assert.equal(onError.mock.callCount(), 0, "there should be no errors");
assert.equal(jsOutput, tsInput);
});
it("allows ambient enum", () => {
const onError = mock.fn();
const jsOutput = tsBlankSpace(`declare enum E1 {}\n`, onError);
assert.equal(onError.mock.callCount(), 0);
assert.equal(jsOutput, " \n");
});
it("allows declared namespace value", () => {
const onError = mock.fn();
const jsOutput = tsBlankSpace(`declare namespace N {}\n`, onError);
assert.equal(onError.mock.callCount(), 0);
assert.equal(jsOutput, " \n");
});
it("allows declared module value", () => {
const onError = mock.fn();
const jsOutput = tsBlankSpace(`declare module M {}\n`, onError);
assert.equal(onError.mock.callCount(), 0);
assert.equal(jsOutput, " \n");
});
it("TSX is preserved in the output", () => {
const onError = mock.fn();
const tsxInput = `const elm = <div>{x as string}</div>;\n`;
const tsxSource = ts.createSourceFile("input.tsx", tsxInput, ts.ScriptTarget.ESNext, false, ts.ScriptKind.TSX);
const jsxOutput = blankSourceFile(tsxSource, onError);
assert.equal(onError.mock.callCount(), 0, "there should be no errors");
assert.equal(jsxOutput, "const elm = <div>{x }</div>;\n");
});
// Easy to miss this case as it's only a single character
it("handles variable definite assignment assertions", () => {
const onError = mock.fn();
const tsInput = `let x: any, y! : string, z: any;\n`;
const jsOutput = tsBlankSpace(tsInput, onError);
assert.equal(onError.mock.callCount(), 0, "there should be no errors");
assert.equal(jsOutput, "let x , y , z ;\n");
});
// Taken from TypeScript's compiler tests because there used to be a bug
// in ts-blank-space where this caused it to hit an infinite loop
it("'parseGenericArrowRatherThanLeftShift'", () => {
// `foo<<` can get scanned as `[foo,<<]` tokens instead of `[foo,<,<]`
const tsInput = `
function foo<T>(_x: T) {}
const b = foo<<T>(x: T) => number>(() => 1);
`;
const expectedOutput = `
function foo (_x ) {}
const b = foo (() => 1);
`;
const onError = mock.fn();
const jsOutput = tsBlankSpace(tsInput, onError);
assert.equal(onError.mock.callCount(), 0, "there should be no errors");
assert.equal(jsOutput, expectedOutput);
});
it("Preserves strict directive after a type declaration", () => {
const tsInput = `
interface I {}
"use strict"
export {}
`;
const expectedOutput = `
${" "}
"use strict"
export {}
`;
const onError = mock.fn();
const jsOutput = tsBlankSpace(tsInput, onError);
assert.equal(onError.mock.callCount(), 0, "there should be no errors");
assert.equal(jsOutput, expectedOutput);
});
it("Preserves nested strict directive after a type declaration", () => {
const tsInput = `
function foo() {
interface I {}
"use strict"
return 1;
}
`;
const expectedOutput = `
function foo() {
${" "}
"use strict"
return 1;
}
`;
const onError = mock.fn();
const jsOutput = tsBlankSpace(tsInput, onError);
assert.equal(onError.mock.callCount(), 0, "there should be no errors");
assert.equal(jsOutput, expectedOutput);
});