@typespec/emitter-framework 0.6.0-dev.0 → 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/interface-declaration.d.ts +1 -1
- package/dist/src/typescript/components/interface-declaration.d.ts.map +1 -1
- package/dist/src/typescript/components/interface-declaration.js +39 -27
- package/dist/src/typescript/components/interface-declaration.js.map +1 -1
- package/dist/src/typescript/components/interface-member.d.ts +2 -1
- package/dist/src/typescript/components/interface-member.d.ts.map +1 -1
- package/dist/src/typescript/components/interface-member.js +35 -20
- package/dist/src/typescript/components/interface-member.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/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/interface-declaration.tsx +38 -31
- package/src/typescript/components/interface-member.tsx +30 -19
- package/src/typescript/components/value-expression.tsx +56 -0
- package/test/typescript/components/interface-declaration.test.tsx +40 -7
- package/test/typescript/components/member-expression.test.tsx +4 -4
- package/test/typescript/components/value-expression.test.tsx +236 -0
- package/test/typescript/test-host.ts +8 -0
|
@@ -10,5 +10,5 @@ export declare function InterfaceDeclaration(props: InterfaceDeclarationProps):
|
|
|
10
10
|
export interface InterfaceExpressionProps extends ts.InterfaceExpressionProps {
|
|
11
11
|
type: Model | Interface;
|
|
12
12
|
}
|
|
13
|
-
export declare function InterfaceExpression(
|
|
13
|
+
export declare function InterfaceExpression(props: InterfaceExpressionProps): ay.Children;
|
|
14
14
|
//# sourceMappingURL=interface-declaration.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"interface-declaration.d.ts","sourceRoot":"","sources":["../../../../src/typescript/components/interface-declaration.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAErC,OAAO,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAC3C,OAAO,
|
|
1
|
+
{"version":3,"file":"interface-declaration.d.ts","sourceRoot":"","sources":["../../../../src/typescript/components/interface-declaration.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAErC,OAAO,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAC3C,OAAO,EACL,SAAS,EAET,KAAK,EAIN,MAAM,oBAAoB,CAAC;AAM5B,MAAM,WAAW,8BAA+B,SAAQ,IAAI,CAAC,EAAE,CAAC,yBAAyB,EAAE,MAAM,CAAC;IAChG,IAAI,EAAE,KAAK,GAAG,SAAS,CAAC;IACxB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,MAAM,yBAAyB,GACjC,8BAA8B,GAC9B,EAAE,CAAC,yBAAyB,CAAC;AAEjC,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,yBAAyB,eA+BpE;AAQD,MAAM,WAAW,wBAAyB,SAAQ,EAAE,CAAC,wBAAwB;IAC3E,IAAI,EAAE,KAAK,GAAG,SAAS,CAAC;CACzB;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,wBAAwB,eAMlE"}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
import { memo as _$memo } from "@alloy-js/core/jsx-runtime";
|
|
2
|
+
import { mergeProps as _$mergeProps } from "@alloy-js/core/jsx-runtime";
|
|
1
3
|
import { createComponent as _$createComponent } from "@alloy-js/core/jsx-runtime";
|
|
2
4
|
import * as ay from "@alloy-js/core";
|
|
3
5
|
import { refkey as getRefkey, mapJoin } from "@alloy-js/core";
|
|
4
6
|
import * as ts from "@alloy-js/typescript";
|
|
7
|
+
import { isNeverType } from "@typespec/compiler";
|
|
5
8
|
import { $ } from "@typespec/compiler/experimental/typekit";
|
|
6
9
|
import { createRekeyableMap } from "@typespec/compiler/utils";
|
|
7
10
|
import { reportDiagnostic } from "../../lib.js";
|
|
@@ -22,13 +25,6 @@ export function InterfaceDeclaration(props) {
|
|
|
22
25
|
name = namePolicy.getName(name, "interface");
|
|
23
26
|
const refkey = props.refkey ?? getRefkey(props.type);
|
|
24
27
|
const extendsType = props.extends ?? getExtendsType(props.type);
|
|
25
|
-
const members = props.type ? [membersFromType(props.type)] : [];
|
|
26
|
-
const children = [...members];
|
|
27
|
-
if (Array.isArray(props.children)) {
|
|
28
|
-
children.push(...props.children);
|
|
29
|
-
} else if (props.children) {
|
|
30
|
-
children.push(props.children);
|
|
31
|
-
}
|
|
32
28
|
return _$createComponent(ts.InterfaceDeclaration, {
|
|
33
29
|
get ["default"]() {
|
|
34
30
|
return props.default;
|
|
@@ -42,18 +38,20 @@ export function InterfaceDeclaration(props) {
|
|
|
42
38
|
name: name,
|
|
43
39
|
refkey: refkey,
|
|
44
40
|
"extends": extendsType,
|
|
45
|
-
children
|
|
41
|
+
get children() {
|
|
42
|
+
return _$createComponent(InterfaceBody, props);
|
|
43
|
+
}
|
|
46
44
|
});
|
|
47
45
|
}
|
|
48
46
|
function isTypedInterfaceDeclarationProps(props) {
|
|
49
47
|
return "type" in props;
|
|
50
48
|
}
|
|
51
|
-
export function InterfaceExpression({
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
49
|
+
export function InterfaceExpression(props) {
|
|
50
|
+
return _$createComponent(ay.Block, {
|
|
51
|
+
get children() {
|
|
52
|
+
return _$createComponent(InterfaceBody, props);
|
|
53
|
+
}
|
|
54
|
+
});
|
|
57
55
|
}
|
|
58
56
|
function getExtendsType(type) {
|
|
59
57
|
if (!$.model.is(type)) {
|
|
@@ -95,11 +93,15 @@ function getExtendsType(type) {
|
|
|
95
93
|
joiner: ","
|
|
96
94
|
});
|
|
97
95
|
}
|
|
98
|
-
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Renders the members of an interface from its properties, including any additional children.
|
|
99
|
+
*/
|
|
100
|
+
function InterfaceBody(props) {
|
|
99
101
|
let typeMembers;
|
|
100
|
-
if ($.model.is(type)) {
|
|
101
|
-
typeMembers = $.model.getProperties(type);
|
|
102
|
-
const additionalProperties = $.model.getAdditionalPropertiesRecord(type);
|
|
102
|
+
if ($.model.is(props.type)) {
|
|
103
|
+
typeMembers = $.model.getProperties(props.type);
|
|
104
|
+
const additionalProperties = $.model.getAdditionalPropertiesRecord(props.type);
|
|
103
105
|
if (additionalProperties) {
|
|
104
106
|
typeMembers.set("additionalProperties", $.modelProperty.create({
|
|
105
107
|
name: "additionalProperties",
|
|
@@ -108,18 +110,28 @@ function membersFromType(type) {
|
|
|
108
110
|
}));
|
|
109
111
|
}
|
|
110
112
|
} else {
|
|
111
|
-
typeMembers = createRekeyableMap(type.operations);
|
|
113
|
+
typeMembers = createRekeyableMap(props.type.operations);
|
|
112
114
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
115
|
+
|
|
116
|
+
// Ensure that we have members to render, otherwise skip rendering the ender property.
|
|
117
|
+
const validTypeMembers = Array.from(typeMembers.values()).filter(member => {
|
|
118
|
+
if ($.modelProperty.is(member) && isNeverType(member.type)) {
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
return true;
|
|
122
|
+
});
|
|
123
|
+
const enderProp = validTypeMembers.length > 0 ? {
|
|
124
|
+
ender: ";"
|
|
125
|
+
} : {};
|
|
126
|
+
return [_$createComponent(ay.For, _$mergeProps({
|
|
127
|
+
each: validTypeMembers,
|
|
128
|
+
line: true
|
|
129
|
+
}, enderProp, {
|
|
130
|
+
children: typeMember => {
|
|
119
131
|
return _$createComponent(InterfaceMember, {
|
|
120
|
-
type:
|
|
132
|
+
type: typeMember
|
|
121
133
|
});
|
|
122
134
|
}
|
|
123
|
-
});
|
|
135
|
+
})), _$memo(() => props.children)];
|
|
124
136
|
}
|
|
125
137
|
//# sourceMappingURL=interface-declaration.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"interface-declaration.js","names":["ay","refkey","getRefkey","mapJoin","ts","$","createRekeyableMap","reportDiagnostic","InterfaceMember","TypeExpression","InterfaceDeclaration","props","isTypedInterfaceDeclarationProps","_$createComponent","namePolicy","useTSNamePolicy","name","type","program","code","target","getName","extendsType","extends","getExtendsType","
|
|
1
|
+
{"version":3,"file":"interface-declaration.js","names":["ay","refkey","getRefkey","mapJoin","ts","isNeverType","$","createRekeyableMap","reportDiagnostic","InterfaceMember","TypeExpression","InterfaceDeclaration","props","isTypedInterfaceDeclarationProps","_$createComponent","namePolicy","useTSNamePolicy","name","type","program","code","target","getName","extendsType","extends","getExtendsType","default","export","kind","children","InterfaceBody","InterfaceExpression","Block","model","is","undefined","extending","baseModel","array","push","record","spreadType","getSpreadType","length","ext","joiner","typeMembers","getProperties","additionalProperties","getAdditionalPropertiesRecord","set","modelProperty","create","optional","operations","validTypeMembers","Array","from","values","filter","member","enderProp","ender","For","_$mergeProps","each","line","typeMember","_$memo"],"sources":["../../../../src/typescript/components/interface-declaration.tsx"],"sourcesContent":[null],"mappings":"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","ignoreList":[]}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import * as ay from "@alloy-js/core";
|
|
1
2
|
import { ModelProperty, Operation } from "@typespec/compiler";
|
|
2
3
|
export interface InterfaceMemberProps {
|
|
3
4
|
type: ModelProperty | Operation;
|
|
4
5
|
optional?: boolean;
|
|
5
6
|
}
|
|
6
|
-
export declare function InterfaceMember(
|
|
7
|
+
export declare function InterfaceMember(props: InterfaceMemberProps): ay.Children;
|
|
7
8
|
//# sourceMappingURL=interface-member.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"interface-member.d.ts","sourceRoot":"","sources":["../../../../src/typescript/components/interface-member.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"interface-member.d.ts","sourceRoot":"","sources":["../../../../src/typescript/components/interface-member.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAErC,OAAO,EAAe,aAAa,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAM3E,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,aAAa,GAAG,SAAS,CAAC;IAChC,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,oBAAoB,eA2C1D"}
|
|
@@ -1,42 +1,57 @@
|
|
|
1
1
|
import { createComponent as _$createComponent } from "@alloy-js/core/jsx-runtime";
|
|
2
|
-
import {
|
|
2
|
+
import { memo as _$memo } from "@alloy-js/core/jsx-runtime";
|
|
3
|
+
import * as ay from "@alloy-js/core";
|
|
4
|
+
import * as ts from "@alloy-js/typescript";
|
|
3
5
|
import { isNeverType } from "@typespec/compiler";
|
|
4
6
|
import { $ } from "@typespec/compiler/experimental/typekit";
|
|
5
7
|
import { getHttpPart } from "@typespec/http";
|
|
6
8
|
import { FunctionDeclaration } from "./function-declaration.js";
|
|
7
9
|
import { TypeExpression } from "./type-expression.js";
|
|
8
|
-
export function InterfaceMember({
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
const name = namer.getName(type.name, "object-member-getter");
|
|
14
|
-
if ($.modelProperty.is(type)) {
|
|
15
|
-
const optionality = optional === true || type.optional === true ? "?" : "";
|
|
16
|
-
if (isNeverType(type.type)) {
|
|
10
|
+
export function InterfaceMember(props) {
|
|
11
|
+
const namer = ts.useTSNamePolicy();
|
|
12
|
+
const name = namer.getName(props.type.name, "object-member-getter");
|
|
13
|
+
if ($.modelProperty.is(props.type)) {
|
|
14
|
+
if (isNeverType(props.type.type)) {
|
|
17
15
|
return null;
|
|
18
16
|
}
|
|
19
|
-
let unpackedType = type.type;
|
|
20
|
-
const part = getHttpPart($.program, type.type);
|
|
17
|
+
let unpackedType = props.type.type;
|
|
18
|
+
const part = getHttpPart($.program, props.type.type);
|
|
21
19
|
if (part) {
|
|
22
20
|
unpackedType = part.type;
|
|
23
21
|
}
|
|
24
|
-
return
|
|
25
|
-
|
|
26
|
-
|
|
22
|
+
return _$createComponent(ts.InterfaceMember, {
|
|
23
|
+
name: name,
|
|
24
|
+
get optional() {
|
|
25
|
+
return props.optional ?? props.type.optional;
|
|
26
|
+
},
|
|
27
|
+
get type() {
|
|
28
|
+
return _$createComponent(TypeExpression, {
|
|
29
|
+
type: unpackedType
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
});
|
|
27
33
|
}
|
|
28
|
-
if ($.operation.is(type)) {
|
|
34
|
+
if ($.operation.is(props.type)) {
|
|
29
35
|
const returnType = _$createComponent(TypeExpression, {
|
|
30
36
|
get type() {
|
|
31
|
-
return type.returnType;
|
|
37
|
+
return props.type.returnType;
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
const params = _$createComponent(ay.Scope, {
|
|
41
|
+
get children() {
|
|
42
|
+
return _$createComponent(FunctionDeclaration.Parameters, {
|
|
43
|
+
get type() {
|
|
44
|
+
return props.type.parameters;
|
|
45
|
+
}
|
|
46
|
+
});
|
|
32
47
|
}
|
|
33
48
|
});
|
|
34
|
-
|
|
49
|
+
return _$createComponent(ts.InterfaceMember, {
|
|
50
|
+
name: name,
|
|
35
51
|
get type() {
|
|
36
|
-
return
|
|
52
|
+
return ["(", params, ") => ", returnType];
|
|
37
53
|
}
|
|
38
54
|
});
|
|
39
|
-
return [name, "(", params, "): ", returnType, ";"];
|
|
40
55
|
}
|
|
41
56
|
}
|
|
42
57
|
//# sourceMappingURL=interface-member.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"interface-member.js","names":["
|
|
1
|
+
{"version":3,"file":"interface-member.js","names":["ay","ts","isNeverType","$","getHttpPart","FunctionDeclaration","TypeExpression","InterfaceMember","props","namer","useTSNamePolicy","name","getName","type","modelProperty","is","unpackedType","part","program","_$createComponent","optional","operation","returnType","params","Scope","children","Parameters","parameters"],"sources":["../../../../src/typescript/components/interface-member.tsx"],"sourcesContent":[null],"mappings":";;AAAA,OAAO,KAAKA,EAAE,MAAM,gBAAgB;AACpC,OAAO,KAAKC,EAAE,MAAM,sBAAsB;AAC1C,SAASC,WAAW,QAAkC,oBAAoB;AAC1E,SAASC,CAAC,QAAQ,yCAAyC;AAC3D,SAASC,WAAW,QAAQ,gBAAgB;AAC5C,SAASC,mBAAmB,QAAQ,2BAA2B;AAC/D,SAASC,cAAc,QAAQ,sBAAsB;AAOrD,OAAO,SAASC,eAAeA,CAACC,KAA2B,EAAE;EAC3D,MAAMC,KAAK,GAAGR,EAAE,CAACS,eAAe,CAAC,CAAC;EAClC,MAAMC,IAAI,GAAGF,KAAK,CAACG,OAAO,CAACJ,KAAK,CAACK,IAAI,CAACF,IAAI,EAAE,sBAAsB,CAAC;EAEnE,IAAIR,CAAC,CAACW,aAAa,CAACC,EAAE,CAACP,KAAK,CAACK,IAAI,CAAC,EAAE;IAClC,IAAIX,WAAW,CAACM,KAAK,CAACK,IAAI,CAACA,IAAI,CAAC,EAAE;MAChC,OAAO,IAAI;IACb;IAEA,IAAIG,YAAY,GAAGR,KAAK,CAACK,IAAI,CAACA,IAAI;IAClC,MAAMI,IAAI,GAAGb,WAAW,CAACD,CAAC,CAACe,OAAO,EAAEV,KAAK,CAACK,IAAI,CAACA,IAAI,CAAC;IACpD,IAAII,IAAI,EAAE;MACRD,YAAY,GAAGC,IAAI,CAACJ,IAAI;IAC1B;IAEA,OAAAM,iBAAA,CACGlB,EAAE,CAACM,eAAe;MACjBI,IAAI,EAAEA,IAAI;MAAA,IACVS,QAAQA,CAAA;QAAA,OAAEZ,KAAK,CAACY,QAAQ,IAAIZ,KAAK,CAACK,IAAI,CAACO,QAAQ;MAAA;MAAA,IAC/CP,IAAIA,CAAA;QAAA,OAAAM,iBAAA,CAAGb,cAAc;UAACO,IAAI,EAAEG;QAAY;MAAA;IAAA;EAG9C;EAEA,IAAIb,CAAC,CAACkB,SAAS,CAACN,EAAE,CAACP,KAAK,CAACK,IAAI,CAAC,EAAE;IAC9B,MAAMS,UAAU,GAAAH,iBAAA,CAAIb,cAAc;MAAA,IAACO,IAAIA,CAAA;QAAA,OAAEL,KAAK,CAACK,IAAI,CAACS,UAAU;MAAA;IAAA,EAAI;IAClE,MAAMC,MAAM,GAAAJ,iBAAA,CACTnB,EAAE,CAACwB,KAAK;MAAA,IAAAC,SAAA;QAAA,OAAAN,iBAAA,CACNd,mBAAmB,CAACqB,UAAU;UAAA,IAACb,IAAIA,CAAA;YAAA,OAAEL,KAAK,CAACK,IAAI,CAACc,UAAU;UAAA;QAAA;MAAA;IAAA,EAE9D;IAED,OAAAR,iBAAA,CACGlB,EAAE,CAACM,eAAe;MACjBI,IAAI,EAAEA,IAAI;MAAA,IACVE,IAAIA,CAAA;QAAA,aAEEU,MAAM,WAASD,UAAU;MAAA;IAAA;EAKrC;AACF","ignoreList":[]}
|
|
@@ -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
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
import * as ay from "@alloy-js/core";
|
|
2
2
|
import { Children, refkey as getRefkey, mapJoin } from "@alloy-js/core";
|
|
3
3
|
import * as ts from "@alloy-js/typescript";
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
Interface,
|
|
6
|
+
isNeverType,
|
|
7
|
+
Model,
|
|
8
|
+
ModelProperty,
|
|
9
|
+
Operation,
|
|
10
|
+
RekeyableMap,
|
|
11
|
+
} from "@typespec/compiler";
|
|
5
12
|
import { $ } from "@typespec/compiler/experimental/typekit";
|
|
6
13
|
import { createRekeyableMap } from "@typespec/compiler/utils";
|
|
7
14
|
import { reportDiagnostic } from "../../lib.js";
|
|
@@ -35,16 +42,6 @@ export function InterfaceDeclaration(props: InterfaceDeclarationProps) {
|
|
|
35
42
|
|
|
36
43
|
const extendsType = props.extends ?? getExtendsType(props.type);
|
|
37
44
|
|
|
38
|
-
const members = props.type ? [membersFromType(props.type)] : [];
|
|
39
|
-
|
|
40
|
-
const children = [...members];
|
|
41
|
-
|
|
42
|
-
if (Array.isArray(props.children)) {
|
|
43
|
-
children.push(...props.children);
|
|
44
|
-
} else if (props.children) {
|
|
45
|
-
children.push(props.children);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
45
|
return (
|
|
49
46
|
<ts.InterfaceDeclaration
|
|
50
47
|
default={props.default}
|
|
@@ -54,7 +51,7 @@ export function InterfaceDeclaration(props: InterfaceDeclarationProps) {
|
|
|
54
51
|
refkey={refkey}
|
|
55
52
|
extends={extendsType}
|
|
56
53
|
>
|
|
57
|
-
{
|
|
54
|
+
<InterfaceBody {...props} />
|
|
58
55
|
</ts.InterfaceDeclaration>
|
|
59
56
|
);
|
|
60
57
|
}
|
|
@@ -69,16 +66,11 @@ export interface InterfaceExpressionProps extends ts.InterfaceExpressionProps {
|
|
|
69
66
|
type: Model | Interface;
|
|
70
67
|
}
|
|
71
68
|
|
|
72
|
-
export function InterfaceExpression(
|
|
73
|
-
const members = type ? membersFromType(type) : [];
|
|
74
|
-
|
|
69
|
+
export function InterfaceExpression(props: InterfaceExpressionProps) {
|
|
75
70
|
return (
|
|
76
|
-
|
|
77
|
-
{
|
|
78
|
-
|
|
79
|
-
{children}
|
|
80
|
-
{"}"}
|
|
81
|
-
</>
|
|
71
|
+
<ay.Block>
|
|
72
|
+
<InterfaceBody {...props} />
|
|
73
|
+
</ay.Block>
|
|
82
74
|
);
|
|
83
75
|
}
|
|
84
76
|
|
|
@@ -124,11 +116,14 @@ function getExtendsType(type: Model | Interface): Children | undefined {
|
|
|
124
116
|
);
|
|
125
117
|
}
|
|
126
118
|
|
|
127
|
-
|
|
119
|
+
/**
|
|
120
|
+
* Renders the members of an interface from its properties, including any additional children.
|
|
121
|
+
*/
|
|
122
|
+
function InterfaceBody(props: TypedInterfaceDeclarationProps): Children {
|
|
128
123
|
let typeMembers: RekeyableMap<string, ModelProperty | Operation> | undefined;
|
|
129
|
-
if ($.model.is(type)) {
|
|
130
|
-
typeMembers = $.model.getProperties(type);
|
|
131
|
-
const additionalProperties = $.model.getAdditionalPropertiesRecord(type);
|
|
124
|
+
if ($.model.is(props.type)) {
|
|
125
|
+
typeMembers = $.model.getProperties(props.type);
|
|
126
|
+
const additionalProperties = $.model.getAdditionalPropertiesRecord(props.type);
|
|
132
127
|
if (additionalProperties) {
|
|
133
128
|
typeMembers.set(
|
|
134
129
|
"additionalProperties",
|
|
@@ -140,14 +135,26 @@ function membersFromType(type: Model | Interface): Children {
|
|
|
140
135
|
);
|
|
141
136
|
}
|
|
142
137
|
} else {
|
|
143
|
-
typeMembers = createRekeyableMap(type.operations);
|
|
138
|
+
typeMembers = createRekeyableMap(props.type.operations);
|
|
144
139
|
}
|
|
145
140
|
|
|
141
|
+
// Ensure that we have members to render, otherwise skip rendering the ender property.
|
|
142
|
+
const validTypeMembers = Array.from(typeMembers.values()).filter((member) => {
|
|
143
|
+
if ($.modelProperty.is(member) && isNeverType(member.type)) {
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
return true;
|
|
147
|
+
});
|
|
148
|
+
const enderProp = validTypeMembers.length > 0 ? { ender: ";" } : {};
|
|
149
|
+
|
|
146
150
|
return (
|
|
147
|
-
|
|
148
|
-
{
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
151
|
+
<>
|
|
152
|
+
<ay.For each={validTypeMembers} line {...enderProp}>
|
|
153
|
+
{(typeMember) => {
|
|
154
|
+
return <InterfaceMember type={typeMember} />;
|
|
155
|
+
}}
|
|
156
|
+
</ay.For>
|
|
157
|
+
{props.children}
|
|
158
|
+
</>
|
|
152
159
|
);
|
|
153
160
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as ay from "@alloy-js/core";
|
|
2
|
+
import * as ts from "@alloy-js/typescript";
|
|
2
3
|
import { isNeverType, ModelProperty, Operation } from "@typespec/compiler";
|
|
3
4
|
import { $ } from "@typespec/compiler/experimental/typekit";
|
|
4
5
|
import { getHttpPart } from "@typespec/http";
|
|
@@ -10,37 +11,47 @@ export interface InterfaceMemberProps {
|
|
|
10
11
|
optional?: boolean;
|
|
11
12
|
}
|
|
12
13
|
|
|
13
|
-
export function InterfaceMember(
|
|
14
|
-
const namer = useTSNamePolicy();
|
|
15
|
-
const name = namer.getName(type.name, "object-member-getter");
|
|
14
|
+
export function InterfaceMember(props: InterfaceMemberProps) {
|
|
15
|
+
const namer = ts.useTSNamePolicy();
|
|
16
|
+
const name = namer.getName(props.type.name, "object-member-getter");
|
|
16
17
|
|
|
17
|
-
if ($.modelProperty.is(type)) {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
if (isNeverType(type.type)) {
|
|
18
|
+
if ($.modelProperty.is(props.type)) {
|
|
19
|
+
if (isNeverType(props.type.type)) {
|
|
21
20
|
return null;
|
|
22
21
|
}
|
|
23
22
|
|
|
24
|
-
let unpackedType = type.type;
|
|
25
|
-
const part = getHttpPart($.program, type.type);
|
|
23
|
+
let unpackedType = props.type.type;
|
|
24
|
+
const part = getHttpPart($.program, props.type.type);
|
|
26
25
|
if (part) {
|
|
27
26
|
unpackedType = part.type;
|
|
28
27
|
}
|
|
29
28
|
|
|
30
29
|
return (
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
<ts.InterfaceMember
|
|
31
|
+
name={name}
|
|
32
|
+
optional={props.optional ?? props.type.optional}
|
|
33
|
+
type={<TypeExpression type={unpackedType} />}
|
|
34
|
+
/>
|
|
34
35
|
);
|
|
35
36
|
}
|
|
36
37
|
|
|
37
|
-
if ($.operation.is(type)) {
|
|
38
|
-
const returnType = <TypeExpression type={type.returnType} />;
|
|
39
|
-
const params =
|
|
38
|
+
if ($.operation.is(props.type)) {
|
|
39
|
+
const returnType = <TypeExpression type={props.type.returnType} />;
|
|
40
|
+
const params = (
|
|
41
|
+
<ay.Scope>
|
|
42
|
+
<FunctionDeclaration.Parameters type={props.type.parameters} />
|
|
43
|
+
</ay.Scope>
|
|
44
|
+
);
|
|
45
|
+
|
|
40
46
|
return (
|
|
41
|
-
|
|
42
|
-
{name}
|
|
43
|
-
|
|
47
|
+
<ts.InterfaceMember
|
|
48
|
+
name={name}
|
|
49
|
+
type={
|
|
50
|
+
<>
|
|
51
|
+
({params}) => {returnType}
|
|
52
|
+
</>
|
|
53
|
+
}
|
|
54
|
+
/>
|
|
44
55
|
);
|
|
45
56
|
}
|
|
46
57
|
}
|
|
@@ -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
|
+
}
|
|
@@ -337,6 +337,39 @@ describe("Typescript Interface", () => {
|
|
|
337
337
|
expect(actualContent).toBe(expectedContent);
|
|
338
338
|
});
|
|
339
339
|
|
|
340
|
+
it("renders an empty interface with a never-typed member", async () => {
|
|
341
|
+
const program = await getProgram(`
|
|
342
|
+
namespace DemoService;
|
|
343
|
+
|
|
344
|
+
model Widget{
|
|
345
|
+
property: never;
|
|
346
|
+
}
|
|
347
|
+
`);
|
|
348
|
+
|
|
349
|
+
const [namespace] = program.resolveTypeReference("DemoService");
|
|
350
|
+
const models = Array.from((namespace as Namespace).models.values());
|
|
351
|
+
|
|
352
|
+
const res = render(
|
|
353
|
+
<Output>
|
|
354
|
+
<SourceFile path="test.ts">
|
|
355
|
+
<InterfaceDeclaration export type={models[0]} />
|
|
356
|
+
</SourceFile>
|
|
357
|
+
</Output>,
|
|
358
|
+
);
|
|
359
|
+
|
|
360
|
+
const testFile = res.contents.find((file) => file.path === "test.ts");
|
|
361
|
+
assert(testFile, "test.ts file not rendered");
|
|
362
|
+
const actualContent = await format(testFile.contents as string, { parser: "typescript" });
|
|
363
|
+
const expectedContent = await format(
|
|
364
|
+
`export interface Widget {
|
|
365
|
+
}`,
|
|
366
|
+
{
|
|
367
|
+
parser: "typescript",
|
|
368
|
+
},
|
|
369
|
+
);
|
|
370
|
+
expect(actualContent).toBe(expectedContent);
|
|
371
|
+
});
|
|
372
|
+
|
|
340
373
|
it("can override interface name", async () => {
|
|
341
374
|
const program = await getProgram(`
|
|
342
375
|
namespace DemoService;
|
|
@@ -505,7 +538,7 @@ describe("Typescript Interface", () => {
|
|
|
505
538
|
});
|
|
506
539
|
});
|
|
507
540
|
|
|
508
|
-
describe
|
|
541
|
+
describe("Bound to Interface", () => {
|
|
509
542
|
it("creates an interface", async () => {
|
|
510
543
|
const program = await getProgram(`
|
|
511
544
|
namespace DemoService;
|
|
@@ -531,7 +564,7 @@ describe("Typescript Interface", () => {
|
|
|
531
564
|
const actualContent = await format(testFile.contents as string, { parser: "typescript" });
|
|
532
565
|
const expectedContent = await format(
|
|
533
566
|
`export interface WidgetOperations {
|
|
534
|
-
getName(id: string)
|
|
567
|
+
getName: (id: string) => string;
|
|
535
568
|
}`,
|
|
536
569
|
{
|
|
537
570
|
parser: "typescript",
|
|
@@ -572,8 +605,8 @@ describe("Typescript Interface", () => {
|
|
|
572
605
|
const actualContent = await format(testFile.contents as string, { parser: "typescript" });
|
|
573
606
|
const expectedContent = await format(
|
|
574
607
|
`export interface WidgetOperations {
|
|
575
|
-
getName(foo: Foo)
|
|
576
|
-
getOtherName(name: string)
|
|
608
|
+
getName: (foo: Foo) => string;
|
|
609
|
+
getOtherName: (name: string) => string
|
|
577
610
|
}
|
|
578
611
|
export interface Foo {
|
|
579
612
|
name: string;
|
|
@@ -621,7 +654,7 @@ describe("Typescript Interface", () => {
|
|
|
621
654
|
const actualContent = await format(testFile.contents as string, { parser: "typescript" });
|
|
622
655
|
const expectedContent = await format(
|
|
623
656
|
`export interface WidgetOperations {
|
|
624
|
-
getName(id: string)
|
|
657
|
+
getName: (id: string) => Widget;
|
|
625
658
|
}
|
|
626
659
|
export interface Widget {
|
|
627
660
|
id: string;
|
|
@@ -674,8 +707,8 @@ describe("Typescript Interface", () => {
|
|
|
674
707
|
const actualContent = await format(testFile.contents as string, { parser: "typescript" });
|
|
675
708
|
const expectedContent = await format(
|
|
676
709
|
`export interface WidgetOperationsExtended {
|
|
677
|
-
getName(id: string)
|
|
678
|
-
delete(id: string)
|
|
710
|
+
getName: (id: string) => Widget;
|
|
711
|
+
delete: (id: string) => void;
|
|
679
712
|
}
|
|
680
713
|
export interface Widget {
|
|
681
714
|
id: string;
|
|
@@ -36,7 +36,7 @@ describe("Typescript Enum Member Expression", () => {
|
|
|
36
36
|
three = 3
|
|
37
37
|
}
|
|
38
38
|
interface Bar {
|
|
39
|
-
|
|
39
|
+
one: Foo.one;
|
|
40
40
|
}
|
|
41
41
|
`);
|
|
42
42
|
});
|
|
@@ -70,7 +70,7 @@ describe("Typescript Enum Member Expression", () => {
|
|
|
70
70
|
three = "three"
|
|
71
71
|
}
|
|
72
72
|
interface Bar {
|
|
73
|
-
|
|
73
|
+
one: Foo.one;
|
|
74
74
|
}
|
|
75
75
|
`);
|
|
76
76
|
});
|
|
@@ -102,7 +102,7 @@ describe("Typescript Union Member Expression", () => {
|
|
|
102
102
|
expect(output).toBe(d`
|
|
103
103
|
type Foo = 1 | 2 | 3;
|
|
104
104
|
interface Bar {
|
|
105
|
-
|
|
105
|
+
one: 1;
|
|
106
106
|
}
|
|
107
107
|
`);
|
|
108
108
|
});
|
|
@@ -132,7 +132,7 @@ describe("Typescript Union Member Expression", () => {
|
|
|
132
132
|
expect(output).toBe(d`
|
|
133
133
|
type Foo = "one" | "two" | "three";
|
|
134
134
|
interface Bar {
|
|
135
|
-
|
|
135
|
+
one: "one";
|
|
136
136
|
}
|
|
137
137
|
`);
|
|
138
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
|
+
}
|