@typespec/emitter-framework 0.6.0-dev.4 → 0.6.0-dev.6
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/core/context/name-policy-context.js +1 -2
- package/dist/src/core/index.js +1 -2
- package/dist/src/core/transport-name-policy.js +1 -2
- package/dist/src/core/write-output.js +1 -2
- package/dist/src/lib.js +1 -2
- package/dist/src/testing/index.js +1 -2
- package/dist/src/testing/scenario-test/harness.js +1 -2
- package/dist/src/testing/scenario-test/index.js +1 -2
- package/dist/src/testing/scenario-test/snippet-extractor.js +1 -2
- package/dist/src/testing/scenario-test/test-host.js +1 -2
- package/dist/src/typescript/components/array-expression.js +1 -2
- package/dist/src/typescript/components/arrow-function.js +2 -5
- package/dist/src/typescript/components/class-method.js +2 -4
- package/dist/src/typescript/components/enum-declaration.js +2 -4
- package/dist/src/typescript/components/function-declaration.js +2 -4
- package/dist/src/typescript/components/function-expression.js +2 -5
- package/dist/src/typescript/components/function-type.js +2 -5
- package/dist/src/typescript/components/index.js +1 -2
- package/dist/src/typescript/components/interface-declaration.js +2 -5
- package/dist/src/typescript/components/interface-member.js +2 -4
- package/dist/src/typescript/components/interface-method.d.ts.map +1 -1
- package/dist/src/typescript/components/interface-method.js +5 -8
- package/dist/src/typescript/components/record-expression.js +1 -2
- package/dist/src/typescript/components/static-serializers.js +1 -2
- package/dist/src/typescript/components/type-alias-declaration.js +2 -5
- package/dist/src/typescript/components/type-declaration.js +2 -4
- package/dist/src/typescript/components/type-expression.js +2 -4
- package/dist/src/typescript/components/type-transform.js +2 -4
- package/dist/src/typescript/components/union-declaration.js +2 -4
- package/dist/src/typescript/components/union-expression.js +2 -4
- package/dist/src/typescript/components/value-expression.js +2 -4
- package/dist/src/typescript/index.js +1 -2
- package/dist/src/typescript/lib.js +1 -2
- package/dist/src/typescript/utils/operation.js +1 -2
- package/dist/test/testing/snippet-extractor-csharp.test.js +96 -0
- package/dist/test/testing/snippet-extractor-java.test.js +104 -0
- package/dist/test/testing/snippet-extractor-python.test.js +33 -0
- package/dist/test/testing/snippet-extractor-typescript.test.js +161 -0
- package/dist/test/typescript/components/arrow-function.test.js +88 -0
- package/dist/test/typescript/components/enum-declaration.test.js +118 -0
- package/dist/test/typescript/components/function-declaration.test.js +246 -0
- package/dist/test/typescript/components/function-expression.test.js +88 -0
- package/dist/test/typescript/components/function-type.test.js +85 -0
- package/dist/test/typescript/components/interface-declaration.test.js +775 -0
- package/dist/test/typescript/components/interface-method.test.js +272 -0
- package/dist/test/typescript/components/member-expression.test.js +155 -0
- package/dist/test/typescript/components/type-alias-declaration.test.js +155 -0
- package/dist/test/typescript/components/type-transform.test.js +682 -0
- package/dist/test/typescript/components/union-declaration.test.js +205 -0
- package/dist/test/typescript/components/value-expression.test.js +199 -0
- package/dist/test/typescript/test-host.js +40 -0
- package/dist/test/utils.js +18 -0
- package/package.json +5 -10
- package/src/typescript/components/interface-method.tsx +2 -4
- package/test/typescript/components/interface-method.test.tsx +167 -2
- package/vitest.config.ts +2 -9
- package/babel.config.js +0 -4
- package/dist/src/core/context/index.js.map +0 -1
- package/dist/src/core/context/name-policy-context.js.map +0 -1
- package/dist/src/core/index.js.map +0 -1
- package/dist/src/core/transport-name-policy.js.map +0 -1
- package/dist/src/core/write-output.js.map +0 -1
- package/dist/src/lib.js.map +0 -1
- package/dist/src/testing/index.js.map +0 -1
- package/dist/src/testing/scenario-test/harness.js.map +0 -1
- package/dist/src/testing/scenario-test/index.js.map +0 -1
- package/dist/src/testing/scenario-test/snippet-extractor.js.map +0 -1
- package/dist/src/testing/scenario-test/test-host.js.map +0 -1
- package/dist/src/typescript/components/array-expression.js.map +0 -1
- package/dist/src/typescript/components/arrow-function.js.map +0 -1
- package/dist/src/typescript/components/class-method.js.map +0 -1
- package/dist/src/typescript/components/enum-declaration.js.map +0 -1
- package/dist/src/typescript/components/function-declaration.js.map +0 -1
- package/dist/src/typescript/components/function-expression.js.map +0 -1
- package/dist/src/typescript/components/function-type.js.map +0 -1
- package/dist/src/typescript/components/index.js.map +0 -1
- package/dist/src/typescript/components/interface-declaration.js.map +0 -1
- package/dist/src/typescript/components/interface-member.js.map +0 -1
- package/dist/src/typescript/components/interface-method.js.map +0 -1
- package/dist/src/typescript/components/record-expression.js.map +0 -1
- package/dist/src/typescript/components/static-serializers.js.map +0 -1
- package/dist/src/typescript/components/type-alias-declaration.js.map +0 -1
- package/dist/src/typescript/components/type-declaration.js.map +0 -1
- package/dist/src/typescript/components/type-expression.js.map +0 -1
- package/dist/src/typescript/components/type-transform.js.map +0 -1
- package/dist/src/typescript/components/union-declaration.js.map +0 -1
- package/dist/src/typescript/components/union-expression.js.map +0 -1
- package/dist/src/typescript/components/value-expression.js.map +0 -1
- package/dist/src/typescript/index.js.map +0 -1
- package/dist/src/typescript/lib.js.map +0 -1
- package/dist/src/typescript/utils/index.js.map +0 -1
- package/dist/src/typescript/utils/operation.js.map +0 -1
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { createComponent as _$createComponent } from "@alloy-js/core/jsx-runtime";
|
|
2
|
+
import { Output, render } from "@alloy-js/core";
|
|
3
|
+
import { SourceFile } from "@alloy-js/typescript";
|
|
4
|
+
import { format } from "prettier";
|
|
5
|
+
import { assert, describe, expect, it } from "vitest";
|
|
6
|
+
import { UnionDeclaration } from "../../../src/typescript/components/union-declaration.js";
|
|
7
|
+
import { UnionExpression } from "../../../src/typescript/components/union-expression.js";
|
|
8
|
+
import { getProgram } from "../test-host.js";
|
|
9
|
+
describe("Typescript Union Declaration", () => {
|
|
10
|
+
describe("Union not bound to Typespec Types", () => {
|
|
11
|
+
it("creates a union declaration", async () => {
|
|
12
|
+
const res = render(_$createComponent(Output, {
|
|
13
|
+
get children() {
|
|
14
|
+
return _$createComponent(SourceFile, {
|
|
15
|
+
path: "test.ts",
|
|
16
|
+
get children() {
|
|
17
|
+
return _$createComponent(UnionDeclaration, {
|
|
18
|
+
name: "MyUnion",
|
|
19
|
+
children: "\"red\" | \"blue\""
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
}));
|
|
25
|
+
const testFile = res.contents.find(file => file.path === "test.ts");
|
|
26
|
+
assert(testFile, "test.ts file not rendered");
|
|
27
|
+
const actualContent = await format(testFile.contents, {
|
|
28
|
+
parser: "typescript"
|
|
29
|
+
});
|
|
30
|
+
const expectedContent = await format(`type MyUnion = "red" | "blue"`, {
|
|
31
|
+
parser: "typescript"
|
|
32
|
+
});
|
|
33
|
+
expect(actualContent).toBe(expectedContent);
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
describe("Union bound to Typespec Types", () => {
|
|
37
|
+
describe("Bound to Union", () => {
|
|
38
|
+
it("creates a union declaration", async () => {
|
|
39
|
+
const program = await getProgram(`
|
|
40
|
+
namespace DemoService;
|
|
41
|
+
union TestUnion {
|
|
42
|
+
one: "one",
|
|
43
|
+
two: "two"
|
|
44
|
+
}
|
|
45
|
+
`);
|
|
46
|
+
const [namespace] = program.resolveTypeReference("DemoService");
|
|
47
|
+
const union = Array.from(namespace.unions.values())[0];
|
|
48
|
+
const res = render(_$createComponent(Output, {
|
|
49
|
+
get children() {
|
|
50
|
+
return _$createComponent(SourceFile, {
|
|
51
|
+
path: "test.ts",
|
|
52
|
+
get children() {
|
|
53
|
+
return _$createComponent(UnionDeclaration, {
|
|
54
|
+
type: union
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
}));
|
|
60
|
+
const testFile = res.contents.find(file => file.path === "test.ts");
|
|
61
|
+
assert(testFile, "test.ts file not rendered");
|
|
62
|
+
const actualContent = await format(testFile.contents, {
|
|
63
|
+
parser: "typescript"
|
|
64
|
+
});
|
|
65
|
+
const expectedContent = await format(`type TestUnion = "one" | "two"`, {
|
|
66
|
+
parser: "typescript"
|
|
67
|
+
});
|
|
68
|
+
expect(actualContent).toBe(expectedContent);
|
|
69
|
+
});
|
|
70
|
+
it("creates a union declaration with name override", async () => {
|
|
71
|
+
const program = await getProgram(`
|
|
72
|
+
namespace DemoService;
|
|
73
|
+
union TestUnion {
|
|
74
|
+
one: "one",
|
|
75
|
+
two: "two"
|
|
76
|
+
}
|
|
77
|
+
`);
|
|
78
|
+
const [namespace] = program.resolveTypeReference("DemoService");
|
|
79
|
+
const union = Array.from(namespace.unions.values())[0];
|
|
80
|
+
const res = render(_$createComponent(Output, {
|
|
81
|
+
get children() {
|
|
82
|
+
return _$createComponent(SourceFile, {
|
|
83
|
+
path: "test.ts",
|
|
84
|
+
get children() {
|
|
85
|
+
return _$createComponent(UnionDeclaration, {
|
|
86
|
+
"export": true,
|
|
87
|
+
type: union,
|
|
88
|
+
name: "MyUnion"
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
}));
|
|
94
|
+
const testFile = res.contents.find(file => file.path === "test.ts");
|
|
95
|
+
assert(testFile, "test.ts file not rendered");
|
|
96
|
+
const actualContent = await format(testFile.contents, {
|
|
97
|
+
parser: "typescript"
|
|
98
|
+
});
|
|
99
|
+
const expectedContent = await format(`export type MyUnion = "one" | "two"`, {
|
|
100
|
+
parser: "typescript"
|
|
101
|
+
});
|
|
102
|
+
expect(actualContent).toBe(expectedContent);
|
|
103
|
+
});
|
|
104
|
+
it("creates a union declaration with extra children", async () => {
|
|
105
|
+
const program = await getProgram(`
|
|
106
|
+
namespace DemoService;
|
|
107
|
+
union TestUnion {
|
|
108
|
+
one: "one",
|
|
109
|
+
two: "two"
|
|
110
|
+
}
|
|
111
|
+
`);
|
|
112
|
+
const [namespace] = program.resolveTypeReference("DemoService");
|
|
113
|
+
const union = Array.from(namespace.unions.values())[0];
|
|
114
|
+
const res = render(_$createComponent(Output, {
|
|
115
|
+
get children() {
|
|
116
|
+
return _$createComponent(SourceFile, {
|
|
117
|
+
path: "test.ts",
|
|
118
|
+
get children() {
|
|
119
|
+
return _$createComponent(UnionDeclaration, {
|
|
120
|
+
type: union,
|
|
121
|
+
children: "\"three\""
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
}));
|
|
127
|
+
const testFile = res.contents.find(file => file.path === "test.ts");
|
|
128
|
+
assert(testFile, "test.ts file not rendered");
|
|
129
|
+
const actualContent = await format(testFile.contents, {
|
|
130
|
+
parser: "typescript"
|
|
131
|
+
});
|
|
132
|
+
const expectedContent = await format(`type TestUnion = "one" | "two" | "three"`, {
|
|
133
|
+
parser: "typescript"
|
|
134
|
+
});
|
|
135
|
+
expect(actualContent).toBe(expectedContent);
|
|
136
|
+
});
|
|
137
|
+
it("renders an union expression", async () => {
|
|
138
|
+
const program = await getProgram(`
|
|
139
|
+
namespace DemoService;
|
|
140
|
+
union TestUnion {
|
|
141
|
+
one: "one",
|
|
142
|
+
two: "two"
|
|
143
|
+
}
|
|
144
|
+
`);
|
|
145
|
+
const [namespace] = program.resolveTypeReference("DemoService");
|
|
146
|
+
const union = Array.from(namespace.unions.values())[0];
|
|
147
|
+
const res = render(_$createComponent(Output, {
|
|
148
|
+
get children() {
|
|
149
|
+
return _$createComponent(SourceFile, {
|
|
150
|
+
path: "test.ts",
|
|
151
|
+
get children() {
|
|
152
|
+
return ["let x: ", _$createComponent(UnionExpression, {
|
|
153
|
+
type: union
|
|
154
|
+
}), " = \"one\";"];
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
}));
|
|
159
|
+
const testFile = res.contents.find(file => file.path === "test.ts");
|
|
160
|
+
assert(testFile, "test.ts file not rendered");
|
|
161
|
+
const actualContent = await format(testFile.contents, {
|
|
162
|
+
parser: "typescript"
|
|
163
|
+
});
|
|
164
|
+
const expectedContent = await format(`let x:"one" | "two" = "one"`, {
|
|
165
|
+
parser: "typescript"
|
|
166
|
+
});
|
|
167
|
+
expect(actualContent).toBe(expectedContent);
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
describe("Bound to Enum", () => {
|
|
171
|
+
it("creates a union declaration", async () => {
|
|
172
|
+
const program = await getProgram(`
|
|
173
|
+
namespace DemoService;
|
|
174
|
+
enum TestEnum {
|
|
175
|
+
one: "one",
|
|
176
|
+
two: "two"
|
|
177
|
+
}
|
|
178
|
+
`);
|
|
179
|
+
const [namespace] = program.resolveTypeReference("DemoService");
|
|
180
|
+
const union = Array.from(namespace.enums.values())[0];
|
|
181
|
+
const res = render(_$createComponent(Output, {
|
|
182
|
+
get children() {
|
|
183
|
+
return _$createComponent(SourceFile, {
|
|
184
|
+
path: "test.ts",
|
|
185
|
+
get children() {
|
|
186
|
+
return _$createComponent(UnionDeclaration, {
|
|
187
|
+
type: union
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
}));
|
|
193
|
+
const testFile = res.contents.find(file => file.path === "test.ts");
|
|
194
|
+
assert(testFile, "test.ts file not rendered");
|
|
195
|
+
const actualContent = await format(testFile.contents, {
|
|
196
|
+
parser: "typescript"
|
|
197
|
+
});
|
|
198
|
+
const expectedContent = await format(`type TestEnum = "one" | "two"`, {
|
|
199
|
+
parser: "typescript"
|
|
200
|
+
});
|
|
201
|
+
expect(actualContent).toBe(expectedContent);
|
|
202
|
+
});
|
|
203
|
+
});
|
|
204
|
+
});
|
|
205
|
+
});
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { createComponent as _$createComponent } from "@alloy-js/core/jsx-runtime";
|
|
2
|
+
import { Output, render } from "@alloy-js/core";
|
|
3
|
+
import { dedent } from "@alloy-js/core/testing";
|
|
4
|
+
import { SourceFile } from "@alloy-js/typescript";
|
|
5
|
+
import { Numeric } from "@typespec/compiler";
|
|
6
|
+
import { $ } from "@typespec/compiler/experimental/typekit";
|
|
7
|
+
import { assert, beforeAll, describe, expect, it } from "vitest";
|
|
8
|
+
import { ValueExpression } from "../../../src/typescript/components/value-expression.js";
|
|
9
|
+
import { getProgram, initEmptyProgram } from "../test-host.js";
|
|
10
|
+
beforeAll(async () => {
|
|
11
|
+
await initEmptyProgram();
|
|
12
|
+
});
|
|
13
|
+
it("renders strings", async () => {
|
|
14
|
+
const value = $.value.createString("test");
|
|
15
|
+
await testValueExpression(value, `"test"`);
|
|
16
|
+
});
|
|
17
|
+
describe("numeric values", () => {
|
|
18
|
+
it("renders integers", async () => {
|
|
19
|
+
const value = $.value.createNumeric(42);
|
|
20
|
+
await testValueExpression(value, `42`);
|
|
21
|
+
});
|
|
22
|
+
it("renders decimals", async () => {
|
|
23
|
+
const value = $.value.createNumeric(42.5);
|
|
24
|
+
await testValueExpression(value, `42.5`);
|
|
25
|
+
});
|
|
26
|
+
it("renders bigints", async () => {
|
|
27
|
+
const digits = "1234567890123456789012345678901234567890";
|
|
28
|
+
const value = {
|
|
29
|
+
entityKind: "Value",
|
|
30
|
+
valueKind: "NumericValue",
|
|
31
|
+
value: Numeric(digits)
|
|
32
|
+
};
|
|
33
|
+
await testValueExpression(value, `${digits}n`);
|
|
34
|
+
});
|
|
35
|
+
it("throws on invalid numbers", async () => {
|
|
36
|
+
const digits = "123456789123456789.112233445566778899";
|
|
37
|
+
const value = {
|
|
38
|
+
entityKind: "Value",
|
|
39
|
+
valueKind: "NumericValue",
|
|
40
|
+
value: Numeric(digits)
|
|
41
|
+
};
|
|
42
|
+
await expect(testValueExpression(value, ``)).rejects.toThrow("BigInt value must be an integer");
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
it("renders booleans", async () => {
|
|
46
|
+
const value = $.value.createBoolean(true);
|
|
47
|
+
await testValueExpression(value, `true`);
|
|
48
|
+
});
|
|
49
|
+
it("renders nulls", async () => {
|
|
50
|
+
const value = {
|
|
51
|
+
entityKind: "Value",
|
|
52
|
+
valueKind: "NullValue",
|
|
53
|
+
value: null
|
|
54
|
+
};
|
|
55
|
+
await testValueExpression(value, `null`);
|
|
56
|
+
});
|
|
57
|
+
it("renders empty arrays", async () => {
|
|
58
|
+
// Can be replaced with with TypeKit once #6976 is implemented
|
|
59
|
+
const value = {
|
|
60
|
+
entityKind: "Value",
|
|
61
|
+
valueKind: "ArrayValue",
|
|
62
|
+
values: []
|
|
63
|
+
};
|
|
64
|
+
await testValueExpression(value, `[]`);
|
|
65
|
+
});
|
|
66
|
+
it("renders arrays with mixed values", async () => {
|
|
67
|
+
// Can be replaced with with TypeKit once #6976 is implemented
|
|
68
|
+
const value = {
|
|
69
|
+
entityKind: "Value",
|
|
70
|
+
valueKind: "ArrayValue",
|
|
71
|
+
values: [$.value.createString("foo"), $.value.createNumeric(42), $.value.createBoolean(true)]
|
|
72
|
+
};
|
|
73
|
+
await testValueExpression(value, `["foo", 42, true]`);
|
|
74
|
+
});
|
|
75
|
+
it("renders scalars", async () => {
|
|
76
|
+
const program = await getProgram(`
|
|
77
|
+
namespace DemoService;
|
|
78
|
+
model DateRange {
|
|
79
|
+
@encode("rfc7231")
|
|
80
|
+
minDate: utcDateTime = utcDateTime.fromISO("2024-02-15T18:36:03Z");
|
|
81
|
+
}
|
|
82
|
+
`);
|
|
83
|
+
const [namespace] = program.resolveTypeReference("DemoService");
|
|
84
|
+
const dateRange = namespace.models.get("DateRange");
|
|
85
|
+
const minDate = dateRange?.properties.get("minDate")?.defaultValue;
|
|
86
|
+
assert.exists(minDate, "unable to find minDate property");
|
|
87
|
+
await testValueExpression(minDate, `"2024-02-15T18:36:03Z"`);
|
|
88
|
+
});
|
|
89
|
+
it("throws on unsupported scalar", async () => {
|
|
90
|
+
const program = await getProgram(`
|
|
91
|
+
namespace DemoService;
|
|
92
|
+
|
|
93
|
+
scalar ipv4 extends string {
|
|
94
|
+
init fromInt(value: uint32);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
@example (#{ip: ipv4.fromInt(2130706433)})
|
|
98
|
+
model IpAddress {
|
|
99
|
+
ip: ipv4;
|
|
100
|
+
}
|
|
101
|
+
`);
|
|
102
|
+
const [namespace] = program.resolveTypeReference("DemoService");
|
|
103
|
+
const model = namespace.models.get("IpAddress");
|
|
104
|
+
assert.exists(model, "unable to find IpAddress model");
|
|
105
|
+
const value = getExampleValue(model);
|
|
106
|
+
await expect(testValueExpression(value, ``)).rejects.toThrow(/Unsupported scalar constructor fromInt/);
|
|
107
|
+
});
|
|
108
|
+
it("renders empty objects", async () => {
|
|
109
|
+
// Can be replaced with with TypeKit once #6976 is implemented
|
|
110
|
+
const program = await getProgram(`
|
|
111
|
+
namespace DemoService;
|
|
112
|
+
@example(#{})
|
|
113
|
+
model ObjectValue {};
|
|
114
|
+
`);
|
|
115
|
+
const [namespace] = program.resolveTypeReference("DemoService");
|
|
116
|
+
const model = namespace.models.get("ObjectValue");
|
|
117
|
+
assert.exists(model, "unable to find ObjectValue model");
|
|
118
|
+
const value = getExampleValue(model);
|
|
119
|
+
await testValueExpression(value, `{}`);
|
|
120
|
+
});
|
|
121
|
+
it("renders objects with properties", async () => {
|
|
122
|
+
// Can be replaced with with TypeKit once #6976 is implemented
|
|
123
|
+
const program = await getProgram(`
|
|
124
|
+
namespace DemoService;
|
|
125
|
+
@example(#{a: 5, b: "foo", c: true})
|
|
126
|
+
model ObjectValue {
|
|
127
|
+
a: int32;
|
|
128
|
+
b: string;
|
|
129
|
+
c: boolean;
|
|
130
|
+
};
|
|
131
|
+
`);
|
|
132
|
+
const [namespace] = program.resolveTypeReference("DemoService");
|
|
133
|
+
const model = namespace.models.get("ObjectValue");
|
|
134
|
+
assert.exists(model, "unable to find ObjectValue model");
|
|
135
|
+
const value = getExampleValue(model);
|
|
136
|
+
await testValueExpression(value, dedent(`
|
|
137
|
+
{
|
|
138
|
+
a: 5,
|
|
139
|
+
b: "foo",
|
|
140
|
+
c: true,
|
|
141
|
+
}`));
|
|
142
|
+
});
|
|
143
|
+
it("renders enums", async () => {
|
|
144
|
+
// Can be replaced with with TypeKit once #6976 is implemented
|
|
145
|
+
const program = await getProgram(`
|
|
146
|
+
namespace DemoService;
|
|
147
|
+
enum Color {
|
|
148
|
+
Red,
|
|
149
|
+
Green: 3,
|
|
150
|
+
Blue
|
|
151
|
+
}
|
|
152
|
+
`);
|
|
153
|
+
const [namespace] = program.resolveTypeReference("DemoService");
|
|
154
|
+
const colors = namespace.enums.get("Color");
|
|
155
|
+
assert.exists(colors, "unable to find Color enum");
|
|
156
|
+
const red = colors?.members.get("Red");
|
|
157
|
+
assert.exists(red, "unable to find Red enum member");
|
|
158
|
+
await testValueExpression({
|
|
159
|
+
valueKind: "EnumValue",
|
|
160
|
+
value: red
|
|
161
|
+
}, `"Red"`);
|
|
162
|
+
const green = colors?.members.get("Green");
|
|
163
|
+
assert.exists(green, "unable to find Green enum member");
|
|
164
|
+
await testValueExpression({
|
|
165
|
+
valueKind: "EnumValue",
|
|
166
|
+
value: green
|
|
167
|
+
}, `3`);
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Helper that renders a value expression and checks the output against the expected value.
|
|
172
|
+
*/
|
|
173
|
+
async function testValueExpression(value, expected) {
|
|
174
|
+
const prefix = "const val = ";
|
|
175
|
+
const res = render(_$createComponent(Output, {
|
|
176
|
+
get children() {
|
|
177
|
+
return _$createComponent(SourceFile, {
|
|
178
|
+
path: "test.ts",
|
|
179
|
+
get children() {
|
|
180
|
+
return [prefix, _$createComponent(ValueExpression, {
|
|
181
|
+
value: value
|
|
182
|
+
})];
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
}));
|
|
187
|
+
const testFile = res.contents.find(file => file.path === "test.ts");
|
|
188
|
+
assert.exists(testFile, "test.ts file not rendered");
|
|
189
|
+
assert.equal(testFile.contents, `${prefix}${expected}`, "test.ts file contents do not match expected");
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Extracts the value marked with the @example decorator from a model.
|
|
194
|
+
*/
|
|
195
|
+
function getExampleValue(model) {
|
|
196
|
+
const decorator = model?.decorators.find(d => d.definition?.name === "@example");
|
|
197
|
+
assert.exists(decorator?.args[0]?.value, "unable to find example decorator");
|
|
198
|
+
return decorator.args[0].value;
|
|
199
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { createTestHost, createTestWrapper, expectDiagnosticEmpty } from "@typespec/compiler/testing";
|
|
2
|
+
import { HttpTestLibrary } from "@typespec/http/testing";
|
|
3
|
+
export async function createTypespecCliTestHost(options = {
|
|
4
|
+
libraries: []
|
|
5
|
+
}) {
|
|
6
|
+
const libraries = [];
|
|
7
|
+
if (options.libraries.includes("Http")) {
|
|
8
|
+
libraries.push(HttpTestLibrary);
|
|
9
|
+
}
|
|
10
|
+
return createTestHost({
|
|
11
|
+
libraries
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
export async function createEmitterFrameworkTestRunner(options = {}) {
|
|
15
|
+
const host = await createTypespecCliTestHost();
|
|
16
|
+
return createTestWrapper(host, {
|
|
17
|
+
autoUsings: options.autoUsings
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
export async function getProgram(code, options = {
|
|
21
|
+
libraries: []
|
|
22
|
+
}) {
|
|
23
|
+
const host = await createTypespecCliTestHost(options);
|
|
24
|
+
const wrapper = createTestWrapper(host, {
|
|
25
|
+
compilerOptions: {
|
|
26
|
+
noEmit: true
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
const [_, diagnostics] = await wrapper.compileAndDiagnose(code);
|
|
30
|
+
expectDiagnosticEmpty(diagnostics);
|
|
31
|
+
return wrapper.program;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Initializes an empty program in the compiler.
|
|
36
|
+
* This is useful when you want to initialize the default TypeKits without any code.
|
|
37
|
+
*/
|
|
38
|
+
export async function initEmptyProgram() {
|
|
39
|
+
await getProgram("");
|
|
40
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { render } from "@alloy-js/core";
|
|
2
|
+
import { Output } from "@alloy-js/core/stc";
|
|
3
|
+
import { SourceFile } from "@alloy-js/typescript/stc";
|
|
4
|
+
import { assert } from "vitest";
|
|
5
|
+
import { getProgram } from "./typescript/test-host.js";
|
|
6
|
+
export async function getEmitOutput(tspCode, cb) {
|
|
7
|
+
const program = await getProgram(tspCode);
|
|
8
|
+
const res = render(Output().children(SourceFile({
|
|
9
|
+
path: "test.ts"
|
|
10
|
+
}).children(cb(program))));
|
|
11
|
+
const testFile = res.contents.find(file => file.path === "test.ts");
|
|
12
|
+
return testFile.contents;
|
|
13
|
+
}
|
|
14
|
+
export function assertFileContents(res, contents) {
|
|
15
|
+
const testFile = res.contents.find(file => file.path === "test.ts");
|
|
16
|
+
assert(testFile, "test.ts file not rendered");
|
|
17
|
+
assert.equal(testFile.contents, contents);
|
|
18
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@typespec/emitter-framework",
|
|
3
|
-
"version": "0.6.0-dev.
|
|
3
|
+
"version": "0.6.0-dev.6",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"exports": {
|
|
@@ -26,12 +26,10 @@
|
|
|
26
26
|
"@typespec/rest": "^0.68.0 || >=0.69.0-dev <0.69.0"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
|
-
"@alloy-js/
|
|
29
|
+
"@alloy-js/cli": "^0.11.0",
|
|
30
|
+
"@alloy-js/rollup-plugin": "^0.1.0",
|
|
30
31
|
"@alloy-js/core": "^0.11.0",
|
|
31
32
|
"@alloy-js/typescript": "^0.11.0",
|
|
32
|
-
"@babel/cli": "^7.24.8",
|
|
33
|
-
"@babel/core": "^7.26.10",
|
|
34
|
-
"@rollup/plugin-babel": "^6.0.4",
|
|
35
33
|
"@types/minimist": "^1.2.5",
|
|
36
34
|
"@typespec/compiler": "^1.0.0-rc.0",
|
|
37
35
|
"@typespec/http": "^1.0.0-rc.0",
|
|
@@ -50,13 +48,10 @@
|
|
|
50
48
|
},
|
|
51
49
|
"dependencies": {},
|
|
52
50
|
"scripts": {
|
|
53
|
-
"build
|
|
54
|
-
"build": "tsc -p . && pnpm build-src",
|
|
51
|
+
"build": "alloy build",
|
|
55
52
|
"clean": "rimraf ./dist",
|
|
56
53
|
"format": "prettier . --write",
|
|
57
|
-
"watch
|
|
58
|
-
"watch-tsc": "tsc -p . --watch",
|
|
59
|
-
"watch": "concurrently --kill-others \"pnpm watch-tsc\" \"pnpm watch-src\"",
|
|
54
|
+
"watch": "alloy build --watch",
|
|
60
55
|
"test": "vitest run",
|
|
61
56
|
"test:ui": "vitest --ui",
|
|
62
57
|
"test:watch": "vitest -w",
|
|
@@ -29,9 +29,7 @@ export function InterfaceMethod(props: Readonly<InterfaceMethodProps>) {
|
|
|
29
29
|
["returnType", "parameters"],
|
|
30
30
|
);
|
|
31
31
|
|
|
32
|
-
const name = props.name
|
|
33
|
-
? props.name
|
|
34
|
-
: ts.useTSNamePolicy().getName(efProps.type.name, "function");
|
|
32
|
+
const name = props.name ?? ts.useTSNamePolicy().getName(efProps.type.name, "function");
|
|
35
33
|
const returnType = props.returnType ?? <TypeExpression type={getReturnType(efProps.type)} />;
|
|
36
34
|
const allParameters = buildParameterDescriptors(efProps.type.parameters, {
|
|
37
35
|
params: props.parameters,
|
|
@@ -41,10 +39,10 @@ export function InterfaceMethod(props: Readonly<InterfaceMethodProps>) {
|
|
|
41
39
|
return (
|
|
42
40
|
<ts.InterfaceMethod
|
|
43
41
|
{...forwardProps}
|
|
42
|
+
{...updateProps}
|
|
44
43
|
name={name}
|
|
45
44
|
returnType={returnType}
|
|
46
45
|
parameters={allParameters}
|
|
47
|
-
{...updateProps}
|
|
48
46
|
/>
|
|
49
47
|
);
|
|
50
48
|
}
|