Skip to content

Commit 4ed0334

Browse files
committed
more fixes and tests
1 parent 5da0681 commit 4ed0334

File tree

3 files changed

+117
-11
lines changed

3 files changed

+117
-11
lines changed
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2+
3+
exports[`transpiles TypeScript class expressions 1`] = `
4+
"class Foo {
5+
}
6+
"
7+
`;
8+
9+
exports[`transpiles TypeScript expressions 1`] = `"(1 + 2)"`;
10+
11+
exports[`transpiles TypeScript expressions 2`] = `"(1, 2)"`;
12+
13+
exports[`transpiles TypeScript expressions 3`] = `"(1, 2)"`;
14+
15+
exports[`transpiles TypeScript expressions 4`] = `"((1), (2))"`;
16+
17+
exports[`transpiles TypeScript expressions 5`] = `"((1 + 2))"`;
18+
19+
exports[`transpiles TypeScript expressions 6`] = `"({ x: 42 })"`;
20+
21+
exports[`transpiles TypeScript expressions 7`] = `"(({ x: 42 }))"`;
22+
23+
exports[`transpiles TypeScript function expressions 1`] = `
24+
"function foo() { }
25+
"
26+
`;
27+
28+
exports[`transpiles TypeScript imports 1`] = `
29+
"import { foo } from "npm:bar";
30+
"
31+
`;
32+
33+
exports[`transpiles TypeScript imports 2`] = `""`;
34+
35+
exports[`transpiles TypeScript statements 1`] = `
36+
"1 + 2;
37+
"
38+
`;
39+
40+
exports[`transpiles TypeScript statements 2`] = `
41+
"1, 2;
42+
"
43+
`;
44+
45+
exports[`transpiles TypeScript statements 3`] = `
46+
"(1), (2);
47+
"
48+
`;
49+
50+
exports[`transpiles TypeScript statements 4`] = `
51+
"(1 + 2);
52+
"
53+
`;
54+
55+
exports[`transpiles TypeScript statements 5`] = `
56+
"{
57+
x: 42;
58+
}
59+
;
60+
"
61+
`;
62+
63+
exports[`transpiles TypeScript statements 6`] = `
64+
"({ x: 42 });
65+
"
66+
`;

src/javascript/typescript.test.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import {assert, expect, it} from "vitest";
2+
import {transpileTypeScript} from "./typescript.js";
3+
4+
it("transpiles TypeScript expressions", () => {
5+
expect(transpileTypeScript("1 + 2")).toMatchSnapshot();
6+
expect(transpileTypeScript("1, 2")).toMatchSnapshot();
7+
expect(transpileTypeScript("1, 2 // comment")).toMatchSnapshot();
8+
expect(transpileTypeScript("(1), (2)")).toMatchSnapshot();
9+
expect(transpileTypeScript("(1 + 2)")).toMatchSnapshot();
10+
expect(transpileTypeScript("{x: 42}")).toMatchSnapshot();
11+
expect(transpileTypeScript("({x: 42})")).toMatchSnapshot();
12+
});
13+
14+
it("transpiles TypeScript function expressions", () => {
15+
expect(transpileTypeScript("function foo() {}")).toMatchSnapshot();
16+
});
17+
18+
it("transpiles TypeScript class expressions", () => {
19+
expect(transpileTypeScript("class Foo {}")).toMatchSnapshot();
20+
});
21+
22+
it("transpiles TypeScript statements", () => {
23+
expect(transpileTypeScript("1 + 2;")).toMatchSnapshot();
24+
expect(transpileTypeScript("1, 2;")).toMatchSnapshot();
25+
expect(transpileTypeScript("(1), (2);")).toMatchSnapshot();
26+
expect(transpileTypeScript("(1 + 2);")).toMatchSnapshot();
27+
expect(transpileTypeScript("{x: 42};")).toMatchSnapshot();
28+
expect(transpileTypeScript("({x: 42});")).toMatchSnapshot();
29+
});
30+
31+
it("transpiles TypeScript imports", () => {
32+
expect(transpileTypeScript('import {foo} from "npm:bar";')).toMatchSnapshot();
33+
expect(transpileTypeScript('import type {foo} from "npm:bar";')).toMatchSnapshot();
34+
});
35+
36+
it("throws SyntaxError on invalid syntax", () => {
37+
assert.throws(() => transpileTypeScript("1) + 2"), SyntaxError);
38+
assert.throws(() => transpileTypeScript("(1 + 2"), SyntaxError);
39+
assert.throws(() => transpileTypeScript("1 + 2 /* comment"), SyntaxError);
40+
});

src/javascript/typescript.ts

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,16 @@ const compilerOptions = {
1616
} as const;
1717

1818
export function transpileTypeScript(input: string): string {
19-
const expr = asExpression(input);
19+
const expr = maybeExpression(input);
2020
if (expr) return trimTrailingSemicolon(transpile(expr, compilerOptions));
2121
parseTypeScript(input); // enforce valid syntax
2222
return transpile(input, compilerOptions);
2323
}
2424

2525
/** If the given is an expression (not a statement), returns it with parens. */
26-
function asExpression(input: string): string | undefined {
27-
if (hasUnmatchedParens(input)) return; // disallow funny business
28-
const expr = `(${trim(input)})`;
26+
function maybeExpression(input: string): string | undefined {
27+
if (!hasMatchedParens(input)) return; // disallow funny business
28+
const expr = withParens(input);
2929
if (!isSolitaryExpression(expr)) return;
3030
return expr;
3131
}
@@ -81,25 +81,25 @@ function* tokenize(input: string): Generator<Token> {
8181
}
8282
}
8383

84-
/** Returns true if the specified input has mismatched parens. */
85-
function hasUnmatchedParens(input: string): boolean {
84+
/** Returns true if the specified input has matched parens. */
85+
function hasMatchedParens(input: string): boolean {
8686
let depth = 0;
8787
for (const t of tokenize(input)) {
8888
if (t.type === tokTypes.parenL) ++depth;
89-
else if (t.type === tokTypes.parenR && --depth < 0) return true;
89+
else if (t.type === tokTypes.parenR && --depth < 0) return false;
9090
}
91-
return false;
91+
return depth === 0;
9292
}
9393

94-
/** Removes leading and trailing whitespace around the specified input. */
95-
function trim(input: string): string {
94+
/** Wraps the specified input with parentheses. */
95+
function withParens(input: string): string {
9696
let start;
9797
let end;
9898
for (const t of tokenize(input)) {
9999
start ??= t;
100100
end = t;
101101
}
102-
return input.slice(start?.start, end?.end);
102+
return `(${input.slice(start?.start, end?.end)})`;
103103
}
104104

105105
/** Removes a trailing semicolon, if present. */

0 commit comments

Comments
 (0)