@typespec/emitter-framework 0.6.0-dev.1 → 0.6.0-dev.2
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/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/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/package.json +1 -1
- package/src/typescript/components/value-expression.tsx +56 -0
- package/test/typescript/components/value-expression.test.tsx +236 -0
- package/test/typescript/test-host.ts +8 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Children } from "@alloy-js/core";
|
|
2
|
+
import { Value } from "@typespec/compiler";
|
|
3
|
+
/**
|
|
4
|
+
* Properties for the {@link ValueExpression} component.
|
|
5
|
+
*/
|
|
6
|
+
interface ValueExpressionProps {
|
|
7
|
+
/**
|
|
8
|
+
* The TypeSpec value to be converted to a JavaScript expression.
|
|
9
|
+
*/
|
|
10
|
+
value: Value;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Generates a JavaScript value expression from a TypeSpec value.
|
|
14
|
+
* @param props properties for the value expression
|
|
15
|
+
* @returns {@link Children} representing the JavaScript value expression
|
|
16
|
+
*/
|
|
17
|
+
export declare function ValueExpression(props: Readonly<ValueExpressionProps>): Children;
|
|
18
|
+
export {};
|
|
19
|
+
//# sourceMappingURL=value-expression.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"value-expression.d.ts","sourceRoot":"","sources":["../../../../src/typescript/components/value-expression.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE1C,OAAO,EAAkB,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAE3D;;GAEG;AACH,UAAU,oBAAoB;IAC5B;;OAEG;IACH,KAAK,EAAE,KAAK,CAAC;CACd;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,QAAQ,CAAC,oBAAoB,CAAC,GAAG,QAAQ,CAoC/E"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { memo as _$memo } from "@alloy-js/core/jsx-runtime";
|
|
2
|
+
import { createComponent as _$createComponent } from "@alloy-js/core/jsx-runtime";
|
|
3
|
+
import * as ts from "@alloy-js/typescript";
|
|
4
|
+
import { compilerAssert } from "@typespec/compiler";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Properties for the {@link ValueExpression} component.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Generates a JavaScript value expression from a TypeSpec value.
|
|
12
|
+
* @param props properties for the value expression
|
|
13
|
+
* @returns {@link Children} representing the JavaScript value expression
|
|
14
|
+
*/
|
|
15
|
+
export function ValueExpression(props) {
|
|
16
|
+
switch (props.value.valueKind) {
|
|
17
|
+
case "StringValue":
|
|
18
|
+
case "BooleanValue":
|
|
19
|
+
case "NullValue":
|
|
20
|
+
return _$createComponent(ts.ValueExpression, {
|
|
21
|
+
get jsValue() {
|
|
22
|
+
return props.value.value;
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
case "NumericValue":
|
|
26
|
+
if (props.value.value.asNumber()) {
|
|
27
|
+
return _$createComponent(ts.ValueExpression, {
|
|
28
|
+
get jsValue() {
|
|
29
|
+
return props.value.value.asNumber();
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
compilerAssert(props.value.value.isInteger, "BigInt value must be an integer", props.value);
|
|
34
|
+
return _$createComponent(ts.ValueExpression, {
|
|
35
|
+
get jsValue() {
|
|
36
|
+
return props.value.value.asBigInt();
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
case "ArrayValue":
|
|
40
|
+
return _$createComponent(ts.ArrayExpression, {
|
|
41
|
+
get jsValue() {
|
|
42
|
+
return props.value.values.map(v => _$createComponent(ValueExpression, {
|
|
43
|
+
value: v
|
|
44
|
+
}));
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
case "ScalarValue":
|
|
48
|
+
compilerAssert(props.value.value.name === "fromISO", `Unsupported scalar constructor ${props.value.value.name}`, props.value);
|
|
49
|
+
return _$createComponent(ValueExpression, {
|
|
50
|
+
get value() {
|
|
51
|
+
return props.value.value.args[0];
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
case "ObjectValue":
|
|
55
|
+
const jsProperties = {};
|
|
56
|
+
for (const [key, value] of props.value.properties) {
|
|
57
|
+
jsProperties[key] = ValueExpression({
|
|
58
|
+
value: value.value
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
return _$createComponent(ts.ObjectExpression, {
|
|
62
|
+
jsValue: jsProperties
|
|
63
|
+
});
|
|
64
|
+
case "EnumValue":
|
|
65
|
+
return _$createComponent(ts.ValueExpression, {
|
|
66
|
+
get jsValue() {
|
|
67
|
+
return props.value.value.value ?? props.value.value.name;
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=value-expression.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"value-expression.js","names":["ts","compilerAssert","ValueExpression","props","value","valueKind","_$createComponent","jsValue","asNumber","isInteger","asBigInt","ArrayExpression","values","map","v","name","args","jsProperties","key","properties","ObjectExpression"],"sources":["../../../../src/typescript/components/value-expression.tsx"],"sourcesContent":[null],"mappings":";;AACA,OAAO,KAAKA,EAAE,MAAM,sBAAsB;AAC1C,SAASC,cAAc,QAAe,oBAAoB;;AAE1D;AACA;AACA;;AAQA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,eAAeA,CAACC,KAAqC,EAAY;EAC/E,QAAQA,KAAK,CAACC,KAAK,CAACC,SAAS;IAC3B,KAAK,aAAa;IAClB,KAAK,cAAc;IACnB,KAAK,WAAW;MACd,OAAAC,iBAAA,CAAQN,EAAE,CAACE,eAAe;QAAA,IAACK,OAAOA,CAAA;UAAA,OAAEJ,KAAK,CAACC,KAAK,CAACA,KAAK;QAAA;MAAA;IACvD,KAAK,cAAc;MACjB,IAAID,KAAK,CAACC,KAAK,CAACA,KAAK,CAACI,QAAQ,CAAC,CAAC,EAAE;QAChC,OAAAF,iBAAA,CAAQN,EAAE,CAACE,eAAe;UAAA,IAACK,OAAOA,CAAA;YAAA,OAAEJ,KAAK,CAACC,KAAK,CAACA,KAAK,CAACI,QAAQ,CAAC,CAAC;UAAA;QAAA;MAClE;MACAP,cAAc,CAACE,KAAK,CAACC,KAAK,CAACA,KAAK,CAACK,SAAS,EAAE,iCAAiC,EAAEN,KAAK,CAACC,KAAK,CAAC;MAC3F,OAAAE,iBAAA,CAAQN,EAAE,CAACE,eAAe;QAAA,IAACK,OAAOA,CAAA;UAAA,OAAEJ,KAAK,CAACC,KAAK,CAACA,KAAK,CAACM,QAAQ,CAAC,CAAC;QAAA;MAAA;IAClE,KAAK,YAAY;MACf,OAAAJ,iBAAA,CACGN,EAAE,CAACW,eAAe;QAAA,IACjBJ,OAAOA,CAAA;UAAA,OAAEJ,KAAK,CAACC,KAAK,CAACQ,MAAM,CAACC,GAAG,CAAEC,CAAC,IAAAR,iBAAA,CAC/BJ,eAAe;YAACE,KAAK,EAAEU;UAAC,EAC1B,CAAC;QAAA;MAAA;IAGR,KAAK,aAAa;MAChBb,cAAc,CACZE,KAAK,CAACC,KAAK,CAACA,KAAK,CAACW,IAAI,KAAK,SAAS,EACpC,kCAAkCZ,KAAK,CAACC,KAAK,CAACA,KAAK,CAACW,IAAI,EAAE,EAC1DZ,KAAK,CAACC,KACR,CAAC;MACD,OAAAE,iBAAA,CAAQJ,eAAe;QAAA,IAACE,KAAKA,CAAA;UAAA,OAAED,KAAK,CAACC,KAAK,CAACA,KAAK,CAACY,IAAI,CAAC,CAAC,CAAC;QAAA;MAAA;IAC1D,KAAK,aAAa;MAChB,MAAMC,YAAsC,GAAG,CAAC,CAAC;MACjD,KAAK,MAAM,CAACC,GAAG,EAAEd,KAAK,CAAC,IAAID,KAAK,CAACC,KAAK,CAACe,UAAU,EAAE;QACjDF,YAAY,CAACC,GAAG,CAAC,GAAGhB,eAAe,CAAC;UAAEE,KAAK,EAAEA,KAAK,CAACA;QAAM,CAAC,CAAC;MAC7D;MACA,OAAAE,iBAAA,CAAQN,EAAE,CAACoB,gBAAgB;QAACb,OAAO,EAAEU;MAAY;IACnD,KAAK,WAAW;MACd,OAAAX,iBAAA,CAAQN,EAAE,CAACE,eAAe;QAAA,IAACK,OAAOA,CAAA;UAAA,OAAEJ,KAAK,CAACC,KAAK,CAACA,KAAK,CAACA,KAAK,IAAID,KAAK,CAACC,KAAK,CAACA,KAAK,CAACW,IAAI;QAAA;MAAA;EACzF;AACF","ignoreList":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"value-expression.test.d.ts","sourceRoot":"","sources":["../../../../test/typescript/components/value-expression.test.tsx"],"names":[],"mappings":""}
|
|
@@ -8,4 +8,9 @@ export declare function createEmitterFrameworkTestRunner(options?: {
|
|
|
8
8
|
export declare function getProgram(code: string, options?: {
|
|
9
9
|
libraries: "Http"[];
|
|
10
10
|
}): Promise<Program>;
|
|
11
|
+
/**
|
|
12
|
+
* Initializes an empty program in the compiler.
|
|
13
|
+
* This is useful when you want to initialize the default TypeKits without any code.
|
|
14
|
+
*/
|
|
15
|
+
export declare function initEmptyProgram(): Promise<void>;
|
|
11
16
|
//# sourceMappingURL=test-host.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"test-host.d.ts","sourceRoot":"","sources":["../../../test/typescript/test-host.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAQ7C,wBAAsB,yBAAyB,CAC7C,OAAO,GAAE;IAAE,SAAS,EAAE,MAAM,EAAE,CAAA;CAAsB,0DASrD;AAED,wBAAsB,gCAAgC,CAAC,OAAO,GAAE;IAAE,UAAU,CAAC,EAAE,MAAM,EAAE,CAAA;CAAO,iEAK7F;AAED,wBAAsB,UAAU,CAC9B,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE;IAAE,SAAS,EAAE,MAAM,EAAE,CAAA;CAAsB,GACnD,OAAO,CAAC,OAAO,CAAC,CAUlB"}
|
|
1
|
+
{"version":3,"file":"test-host.d.ts","sourceRoot":"","sources":["../../../test/typescript/test-host.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAQ7C,wBAAsB,yBAAyB,CAC7C,OAAO,GAAE;IAAE,SAAS,EAAE,MAAM,EAAE,CAAA;CAAsB,0DASrD;AAED,wBAAsB,gCAAgC,CAAC,OAAO,GAAE;IAAE,UAAU,CAAC,EAAE,MAAM,EAAE,CAAA;CAAO,iEAK7F;AAED,wBAAsB,UAAU,CAC9B,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE;IAAE,SAAS,EAAE,MAAM,EAAE,CAAA;CAAsB,GACnD,OAAO,CAAC,OAAO,CAAC,CAUlB;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC,CAEtD"}
|
package/package.json
CHANGED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { Children } from "@alloy-js/core";
|
|
2
|
+
import * as ts from "@alloy-js/typescript";
|
|
3
|
+
import { compilerAssert, Value } from "@typespec/compiler";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Properties for the {@link ValueExpression} component.
|
|
7
|
+
*/
|
|
8
|
+
interface ValueExpressionProps {
|
|
9
|
+
/**
|
|
10
|
+
* The TypeSpec value to be converted to a JavaScript expression.
|
|
11
|
+
*/
|
|
12
|
+
value: Value;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Generates a JavaScript value expression from a TypeSpec value.
|
|
17
|
+
* @param props properties for the value expression
|
|
18
|
+
* @returns {@link Children} representing the JavaScript value expression
|
|
19
|
+
*/
|
|
20
|
+
export function ValueExpression(props: Readonly<ValueExpressionProps>): Children {
|
|
21
|
+
switch (props.value.valueKind) {
|
|
22
|
+
case "StringValue":
|
|
23
|
+
case "BooleanValue":
|
|
24
|
+
case "NullValue":
|
|
25
|
+
return <ts.ValueExpression jsValue={props.value.value} />;
|
|
26
|
+
case "NumericValue":
|
|
27
|
+
if (props.value.value.asNumber()) {
|
|
28
|
+
return <ts.ValueExpression jsValue={props.value.value.asNumber()} />;
|
|
29
|
+
}
|
|
30
|
+
compilerAssert(props.value.value.isInteger, "BigInt value must be an integer", props.value);
|
|
31
|
+
return <ts.ValueExpression jsValue={props.value.value.asBigInt()} />;
|
|
32
|
+
case "ArrayValue":
|
|
33
|
+
return (
|
|
34
|
+
<ts.ArrayExpression
|
|
35
|
+
jsValue={props.value.values.map((v) => (
|
|
36
|
+
<ValueExpression value={v} />
|
|
37
|
+
))}
|
|
38
|
+
/>
|
|
39
|
+
);
|
|
40
|
+
case "ScalarValue":
|
|
41
|
+
compilerAssert(
|
|
42
|
+
props.value.value.name === "fromISO",
|
|
43
|
+
`Unsupported scalar constructor ${props.value.value.name}`,
|
|
44
|
+
props.value,
|
|
45
|
+
);
|
|
46
|
+
return <ValueExpression value={props.value.value.args[0]} />;
|
|
47
|
+
case "ObjectValue":
|
|
48
|
+
const jsProperties: Record<string, Children> = {};
|
|
49
|
+
for (const [key, value] of props.value.properties) {
|
|
50
|
+
jsProperties[key] = ValueExpression({ value: value.value });
|
|
51
|
+
}
|
|
52
|
+
return <ts.ObjectExpression jsValue={jsProperties} />;
|
|
53
|
+
case "EnumValue":
|
|
54
|
+
return <ts.ValueExpression jsValue={props.value.value.value ?? props.value.value.name} />;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -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
|
+
}
|