@typespec/emitter-framework 0.6.0-dev.1 → 0.6.0-dev.4
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/dist/src/typescript/components/arrow-function.d.ts +17 -0
- package/dist/src/typescript/components/arrow-function.d.ts.map +1 -0
- package/dist/src/typescript/components/arrow-function.js +31 -0
- package/dist/src/typescript/components/arrow-function.js.map +1 -0
- package/dist/src/typescript/components/function-declaration.d.ts +5 -0
- package/dist/src/typescript/components/function-declaration.d.ts.map +1 -1
- package/dist/src/typescript/components/function-declaration.js +5 -1
- package/dist/src/typescript/components/function-declaration.js.map +1 -1
- package/dist/src/typescript/components/function-expression.d.ts +17 -0
- package/dist/src/typescript/components/function-expression.d.ts.map +1 -0
- package/dist/src/typescript/components/function-expression.js +31 -0
- package/dist/src/typescript/components/function-expression.js.map +1 -0
- package/dist/src/typescript/components/function-type.d.ts +17 -0
- package/dist/src/typescript/components/function-type.d.ts.map +1 -0
- package/dist/src/typescript/components/function-type.js +31 -0
- package/dist/src/typescript/components/function-type.js.map +1 -0
- package/dist/src/typescript/components/index.d.ts +6 -0
- package/dist/src/typescript/components/index.d.ts.map +1 -1
- package/dist/src/typescript/components/index.js +6 -0
- package/dist/src/typescript/components/index.js.map +1 -1
- package/dist/src/typescript/components/interface-member.d.ts +1 -2
- package/dist/src/typescript/components/interface-member.d.ts.map +1 -1
- package/dist/src/typescript/components/interface-member.js +3 -19
- package/dist/src/typescript/components/interface-member.js.map +1 -1
- package/dist/src/typescript/components/interface-method.d.ts +15 -0
- package/dist/src/typescript/components/interface-method.d.ts.map +1 -0
- package/dist/src/typescript/components/interface-method.js +34 -0
- package/dist/src/typescript/components/interface-method.js.map +1 -0
- package/dist/src/typescript/components/type-alias-declaration.d.ts +6 -2
- package/dist/src/typescript/components/type-alias-declaration.d.ts.map +1 -1
- package/dist/src/typescript/components/type-alias-declaration.js +7 -2
- package/dist/src/typescript/components/type-alias-declaration.js.map +1 -1
- package/dist/src/typescript/components/type-declaration.d.ts.map +1 -1
- package/dist/src/typescript/components/type-declaration.js +4 -0
- package/dist/src/typescript/components/type-declaration.js.map +1 -1
- package/dist/src/typescript/components/type-expression.d.ts +6 -0
- package/dist/src/typescript/components/type-expression.d.ts.map +1 -1
- package/dist/src/typescript/components/type-expression.js +6 -1
- package/dist/src/typescript/components/type-expression.js.map +1 -1
- package/dist/src/typescript/components/value-expression.d.ts +19 -0
- package/dist/src/typescript/components/value-expression.d.ts.map +1 -0
- package/dist/src/typescript/components/value-expression.js +72 -0
- package/dist/src/typescript/components/value-expression.js.map +1 -0
- package/dist/test/typescript/components/arrow-function.test.d.ts +2 -0
- package/dist/test/typescript/components/arrow-function.test.d.ts.map +1 -0
- package/dist/test/typescript/components/function-expression.test.d.ts +2 -0
- package/dist/test/typescript/components/function-expression.test.d.ts.map +1 -0
- package/dist/test/typescript/components/function-type.test.d.ts +2 -0
- package/dist/test/typescript/components/function-type.test.d.ts.map +1 -0
- package/dist/test/typescript/components/interface-method.test.d.ts +2 -0
- package/dist/test/typescript/components/interface-method.test.d.ts.map +1 -0
- package/dist/test/typescript/components/value-expression.test.d.ts +2 -0
- package/dist/test/typescript/components/value-expression.test.d.ts.map +1 -0
- package/dist/test/typescript/test-host.d.ts +5 -0
- package/dist/test/typescript/test-host.d.ts.map +1 -1
- package/dist/test/utils.d.ts +3 -2
- package/dist/test/utils.d.ts.map +1 -1
- package/package.json +5 -5
- package/src/typescript/components/arrow-function.tsx +39 -0
- package/src/typescript/components/function-declaration.tsx +5 -2
- package/src/typescript/components/function-expression.tsx +41 -0
- package/src/typescript/components/function-type.tsx +38 -0
- package/src/typescript/components/index.ts +6 -0
- package/src/typescript/components/interface-member.tsx +2 -19
- package/src/typescript/components/interface-method.tsx +50 -0
- package/src/typescript/components/type-alias-declaration.tsx +10 -4
- package/src/typescript/components/type-declaration.tsx +2 -0
- package/src/typescript/components/type-expression.tsx +11 -2
- package/src/typescript/components/value-expression.tsx +56 -0
- package/test/typescript/components/arrow-function.test.tsx +85 -0
- package/test/typescript/components/function-expression.test.tsx +85 -0
- package/test/typescript/components/function-type.test.tsx +80 -0
- package/test/typescript/components/interface-declaration.test.tsx +6 -6
- package/test/typescript/components/interface-method.test.tsx +69 -0
- package/test/typescript/components/type-alias-declaration.test.tsx +20 -2
- package/test/typescript/components/value-expression.test.tsx +236 -0
- package/test/typescript/test-host.ts +8 -0
- package/test/utils.ts +8 -1
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { Output, render } from "@alloy-js/core";
|
|
2
|
+
import { d } from "@alloy-js/core/testing";
|
|
3
|
+
import { SourceFile } from "@alloy-js/typescript";
|
|
4
|
+
import { Operation } from "@typespec/compiler";
|
|
5
|
+
import { BasicTestRunner } from "@typespec/compiler/testing";
|
|
6
|
+
import { beforeEach, describe, it } from "vitest";
|
|
7
|
+
import { ArrowFunction } from "../../../src/typescript/components/arrow-function.jsx";
|
|
8
|
+
import { assertFileContents } from "../../utils.js";
|
|
9
|
+
import { createEmitterFrameworkTestRunner } from "../test-host.js";
|
|
10
|
+
|
|
11
|
+
describe("arrow functions with a `type` prop", () => {
|
|
12
|
+
let runner: BasicTestRunner;
|
|
13
|
+
|
|
14
|
+
beforeEach(async () => {
|
|
15
|
+
runner = await createEmitterFrameworkTestRunner();
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it("creates a function", async () => {
|
|
19
|
+
const { getName } = (await runner.compile(`
|
|
20
|
+
@test op getName(id: string): string;
|
|
21
|
+
`)) as { getName: Operation };
|
|
22
|
+
|
|
23
|
+
const res = render(
|
|
24
|
+
<Output>
|
|
25
|
+
<SourceFile path="test.ts">
|
|
26
|
+
<ArrowFunction type={getName}>console.log("Hello!");</ArrowFunction>
|
|
27
|
+
</SourceFile>
|
|
28
|
+
</Output>,
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
assertFileContents(
|
|
32
|
+
res,
|
|
33
|
+
d`
|
|
34
|
+
(id: string): string => {
|
|
35
|
+
console.log("Hello!");
|
|
36
|
+
}
|
|
37
|
+
`,
|
|
38
|
+
);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it("creates an async function", async () => {
|
|
42
|
+
const { getName } = (await runner.compile(`
|
|
43
|
+
@test op getName(id: string): string;
|
|
44
|
+
`)) as { getName: Operation };
|
|
45
|
+
|
|
46
|
+
const res = render(
|
|
47
|
+
<Output>
|
|
48
|
+
<SourceFile path="test.ts">
|
|
49
|
+
<ArrowFunction async type={getName} />
|
|
50
|
+
</SourceFile>
|
|
51
|
+
</Output>,
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
assertFileContents(
|
|
55
|
+
res,
|
|
56
|
+
d`
|
|
57
|
+
async (id: string): Promise<string> => {}
|
|
58
|
+
`,
|
|
59
|
+
);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it("can append extra parameters with raw params provided", async () => {
|
|
63
|
+
const { getName } = (await runner.compile(`
|
|
64
|
+
@test op getName(id: string): string;
|
|
65
|
+
`)) as { getName: Operation };
|
|
66
|
+
|
|
67
|
+
const res = render(
|
|
68
|
+
<Output>
|
|
69
|
+
<SourceFile path="test.ts">
|
|
70
|
+
<ArrowFunction
|
|
71
|
+
type={getName}
|
|
72
|
+
parameters={[{ name: "additionalParam", type: "number" }]}
|
|
73
|
+
/>
|
|
74
|
+
</SourceFile>
|
|
75
|
+
</Output>,
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
assertFileContents(
|
|
79
|
+
res,
|
|
80
|
+
d`
|
|
81
|
+
(additionalParam: number, id: string): string => {}
|
|
82
|
+
`,
|
|
83
|
+
);
|
|
84
|
+
});
|
|
85
|
+
});
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { Output, render } from "@alloy-js/core";
|
|
2
|
+
import { d } from "@alloy-js/core/testing";
|
|
3
|
+
import { SourceFile } from "@alloy-js/typescript";
|
|
4
|
+
import { Operation } from "@typespec/compiler";
|
|
5
|
+
import { BasicTestRunner } from "@typespec/compiler/testing";
|
|
6
|
+
import { beforeEach, describe, it } from "vitest";
|
|
7
|
+
import { FunctionExpression } from "../../../src/typescript/components/function-expression.jsx";
|
|
8
|
+
import { assertFileContents } from "../../utils.js";
|
|
9
|
+
import { createEmitterFrameworkTestRunner } from "../test-host.js";
|
|
10
|
+
|
|
11
|
+
describe("function expressions with a `type` prop", () => {
|
|
12
|
+
let runner: BasicTestRunner;
|
|
13
|
+
|
|
14
|
+
beforeEach(async () => {
|
|
15
|
+
runner = await createEmitterFrameworkTestRunner();
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it("creates a function", async () => {
|
|
19
|
+
const { getName } = (await runner.compile(`
|
|
20
|
+
@test op getName(id: string): string;
|
|
21
|
+
`)) as { getName: Operation };
|
|
22
|
+
|
|
23
|
+
const res = render(
|
|
24
|
+
<Output>
|
|
25
|
+
<SourceFile path="test.ts">
|
|
26
|
+
<FunctionExpression type={getName}>console.log("Hello!");</FunctionExpression>
|
|
27
|
+
</SourceFile>
|
|
28
|
+
</Output>,
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
assertFileContents(
|
|
32
|
+
res,
|
|
33
|
+
d`
|
|
34
|
+
function (id: string): string {
|
|
35
|
+
console.log("Hello!");
|
|
36
|
+
}
|
|
37
|
+
`,
|
|
38
|
+
);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it("creates an async function", async () => {
|
|
42
|
+
const { getName } = (await runner.compile(`
|
|
43
|
+
@test op getName(id: string): string;
|
|
44
|
+
`)) as { getName: Operation };
|
|
45
|
+
|
|
46
|
+
const res = render(
|
|
47
|
+
<Output>
|
|
48
|
+
<SourceFile path="test.ts">
|
|
49
|
+
<FunctionExpression async type={getName} />
|
|
50
|
+
</SourceFile>
|
|
51
|
+
</Output>,
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
assertFileContents(
|
|
55
|
+
res,
|
|
56
|
+
d`
|
|
57
|
+
async function (id: string): Promise<string> {}
|
|
58
|
+
`,
|
|
59
|
+
);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it("can append extra parameters with raw params provided", async () => {
|
|
63
|
+
const { getName } = (await runner.compile(`
|
|
64
|
+
@test op getName(id: string): string;
|
|
65
|
+
`)) as { getName: Operation };
|
|
66
|
+
|
|
67
|
+
const res = render(
|
|
68
|
+
<Output>
|
|
69
|
+
<SourceFile path="test.ts">
|
|
70
|
+
<FunctionExpression
|
|
71
|
+
type={getName}
|
|
72
|
+
parameters={[{ name: "additionalParam", type: "number" }]}
|
|
73
|
+
/>
|
|
74
|
+
</SourceFile>
|
|
75
|
+
</Output>,
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
assertFileContents(
|
|
79
|
+
res,
|
|
80
|
+
d`
|
|
81
|
+
function (additionalParam: number, id: string): string {}
|
|
82
|
+
`,
|
|
83
|
+
);
|
|
84
|
+
});
|
|
85
|
+
});
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { Output, render } from "@alloy-js/core";
|
|
2
|
+
import { d } from "@alloy-js/core/testing";
|
|
3
|
+
import { SourceFile } from "@alloy-js/typescript";
|
|
4
|
+
import { Operation } from "@typespec/compiler";
|
|
5
|
+
import { BasicTestRunner } from "@typespec/compiler/testing";
|
|
6
|
+
import { beforeEach, describe, it } from "vitest";
|
|
7
|
+
import { FunctionType } from "../../../src/typescript/index.js";
|
|
8
|
+
import { assertFileContents } from "../../utils.js";
|
|
9
|
+
import { createEmitterFrameworkTestRunner } from "../test-host.js";
|
|
10
|
+
|
|
11
|
+
describe("function types with a `type` prop", () => {
|
|
12
|
+
let runner: BasicTestRunner;
|
|
13
|
+
|
|
14
|
+
beforeEach(async () => {
|
|
15
|
+
runner = await createEmitterFrameworkTestRunner();
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it("creates a function type", async () => {
|
|
19
|
+
const { getName } = (await runner.compile(`
|
|
20
|
+
@test op getName(id: string): string;
|
|
21
|
+
`)) as { getName: Operation };
|
|
22
|
+
|
|
23
|
+
const res = render(
|
|
24
|
+
<Output>
|
|
25
|
+
<SourceFile path="test.ts">
|
|
26
|
+
<FunctionType type={getName} />
|
|
27
|
+
</SourceFile>
|
|
28
|
+
</Output>,
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
assertFileContents(
|
|
32
|
+
res,
|
|
33
|
+
d`
|
|
34
|
+
(id: string) => string
|
|
35
|
+
`,
|
|
36
|
+
);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("creates an async function type", async () => {
|
|
40
|
+
const { getName } = (await runner.compile(`
|
|
41
|
+
@test op getName(id: string): string;
|
|
42
|
+
`)) as { getName: Operation };
|
|
43
|
+
|
|
44
|
+
const res = render(
|
|
45
|
+
<Output>
|
|
46
|
+
<SourceFile path="test.ts">
|
|
47
|
+
<FunctionType async type={getName} />
|
|
48
|
+
</SourceFile>
|
|
49
|
+
</Output>,
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
assertFileContents(
|
|
53
|
+
res,
|
|
54
|
+
d`
|
|
55
|
+
(id: string) => Promise<string>
|
|
56
|
+
`,
|
|
57
|
+
);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it("can append extra parameters with raw params provided", async () => {
|
|
61
|
+
const { getName } = (await runner.compile(`
|
|
62
|
+
@test op getName(id: string): string;
|
|
63
|
+
`)) as { getName: Operation };
|
|
64
|
+
|
|
65
|
+
const res = render(
|
|
66
|
+
<Output>
|
|
67
|
+
<SourceFile path="test.ts">
|
|
68
|
+
<FunctionType type={getName} parameters={[{ name: "additionalParam", type: "number" }]} />
|
|
69
|
+
</SourceFile>
|
|
70
|
+
</Output>,
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
assertFileContents(
|
|
74
|
+
res,
|
|
75
|
+
d`
|
|
76
|
+
(additionalParam: number, id: string) => string
|
|
77
|
+
`,
|
|
78
|
+
);
|
|
79
|
+
});
|
|
80
|
+
});
|
|
@@ -564,7 +564,7 @@ describe("Typescript Interface", () => {
|
|
|
564
564
|
const actualContent = await format(testFile.contents as string, { parser: "typescript" });
|
|
565
565
|
const expectedContent = await format(
|
|
566
566
|
`export interface WidgetOperations {
|
|
567
|
-
getName
|
|
567
|
+
getName(id: string): string;
|
|
568
568
|
}`,
|
|
569
569
|
{
|
|
570
570
|
parser: "typescript",
|
|
@@ -605,8 +605,8 @@ describe("Typescript Interface", () => {
|
|
|
605
605
|
const actualContent = await format(testFile.contents as string, { parser: "typescript" });
|
|
606
606
|
const expectedContent = await format(
|
|
607
607
|
`export interface WidgetOperations {
|
|
608
|
-
getName
|
|
609
|
-
getOtherName
|
|
608
|
+
getName(foo: Foo): string;
|
|
609
|
+
getOtherName(name: string): string
|
|
610
610
|
}
|
|
611
611
|
export interface Foo {
|
|
612
612
|
name: string;
|
|
@@ -654,7 +654,7 @@ describe("Typescript Interface", () => {
|
|
|
654
654
|
const actualContent = await format(testFile.contents as string, { parser: "typescript" });
|
|
655
655
|
const expectedContent = await format(
|
|
656
656
|
`export interface WidgetOperations {
|
|
657
|
-
getName
|
|
657
|
+
getName(id: string): Widget;
|
|
658
658
|
}
|
|
659
659
|
export interface Widget {
|
|
660
660
|
id: string;
|
|
@@ -707,8 +707,8 @@ describe("Typescript Interface", () => {
|
|
|
707
707
|
const actualContent = await format(testFile.contents as string, { parser: "typescript" });
|
|
708
708
|
const expectedContent = await format(
|
|
709
709
|
`export interface WidgetOperationsExtended {
|
|
710
|
-
getName
|
|
711
|
-
delete
|
|
710
|
+
getName(id: string): Widget;
|
|
711
|
+
delete(id: string): void;
|
|
712
712
|
}
|
|
713
713
|
export interface Widget {
|
|
714
714
|
id: string;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { Output, render } from "@alloy-js/core";
|
|
2
|
+
import { d } from "@alloy-js/core/testing";
|
|
3
|
+
import { InterfaceDeclaration, SourceFile } from "@alloy-js/typescript";
|
|
4
|
+
import { Operation } from "@typespec/compiler";
|
|
5
|
+
import { BasicTestRunner } from "@typespec/compiler/testing";
|
|
6
|
+
import { beforeEach, describe, it } from "vitest";
|
|
7
|
+
import { InterfaceMethod } from "../../../src/typescript/components/interface-method.jsx";
|
|
8
|
+
import { assertFileContents } from "../../utils.js";
|
|
9
|
+
import { createEmitterFrameworkTestRunner } from "../test-host.js";
|
|
10
|
+
|
|
11
|
+
describe("interface methods with a `type` prop", () => {
|
|
12
|
+
let runner: BasicTestRunner;
|
|
13
|
+
|
|
14
|
+
beforeEach(async () => {
|
|
15
|
+
runner = await createEmitterFrameworkTestRunner();
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it("creates a interface member", async () => {
|
|
19
|
+
const { getName } = (await runner.compile(`
|
|
20
|
+
@test op getName(id: string): string;
|
|
21
|
+
`)) as { getName: Operation };
|
|
22
|
+
|
|
23
|
+
const res = render(
|
|
24
|
+
<Output>
|
|
25
|
+
<SourceFile path="test.ts">
|
|
26
|
+
<InterfaceDeclaration name="basicInterface">
|
|
27
|
+
<InterfaceMethod type={getName} name={getName.name} />
|
|
28
|
+
</InterfaceDeclaration>
|
|
29
|
+
</SourceFile>
|
|
30
|
+
</Output>,
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
assertFileContents(
|
|
34
|
+
res,
|
|
35
|
+
d`
|
|
36
|
+
interface basicInterface {
|
|
37
|
+
getName(id: string): string
|
|
38
|
+
}
|
|
39
|
+
`,
|
|
40
|
+
);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it("creates an async interface function", async () => {
|
|
44
|
+
const { getName } = (await runner.compile(`
|
|
45
|
+
@test op getName(id: string): string;
|
|
46
|
+
`)) as { getName: Operation };
|
|
47
|
+
|
|
48
|
+
const res = render(
|
|
49
|
+
<Output>
|
|
50
|
+
<SourceFile path="test.ts">
|
|
51
|
+
<InterfaceDeclaration name="basicInterface">
|
|
52
|
+
<InterfaceMethod async type={getName} />
|
|
53
|
+
</InterfaceDeclaration>
|
|
54
|
+
</SourceFile>
|
|
55
|
+
</Output>,
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
assertFileContents(
|
|
59
|
+
res,
|
|
60
|
+
d`
|
|
61
|
+
interface basicInterface {
|
|
62
|
+
getName(id: string): Promise<string>
|
|
63
|
+
}
|
|
64
|
+
`,
|
|
65
|
+
);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it.todo("can append extra parameters with raw params provided", async () => {});
|
|
69
|
+
});
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { Output, render } from "@alloy-js/core";
|
|
2
2
|
import { SourceFile } from "@alloy-js/typescript";
|
|
3
|
-
import { Namespace } from "@typespec/compiler";
|
|
3
|
+
import { Namespace, Operation } from "@typespec/compiler";
|
|
4
4
|
import { format } from "prettier";
|
|
5
5
|
import { assert, describe, expect, it } from "vitest";
|
|
6
6
|
import { TypeAliasDeclaration } from "../../../src/typescript/components/type-alias-declaration.jsx";
|
|
7
|
-
import {
|
|
7
|
+
import { assertFileContents } from "../../utils.js";
|
|
8
|
+
import { createEmitterFrameworkTestRunner, getProgram } from "../test-host.js";
|
|
8
9
|
|
|
9
10
|
describe("Typescript Type Alias Declaration", () => {
|
|
10
11
|
describe("Type Alias bound to Typespec Scalar", () => {
|
|
@@ -117,4 +118,21 @@ describe("Typescript Type Alias Declaration", () => {
|
|
|
117
118
|
});
|
|
118
119
|
});
|
|
119
120
|
});
|
|
121
|
+
|
|
122
|
+
it("creates a type alias of a function", async () => {
|
|
123
|
+
const runner = await createEmitterFrameworkTestRunner();
|
|
124
|
+
const { getName } = (await runner.compile(`
|
|
125
|
+
@test op getName(id: string): string;
|
|
126
|
+
`)) as { getName: Operation };
|
|
127
|
+
|
|
128
|
+
const res = render(
|
|
129
|
+
<Output>
|
|
130
|
+
<SourceFile path="test.ts">
|
|
131
|
+
<TypeAliasDeclaration type={getName} />
|
|
132
|
+
</SourceFile>
|
|
133
|
+
</Output>,
|
|
134
|
+
);
|
|
135
|
+
|
|
136
|
+
assertFileContents(res, "type getName = (id: string) => string;");
|
|
137
|
+
});
|
|
120
138
|
});
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import { Output, render } from "@alloy-js/core";
|
|
2
|
+
import { dedent } from "@alloy-js/core/testing";
|
|
3
|
+
import { SourceFile } from "@alloy-js/typescript";
|
|
4
|
+
import { EnumValue, Model, Namespace, Numeric, NumericValue, Value } from "@typespec/compiler";
|
|
5
|
+
import { $ } from "@typespec/compiler/experimental/typekit";
|
|
6
|
+
import { assert, beforeAll, describe, expect, it } from "vitest";
|
|
7
|
+
import { ValueExpression } from "../../../src/typescript/components/value-expression.js";
|
|
8
|
+
import { getProgram, initEmptyProgram } from "../test-host.js";
|
|
9
|
+
|
|
10
|
+
beforeAll(async () => {
|
|
11
|
+
await initEmptyProgram();
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it("renders strings", async () => {
|
|
15
|
+
const value = $.value.createString("test");
|
|
16
|
+
|
|
17
|
+
await testValueExpression(value, `"test"`);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
describe("numeric values", () => {
|
|
21
|
+
it("renders integers", async () => {
|
|
22
|
+
const value = $.value.createNumeric(42);
|
|
23
|
+
|
|
24
|
+
await testValueExpression(value, `42`);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it("renders decimals", async () => {
|
|
28
|
+
const value = $.value.createNumeric(42.5);
|
|
29
|
+
|
|
30
|
+
await testValueExpression(value, `42.5`);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it("renders bigints", async () => {
|
|
34
|
+
const digits = "1234567890123456789012345678901234567890";
|
|
35
|
+
const value: NumericValue = {
|
|
36
|
+
entityKind: "Value",
|
|
37
|
+
valueKind: "NumericValue",
|
|
38
|
+
value: Numeric(digits),
|
|
39
|
+
} as NumericValue;
|
|
40
|
+
|
|
41
|
+
await testValueExpression(value, `${digits}n`);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it("throws on invalid numbers", async () => {
|
|
45
|
+
const digits = "123456789123456789.112233445566778899";
|
|
46
|
+
const value: NumericValue = {
|
|
47
|
+
entityKind: "Value",
|
|
48
|
+
valueKind: "NumericValue",
|
|
49
|
+
value: Numeric(digits),
|
|
50
|
+
} as NumericValue;
|
|
51
|
+
|
|
52
|
+
await expect(testValueExpression(value, ``)).rejects.toThrow("BigInt value must be an integer");
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it("renders booleans", async () => {
|
|
57
|
+
const value = $.value.createBoolean(true);
|
|
58
|
+
await testValueExpression(value, `true`);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it("renders nulls", async () => {
|
|
62
|
+
const value = {
|
|
63
|
+
entityKind: "Value",
|
|
64
|
+
valueKind: "NullValue",
|
|
65
|
+
value: null,
|
|
66
|
+
} as Value;
|
|
67
|
+
await testValueExpression(value, `null`);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it("renders empty arrays", async () => {
|
|
71
|
+
// Can be replaced with with TypeKit once #6976 is implemented
|
|
72
|
+
const value = {
|
|
73
|
+
entityKind: "Value",
|
|
74
|
+
valueKind: "ArrayValue",
|
|
75
|
+
values: [],
|
|
76
|
+
} as unknown as Value;
|
|
77
|
+
await testValueExpression(value, `[]`);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it("renders arrays with mixed values", async () => {
|
|
81
|
+
// Can be replaced with with TypeKit once #6976 is implemented
|
|
82
|
+
const value = {
|
|
83
|
+
entityKind: "Value",
|
|
84
|
+
valueKind: "ArrayValue",
|
|
85
|
+
values: [$.value.createString("foo"), $.value.createNumeric(42), $.value.createBoolean(true)],
|
|
86
|
+
} as Value;
|
|
87
|
+
await testValueExpression(value, `["foo", 42, true]`);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it("renders scalars", async () => {
|
|
91
|
+
const program = await getProgram(`
|
|
92
|
+
namespace DemoService;
|
|
93
|
+
model DateRange {
|
|
94
|
+
@encode("rfc7231")
|
|
95
|
+
minDate: utcDateTime = utcDateTime.fromISO("2024-02-15T18:36:03Z");
|
|
96
|
+
}
|
|
97
|
+
`);
|
|
98
|
+
const [namespace] = program.resolveTypeReference("DemoService");
|
|
99
|
+
const dateRange = (namespace as Namespace).models.get("DateRange");
|
|
100
|
+
const minDate = dateRange?.properties.get("minDate")?.defaultValue;
|
|
101
|
+
assert.exists(minDate, "unable to find minDate property");
|
|
102
|
+
await testValueExpression(minDate, `"2024-02-15T18:36:03Z"`);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it("throws on unsupported scalar", async () => {
|
|
106
|
+
const program = await getProgram(`
|
|
107
|
+
namespace DemoService;
|
|
108
|
+
|
|
109
|
+
scalar ipv4 extends string {
|
|
110
|
+
init fromInt(value: uint32);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
@example (#{ip: ipv4.fromInt(2130706433)})
|
|
114
|
+
model IpAddress {
|
|
115
|
+
ip: ipv4;
|
|
116
|
+
}
|
|
117
|
+
`);
|
|
118
|
+
const [namespace] = program.resolveTypeReference("DemoService");
|
|
119
|
+
const model = (namespace as Namespace).models.get("IpAddress");
|
|
120
|
+
assert.exists(model, "unable to find IpAddress model");
|
|
121
|
+
|
|
122
|
+
const value = getExampleValue(model);
|
|
123
|
+
await expect(testValueExpression(value, ``)).rejects.toThrow(
|
|
124
|
+
/Unsupported scalar constructor fromInt/,
|
|
125
|
+
);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it("renders empty objects", async () => {
|
|
129
|
+
// Can be replaced with with TypeKit once #6976 is implemented
|
|
130
|
+
const program = await getProgram(`
|
|
131
|
+
namespace DemoService;
|
|
132
|
+
@example(#{})
|
|
133
|
+
model ObjectValue {};
|
|
134
|
+
`);
|
|
135
|
+
const [namespace] = program.resolveTypeReference("DemoService");
|
|
136
|
+
const model = (namespace as Namespace).models.get("ObjectValue");
|
|
137
|
+
assert.exists(model, "unable to find ObjectValue model");
|
|
138
|
+
|
|
139
|
+
const value = getExampleValue(model);
|
|
140
|
+
await testValueExpression(value, `{}`);
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it("renders objects with properties", async () => {
|
|
144
|
+
// Can be replaced with with TypeKit once #6976 is implemented
|
|
145
|
+
const program = await getProgram(`
|
|
146
|
+
namespace DemoService;
|
|
147
|
+
@example(#{a: 5, b: "foo", c: true})
|
|
148
|
+
model ObjectValue {
|
|
149
|
+
a: int32;
|
|
150
|
+
b: string;
|
|
151
|
+
c: boolean;
|
|
152
|
+
};
|
|
153
|
+
`);
|
|
154
|
+
const [namespace] = program.resolveTypeReference("DemoService");
|
|
155
|
+
const model = (namespace as Namespace).models.get("ObjectValue");
|
|
156
|
+
assert.exists(model, "unable to find ObjectValue model");
|
|
157
|
+
|
|
158
|
+
const value = getExampleValue(model);
|
|
159
|
+
await testValueExpression(
|
|
160
|
+
value,
|
|
161
|
+
dedent(`
|
|
162
|
+
{
|
|
163
|
+
a: 5,
|
|
164
|
+
b: "foo",
|
|
165
|
+
c: true,
|
|
166
|
+
}`),
|
|
167
|
+
);
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
it("renders enums", async () => {
|
|
171
|
+
// Can be replaced with with TypeKit once #6976 is implemented
|
|
172
|
+
const program = await getProgram(`
|
|
173
|
+
namespace DemoService;
|
|
174
|
+
enum Color {
|
|
175
|
+
Red,
|
|
176
|
+
Green: 3,
|
|
177
|
+
Blue
|
|
178
|
+
}
|
|
179
|
+
`);
|
|
180
|
+
const [namespace] = program.resolveTypeReference("DemoService");
|
|
181
|
+
const colors = (namespace as Namespace).enums.get("Color");
|
|
182
|
+
assert.exists(colors, "unable to find Color enum");
|
|
183
|
+
|
|
184
|
+
const red = colors?.members.get("Red");
|
|
185
|
+
assert.exists(red, "unable to find Red enum member");
|
|
186
|
+
await testValueExpression(
|
|
187
|
+
{
|
|
188
|
+
valueKind: "EnumValue",
|
|
189
|
+
value: red,
|
|
190
|
+
} as EnumValue,
|
|
191
|
+
`"Red"`,
|
|
192
|
+
);
|
|
193
|
+
|
|
194
|
+
const green = colors?.members.get("Green");
|
|
195
|
+
assert.exists(green, "unable to find Green enum member");
|
|
196
|
+
await testValueExpression(
|
|
197
|
+
{
|
|
198
|
+
valueKind: "EnumValue",
|
|
199
|
+
value: green,
|
|
200
|
+
} as EnumValue,
|
|
201
|
+
`3`,
|
|
202
|
+
);
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Helper that renders a value expression and checks the output against the expected value.
|
|
207
|
+
*/
|
|
208
|
+
async function testValueExpression(value: Value, expected: string) {
|
|
209
|
+
const prefix = "const val = ";
|
|
210
|
+
const res = render(
|
|
211
|
+
<Output>
|
|
212
|
+
<SourceFile path="test.ts">
|
|
213
|
+
{prefix}
|
|
214
|
+
<ValueExpression value={value} />
|
|
215
|
+
</SourceFile>
|
|
216
|
+
</Output>,
|
|
217
|
+
);
|
|
218
|
+
const testFile = res.contents.find((file) => file.path === "test.ts");
|
|
219
|
+
|
|
220
|
+
assert.exists(testFile, "test.ts file not rendered");
|
|
221
|
+
|
|
222
|
+
assert.equal(
|
|
223
|
+
testFile.contents,
|
|
224
|
+
`${prefix}${expected}`,
|
|
225
|
+
"test.ts file contents do not match expected",
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Extracts the value marked with the @example decorator from a model.
|
|
231
|
+
*/
|
|
232
|
+
function getExampleValue(model: Model): Value {
|
|
233
|
+
const decorator = model?.decorators.find((d) => d.definition?.name === "@example");
|
|
234
|
+
assert.exists(decorator?.args[0]?.value, "unable to find example decorator");
|
|
235
|
+
return decorator.args[0].value as Value;
|
|
236
|
+
}
|
|
@@ -39,3 +39,11 @@ export async function getProgram(
|
|
|
39
39
|
expectDiagnosticEmpty(diagnostics);
|
|
40
40
|
return wrapper.program;
|
|
41
41
|
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Initializes an empty program in the compiler.
|
|
45
|
+
* This is useful when you want to initialize the default TypeKits without any code.
|
|
46
|
+
*/
|
|
47
|
+
export async function initEmptyProgram(): Promise<void> {
|
|
48
|
+
await getProgram("");
|
|
49
|
+
}
|
package/test/utils.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { Children, render } from "@alloy-js/core";
|
|
1
|
+
import { Children, OutputDirectory, render } from "@alloy-js/core";
|
|
2
2
|
import { Output } from "@alloy-js/core/stc";
|
|
3
3
|
import { SourceFile } from "@alloy-js/typescript/stc";
|
|
4
4
|
import { Program } from "@typespec/compiler";
|
|
5
|
+
import { assert } from "vitest";
|
|
5
6
|
import { getProgram } from "./typescript/test-host.js";
|
|
6
7
|
|
|
7
8
|
export async function getEmitOutput(tspCode: string, cb: (program: Program) => Children) {
|
|
@@ -12,3 +13,9 @@ export async function getEmitOutput(tspCode: string, cb: (program: Program) => C
|
|
|
12
13
|
|
|
13
14
|
return testFile.contents;
|
|
14
15
|
}
|
|
16
|
+
|
|
17
|
+
export function assertFileContents(res: OutputDirectory, contents: string) {
|
|
18
|
+
const testFile = res.contents.find((file) => file.path === "test.ts")!;
|
|
19
|
+
assert(testFile, "test.ts file not rendered");
|
|
20
|
+
assert.equal(testFile.contents, contents);
|
|
21
|
+
}
|