@typespec/emitter-framework 0.10.0 → 0.11.0-dev.1

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.
Files changed (42) hide show
  1. package/dist/src/core/components/index.d.ts +2 -0
  2. package/dist/src/core/components/index.d.ts.map +1 -1
  3. package/dist/src/core/components/index.js +3 -1
  4. package/dist/src/core/components/overrides/component-overrides.d.ts +64 -0
  5. package/dist/src/core/components/overrides/component-overrides.d.ts.map +1 -0
  6. package/dist/src/core/components/overrides/component-overrides.js +40 -0
  7. package/dist/src/core/components/overrides/config.d.ts +28 -0
  8. package/dist/src/core/components/overrides/config.d.ts.map +1 -0
  9. package/dist/src/core/components/overrides/config.js +54 -0
  10. package/dist/src/core/components/overrides/context.d.ts +11 -0
  11. package/dist/src/core/components/overrides/context.d.ts.map +1 -0
  12. package/dist/src/core/components/overrides/context.js +8 -0
  13. package/dist/src/csharp/components/class/declaration.test.js +74 -1
  14. package/dist/src/csharp/components/type-expression.d.ts.map +1 -1
  15. package/dist/src/csharp/components/type-expression.js +12 -3
  16. package/dist/src/testing/scenario-test/harness.js +6 -1
  17. package/dist/src/typescript/components/interface-member.d.ts.map +1 -1
  18. package/dist/src/typescript/components/interface-member.js +11 -19
  19. package/dist/src/typescript/components/type-expression.d.ts +0 -1
  20. package/dist/src/typescript/components/type-expression.d.ts.map +1 -1
  21. package/dist/src/typescript/components/type-expression.js +11 -11
  22. package/dist/src/typescript/components/type-transform.d.ts.map +1 -1
  23. package/dist/src/typescript/components/type-transform.js +3 -3
  24. package/dist/test/typescript/components/component-override.test.d.ts +2 -0
  25. package/dist/test/typescript/components/component-override.test.d.ts.map +1 -0
  26. package/dist/test/typescript/components/component-override.test.js +77 -0
  27. package/dist/test/typescript/test-host.d.ts +2 -6
  28. package/dist/test/typescript/test-host.d.ts.map +1 -1
  29. package/dist/test/typescript/test-host.js +4 -15
  30. package/package.json +5 -8
  31. package/src/core/components/index.tsx +2 -0
  32. package/src/core/components/overrides/component-overrides.tsx +134 -0
  33. package/src/core/components/overrides/config.ts +85 -0
  34. package/src/core/components/overrides/context.ts +14 -0
  35. package/src/csharp/components/class/declaration.test.tsx +65 -1
  36. package/src/csharp/components/type-expression.tsx +6 -1
  37. package/src/testing/scenario-test/harness.ts +6 -1
  38. package/src/typescript/components/interface-member.tsx +8 -14
  39. package/src/typescript/components/type-expression.tsx +7 -8
  40. package/src/typescript/components/type-transform.tsx +3 -7
  41. package/test/typescript/components/component-override.test.tsx +71 -0
  42. package/test/typescript/test-host.ts +4 -16
@@ -1,15 +1,6 @@
1
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
- });
2
+ export async function createTypespecCliTestHost() {
3
+ return createTestHost({});
13
4
  }
14
5
  export async function createEmitterFrameworkTestRunner(options = {}) {
15
6
  const host = await createTypespecCliTestHost();
@@ -17,10 +8,8 @@ export async function createEmitterFrameworkTestRunner(options = {}) {
17
8
  autoUsings: options.autoUsings
18
9
  });
19
10
  }
20
- export async function getProgram(code, options = {
21
- libraries: []
22
- }) {
23
- const host = await createTypespecCliTestHost(options);
11
+ export async function getProgram(code) {
12
+ const host = await createTypespecCliTestHost();
24
13
  const wrapper = createTestWrapper(host, {
25
14
  compilerOptions: {
26
15
  noEmit: true
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@typespec/emitter-framework",
3
- "version": "0.10.0",
3
+ "version": "0.11.0-dev.1",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "repository": {
@@ -44,15 +44,14 @@
44
44
  "@alloy-js/core": "^0.19.0",
45
45
  "@alloy-js/csharp": "^0.19.0",
46
46
  "@alloy-js/typescript": "^0.19.0",
47
- "@typespec/compiler": "^1.3.0",
48
- "@typespec/rest": "^0.73.0",
49
- "@typespec/http": "^1.3.0"
47
+ "@typespec/compiler": "^1.3.0"
50
48
  },
51
49
  "devDependencies": {
52
50
  "@alloy-js/cli": "^0.19.0",
53
51
  "@alloy-js/core": "^0.19.0",
54
52
  "@alloy-js/rollup-plugin": "^0.1.0",
55
53
  "@alloy-js/typescript": "^0.19.0",
54
+ "@typespec/compiler": "^1.3.0",
56
55
  "concurrently": "^9.1.2",
57
56
  "pathe": "^2.0.3",
58
57
  "prettier": "~3.6.2",
@@ -63,11 +62,9 @@
63
62
  "tree-sitter-typescript": "^0.23.0",
64
63
  "typescript": "~5.8.2",
65
64
  "vitest": "^3.1.2",
66
- "web-tree-sitter": "^0.25.4",
67
- "@typespec/compiler": "^1.3.0",
68
- "@typespec/http": "^1.3.0",
69
- "@typespec/rest": "^0.73.0"
65
+ "web-tree-sitter": "^0.25.4"
70
66
  },
67
+ "dependencies": {},
71
68
  "scripts": {
72
69
  "build": "alloy build",
73
70
  "clean": "rimraf ./dist",
@@ -1 +1,3 @@
1
1
  export * from "./output.jsx";
2
+ export * from "./overrides/component-overrides.jsx";
3
+ export * from "./overrides/config.js";
@@ -0,0 +1,134 @@
1
+ import { type Children, type ComponentDefinition } from "@alloy-js/core";
2
+ import type { ObjectPropertyProps, VarDeclarationProps } from "@alloy-js/typescript";
3
+ import type {
4
+ Enum,
5
+ EnumMember,
6
+ Model,
7
+ ModelProperty,
8
+ Scalar,
9
+ Type,
10
+ Union,
11
+ UnionVariant,
12
+ } from "@typespec/compiler";
13
+ import { useTsp } from "../../context/index.js";
14
+ import {
15
+ type Experimental_ComponentOverridesConfig,
16
+ getOverrideForType,
17
+ getOverridesForTypeKind,
18
+ } from "./config.js";
19
+ import { type ComponentOverridesContext, OverridesContext, useOverrides } from "./context.js";
20
+
21
+ export interface Experimental_OverrideEmitPropsBase<TCustomType extends Type> {
22
+ /**
23
+ * The TypeSpec type to render.
24
+ */
25
+ type: TCustomType;
26
+
27
+ /**
28
+ * The default emitted output for this type.
29
+ */
30
+ default: Children;
31
+ }
32
+
33
+ export type Experimental_CustomTypeToProps<TCustomType extends Type> =
34
+ TCustomType extends ModelProperty
35
+ ? ObjectPropertyProps
36
+ : TCustomType extends EnumMember
37
+ ? {}
38
+ : TCustomType extends UnionVariant
39
+ ? {}
40
+ : TCustomType extends Model | Scalar | Union | Enum
41
+ ? VarDeclarationProps
42
+ : VarDeclarationProps | ObjectPropertyProps;
43
+
44
+ export interface Experimental_OverrideReferenceProps<TCustomType extends Type>
45
+ extends Experimental_OverrideEmitPropsBase<TCustomType> {
46
+ /**
47
+ * The member this type is referenced from, if any. This member may contain
48
+ * additional metadata that should be represented in the emitted output.
49
+ */
50
+ member?: ModelProperty;
51
+ }
52
+
53
+ export interface Experimental_OverrideDeclareProps<TCustomType extends Type>
54
+ extends Experimental_OverrideEmitPropsBase<TCustomType> {
55
+ Declaration: ComponentDefinition<Experimental_CustomTypeToProps<TCustomType>>;
56
+ declarationProps: Experimental_CustomTypeToProps<TCustomType>;
57
+ }
58
+
59
+ export type Experimental_OverrideDeclarationComponent<TCustomType extends Type> =
60
+ ComponentDefinition<Experimental_OverrideDeclareProps<TCustomType>>;
61
+
62
+ export type Experimental_OverrideReferenceComponent<TCustomType extends Type> = ComponentDefinition<
63
+ Experimental_OverrideReferenceProps<TCustomType>
64
+ >;
65
+
66
+ export interface Experimental_ComponentOverridesConfigBase<TCustomType extends Type> {
67
+ /**
68
+ * Override when this type is referenced.
69
+ * e.g. When used in <TypeExpression type={type} />
70
+ */
71
+ reference?: Experimental_OverrideReferenceComponent<TCustomType>;
72
+ }
73
+
74
+ export interface Experimental_ComponentOverridesProps {
75
+ overrides: Experimental_ComponentOverridesConfig;
76
+ children?: Children;
77
+ }
78
+ export function Experimental_ComponentOverrides(props: Experimental_ComponentOverridesProps) {
79
+ const context: ComponentOverridesContext = {
80
+ overrides: props.overrides,
81
+ };
82
+
83
+ return <OverridesContext.Provider value={context}>{props.children}</OverridesContext.Provider>;
84
+ }
85
+
86
+ export interface Experimental_OverrideTypeComponentCommonProps<T extends Type> {
87
+ /**
88
+ * The TypeSpec type to render.
89
+ */
90
+ type: T;
91
+
92
+ /**
93
+ * The default rendering.
94
+ */
95
+ children: Children;
96
+ }
97
+
98
+ export interface Experimental_OverridableComponentReferenceProps<T extends Type>
99
+ extends Experimental_OverrideTypeComponentCommonProps<T> {
100
+ /**
101
+ * Pass when rendering a reference to the provided type or type kind.
102
+ */
103
+ reference: true;
104
+
105
+ /**
106
+ * The member this type is referenced from, if any. This member may contain
107
+ * additional metadata that should be represented in the emitted output.
108
+ */
109
+ member?: ModelProperty;
110
+ }
111
+
112
+ export type Experimental_OverridableComponentProps<T extends Type> =
113
+ Experimental_OverridableComponentReferenceProps<T>;
114
+
115
+ export function Experimental_OverridableComponent<T extends Type>(
116
+ props: Experimental_OverridableComponentProps<T>,
117
+ ) {
118
+ const options = useOverrides();
119
+ const { $ } = useTsp();
120
+ const descriptor =
121
+ getOverrideForType($.program, props.type, options.overrides) ??
122
+ getOverridesForTypeKind($.program, props.type.kind, options.overrides);
123
+
124
+ if (!descriptor) {
125
+ return <>{props.children}</>;
126
+ }
127
+
128
+ if ("reference" in props && props.reference && descriptor.reference) {
129
+ const CustomComponent = descriptor.reference;
130
+ return <CustomComponent type={props.type} member={props.member} default={props.children} />;
131
+ }
132
+
133
+ return <>{props.children}</>;
134
+ }
@@ -0,0 +1,85 @@
1
+ import type { Program, Scalar, Type } from "@typespec/compiler";
2
+ import { $ } from "@typespec/compiler/typekit";
3
+ import type { Experimental_ComponentOverridesConfigBase } from "./component-overrides.jsx";
4
+
5
+ const getOverrideForTypeSym: unique symbol = Symbol.for("ef-ts:getOverrideForType");
6
+ const getOverrideForTypeKindSym: unique symbol = Symbol.for("ef-ts:getOverrideForTypeKind");
7
+
8
+ export type Experimental_ComponentOverridesConfig = Experimental_ComponentOverridesClass;
9
+ export const Experimental_ComponentOverridesConfig = function () {
10
+ return new Experimental_ComponentOverridesClass();
11
+ } as {
12
+ new (): Experimental_ComponentOverridesClass;
13
+ (): Experimental_ComponentOverridesClass;
14
+ };
15
+
16
+ export class Experimental_ComponentOverridesClass {
17
+ #typeEmitOptions: Map<Type, Experimental_ComponentOverridesConfigBase<any>> = new Map();
18
+ #typeKindEmitOptions: Map<Type["kind"], Experimental_ComponentOverridesConfigBase<any>> =
19
+ new Map();
20
+
21
+ forType<const T extends Type>(type: T, options: Experimental_ComponentOverridesConfigBase<T>) {
22
+ this.#typeEmitOptions.set(type, options);
23
+
24
+ return this;
25
+ }
26
+
27
+ forTypeKind<const TKind extends Type["kind"]>(
28
+ typeKind: TKind,
29
+ options: Experimental_ComponentOverridesConfigBase<Extract<Type, { kind: TKind }>>,
30
+ ) {
31
+ this.#typeKindEmitOptions.set(typeKind, options);
32
+
33
+ return this;
34
+ }
35
+
36
+ /**
37
+ * @internal
38
+ */
39
+ [getOverrideForTypeSym](program: Program, type: Type) {
40
+ const options = this.#typeEmitOptions.get(type);
41
+ if (options || !$(program).scalar.is(type) /** || isBuiltIn(program, type) */) {
42
+ return options;
43
+ }
44
+
45
+ // have a scalar, it's not a built-in scalar, and didn't find options, so
46
+ // see if we have options for a base scalar.
47
+ let currentScalar: Scalar | undefined = type;
48
+ while (
49
+ currentScalar &&
50
+ // !isBuiltIn(program, currentScalar) &&
51
+ !this.#typeEmitOptions.has(currentScalar)
52
+ ) {
53
+ currentScalar = currentScalar?.baseScalar;
54
+ }
55
+
56
+ if (!currentScalar) {
57
+ return undefined;
58
+ }
59
+
60
+ return this.#typeEmitOptions.get(currentScalar);
61
+ }
62
+
63
+ /**
64
+ * @internal
65
+ */
66
+ [getOverrideForTypeKindSym](program: Program, typeKind: Type["kind"]) {
67
+ return this.#typeKindEmitOptions.get(typeKind);
68
+ }
69
+ }
70
+
71
+ export function getOverrideForType(
72
+ program: Program,
73
+ type: Type,
74
+ options?: Experimental_ComponentOverridesConfig,
75
+ ) {
76
+ return options?.[getOverrideForTypeSym](program, type);
77
+ }
78
+
79
+ export function getOverridesForTypeKind(
80
+ program: Program,
81
+ typeKind: Type["kind"],
82
+ options?: Experimental_ComponentOverridesConfig,
83
+ ) {
84
+ return options?.[getOverrideForTypeKindSym](program, typeKind);
85
+ }
@@ -0,0 +1,14 @@
1
+ import { createContext, useContext, type ComponentContext } from "@alloy-js/core";
2
+ import type { Experimental_ComponentOverridesConfig } from "./config.js";
3
+
4
+ export interface ComponentOverridesContext {
5
+ overrides?: Experimental_ComponentOverridesConfig;
6
+ }
7
+ /**
8
+ * Context for setting overrides for components
9
+ */
10
+ export const OverridesContext: ComponentContext<ComponentOverridesContext> = createContext({});
11
+
12
+ export function useOverrides(): ComponentOverridesContext {
13
+ return useContext(OverridesContext)!;
14
+ }
@@ -1,5 +1,10 @@
1
+ import {
2
+ Experimental_ComponentOverrides,
3
+ Experimental_ComponentOverridesConfig,
4
+ } from "#core/index.js";
1
5
  import { Tester } from "#test/test-host.js";
2
- import { type Children } from "@alloy-js/core";
6
+ import { List, type Children } from "@alloy-js/core";
7
+ import { d } from "@alloy-js/core/testing";
3
8
  import { createCSharpNamePolicy, Namespace, SourceFile } from "@alloy-js/csharp";
4
9
  import { t, type TesterInstance } from "@typespec/compiler/testing";
5
10
  import { beforeEach, describe, expect, it } from "vitest";
@@ -67,6 +72,65 @@ it("renders a class declaration with properties", async () => {
67
72
  `);
68
73
  });
69
74
 
75
+ it("renders a class declaration with properties using component override", async () => {
76
+ const { TestModel, Foo, Bar } = await runner.compile(t.code`
77
+ model ${t.model("Foo")} {}
78
+ model ${t.model("Bar")} {}
79
+ model ${t.model("TestModel")} {
80
+ Prop1: string;
81
+ Prop2: int32;
82
+ Prop3?: Foo;
83
+ }
84
+ `);
85
+
86
+ expect(
87
+ <Wrapper>
88
+ <TestClientOverrides>
89
+ <List hardline>
90
+ <ClassDeclaration type={Foo} />
91
+ <ClassDeclaration type={Bar} />
92
+ <ClassDeclaration type={TestModel} />
93
+ </List>
94
+ </TestClientOverrides>
95
+ </Wrapper>,
96
+ ).toRenderTo(d`
97
+ namespace TestNamespace
98
+ {
99
+ class Foo
100
+ {
101
+
102
+ }
103
+ class Bar
104
+ {
105
+
106
+ }
107
+ class TestModel
108
+ {
109
+ public required string Prop1 { get; set; }
110
+ public required int Prop2 { get; set; }
111
+ public Bar Prop3 { get; set; }
112
+ }
113
+ }
114
+ `);
115
+ });
116
+
117
+ function TestClientOverrides(props: { children?: Children }) {
118
+ const overrides = Experimental_ComponentOverridesConfig().forTypeKind("Model", {
119
+ reference: (props) => {
120
+ if (props.type.name === "Foo") {
121
+ return "Bar";
122
+ } else {
123
+ return props.default;
124
+ }
125
+ },
126
+ });
127
+ return (
128
+ <Experimental_ComponentOverrides overrides={overrides}>
129
+ {props.children}
130
+ </Experimental_ComponentOverrides>
131
+ );
132
+ }
133
+
70
134
  it("can override class name", async () => {
71
135
  const { TestModel } = await runner.compile(t.code`
72
136
  model ${t.model("TestModel")} {}
@@ -1,3 +1,4 @@
1
+ import { Experimental_OverridableComponent } from "#core/index.js";
1
2
  import { type Children, code } from "@alloy-js/core";
2
3
  import { Reference } from "@alloy-js/csharp";
3
4
  import { getTypeName, type IntrinsicType, type Scalar, type Type } from "@typespec/compiler";
@@ -13,7 +14,11 @@ export interface TypeExpressionProps {
13
14
  export function TypeExpression(props: TypeExpressionProps): Children {
14
15
  const { $ } = useTsp();
15
16
  if (isDeclaration($, props.type)) {
16
- return <Reference refkey={efRefkey(props.type)} />;
17
+ return (
18
+ <Experimental_OverridableComponent reference type={props.type}>
19
+ <Reference refkey={efRefkey(props.type)} />
20
+ </Experimental_OverridableComponent>
21
+ );
17
22
  }
18
23
  if ($.scalar.is(props.type)) {
19
24
  return getScalarIntrinsicExpression($, props.type);
@@ -198,7 +198,12 @@ function describeScenarios(
198
198
  );
199
199
 
200
200
  if (SCENARIOS_UPDATE) {
201
- testBlock.content = await languageConfiguration.format(result);
201
+ try {
202
+ testBlock.content = await languageConfiguration.format(result);
203
+ } catch {
204
+ // If formatting fails, we still want to update the content
205
+ testBlock.content = result;
206
+ }
202
207
  } else {
203
208
  const expected = await languageConfiguration.format(testBlock.content);
204
209
  const actual = await languageConfiguration.format(result);
@@ -1,7 +1,6 @@
1
1
  import { type Children } from "@alloy-js/core";
2
2
  import * as ts from "@alloy-js/typescript";
3
3
  import { isNeverType, type ModelProperty, type Operation } from "@typespec/compiler";
4
- import { getHttpPart } from "@typespec/http";
5
4
  import { useTsp } from "../../core/context/tsp-context.js";
6
5
  import { InterfaceMethod } from "./interface-method.jsx";
7
6
  import { TypeExpression } from "./type-expression.js";
@@ -23,20 +22,15 @@ export function InterfaceMember(props: InterfaceMemberProps) {
23
22
  return null;
24
23
  }
25
24
 
26
- let unpackedType = props.type.type;
27
- const part = getHttpPart($.program, props.type.type);
28
- if (part) {
29
- unpackedType = part.type;
30
- }
25
+ const unpackedType = props.type.type;
31
26
 
32
- return (
33
- <ts.InterfaceMember
34
- doc={doc}
35
- name={name}
36
- optional={props.optional ?? props.type.optional}
37
- type={<TypeExpression type={unpackedType} />}
38
- />
39
- );
27
+ const interfaceMemberProps = {
28
+ doc,
29
+ name,
30
+ optional: props.optional ?? props.type.optional,
31
+ type: <TypeExpression type={unpackedType} />,
32
+ };
33
+ return <ts.InterfaceMember {...interfaceMemberProps} />;
40
34
  }
41
35
 
42
36
  if ($.operation.is(props.type)) {
@@ -2,7 +2,7 @@ import { For } from "@alloy-js/core";
2
2
  import { Reference, ValueExpression } from "@alloy-js/typescript";
3
3
  import type { IntrinsicType, Model, Scalar, Type } from "@typespec/compiler";
4
4
  import type { Typekit } from "@typespec/compiler/typekit";
5
- import "@typespec/http/experimental/typekit";
5
+ import { Experimental_OverridableComponent } from "../../core/components/overrides/component-overrides.jsx";
6
6
  import { useTsp } from "../../core/context/tsp-context.js";
7
7
  import { reportTypescriptDiagnostic } from "../../typescript/lib.js";
8
8
  import { efRefkey } from "../utils/refkey.js";
@@ -25,11 +25,15 @@ export interface TypeExpressionProps {
25
25
 
26
26
  export function TypeExpression(props: TypeExpressionProps) {
27
27
  const { $ } = useTsp();
28
- const type = $.httpPart.unpack(props.type);
28
+ const type = props.type;
29
29
  if (!props.noReference && isDeclaration($, type)) {
30
30
  // todo: probably need abstraction around deciding what's a declaration in the output
31
31
  // (it may not correspond to things which are declarations in TypeSpec?)
32
- return <Reference refkey={efRefkey(type)} />;
32
+ return (
33
+ <Experimental_OverridableComponent reference type={type}>
34
+ <Reference refkey={efRefkey(type)} />
35
+ </Experimental_OverridableComponent>
36
+ );
33
37
  //throw new Error("Reference not implemented");
34
38
  }
35
39
 
@@ -69,11 +73,6 @@ export function TypeExpression(props: TypeExpressionProps) {
69
73
  return <RecordExpression elementType={elementType} />;
70
74
  }
71
75
 
72
- if ($.httpPart.is(type)) {
73
- const partType = $.httpPart.unpack(type);
74
- return <TypeExpression type={partType} />;
75
- }
76
-
77
76
  return <InterfaceExpression type={type} />;
78
77
  case "Operation":
79
78
  return <FunctionType type={type} />;
@@ -227,7 +227,7 @@ export function ModelTransformExpression(props: ModelTransformExpressionProps) {
227
227
  {mapJoin(
228
228
  () => modelProperties,
229
229
  (_, property) => {
230
- const unpackedType = $.httpPart.unpack(property.type) ?? property.type;
230
+ const unpackedType = property.type;
231
231
  let targetPropertyName = property.name;
232
232
  let sourcePropertyName = namePolicy.getName(property.name, "interface-member");
233
233
 
@@ -368,9 +368,7 @@ export function TypeTransformCall(props: TypeTransformCallProps): Children {
368
368
  }
369
369
  const transformType = collapsedProperty?.type ?? props.type;
370
370
  if ($.model.is(transformType) && $.array.is(transformType)) {
371
- const unpackedElement =
372
- $.httpPart.unpack($.array.getElementType(transformType)) ??
373
- $.array.getElementType(transformType);
371
+ const unpackedElement = $.array.getElementType(transformType);
374
372
  return (
375
373
  <ts.FunctionCallExpression
376
374
  target={ArraySerializerRefkey}
@@ -380,9 +378,7 @@ export function TypeTransformCall(props: TypeTransformCallProps): Children {
380
378
  }
381
379
 
382
380
  if ($.model.is(transformType) && $.record.is(transformType)) {
383
- const unpackedElement =
384
- $.httpPart.unpack($.record.getElementType(transformType)) ??
385
- $.record.getElementType(transformType);
381
+ const unpackedElement = $.record.getElementType(transformType);
386
382
  return (
387
383
  <ts.FunctionCallExpression
388
384
  target={RecordSerializerRefkey}
@@ -0,0 +1,71 @@
1
+ import {
2
+ Experimental_ComponentOverrides,
3
+ Experimental_ComponentOverridesConfig,
4
+ } from "#core/index.js";
5
+ import { FunctionDeclaration } from "#typescript/index.js";
6
+ import { For, List, type Children } from "@alloy-js/core";
7
+ import { d } from "@alloy-js/core/testing";
8
+ import { SourceFile } from "@alloy-js/typescript";
9
+ import type { Namespace } from "@typespec/compiler";
10
+ import { expect, it } from "vitest";
11
+ import { Output } from "../../../src/core/components/output.jsx";
12
+ import { InterfaceDeclaration } from "../../../src/typescript/components/interface-declaration.jsx";
13
+ import { Tester } from "../../test-host.js";
14
+
15
+ it("uses overridden component", async () => {
16
+ const { program } = await Tester.compile(`
17
+ namespace DemoService;
18
+ model Foo {
19
+ knownProp: string;
20
+ }
21
+
22
+ op foo(): Foo;
23
+
24
+ `);
25
+
26
+ const [namespace] = program.resolveTypeReference("DemoService");
27
+ const models = Array.from((namespace as Namespace).models.values());
28
+ const operations = Array.from((namespace as Namespace).operations.values());
29
+
30
+ expect(
31
+ <Output program={program}>
32
+ <TestClientOverrides>
33
+ <SourceFile path="test.ts">
34
+ <List hardline>
35
+ {models.map((model) => (
36
+ <InterfaceDeclaration export type={model} />
37
+ ))}
38
+ </List>
39
+ <hbr />
40
+ <For each={operations}>
41
+ {(operation) => <FunctionDeclaration export type={operation} />}
42
+ </For>
43
+ </SourceFile>
44
+ </TestClientOverrides>
45
+ </Output>,
46
+ ).toRenderTo(
47
+ d`
48
+ export interface Foo {
49
+ knownProp: string;
50
+ }
51
+ export function foo(): unknown {}
52
+ `,
53
+ );
54
+ });
55
+
56
+ function TestClientOverrides(props: { children?: Children }) {
57
+ const overrides = Experimental_ComponentOverridesConfig().forTypeKind("Model", {
58
+ reference: (props) => {
59
+ if (props.type.name === "Foo") {
60
+ return "unknown";
61
+ } else {
62
+ return props.default;
63
+ }
64
+ },
65
+ });
66
+ return (
67
+ <Experimental_ComponentOverrides overrides={overrides}>
68
+ {props.children}
69
+ </Experimental_ComponentOverrides>
70
+ );
71
+ }
@@ -4,18 +4,9 @@ import {
4
4
  createTestWrapper,
5
5
  expectDiagnosticEmpty,
6
6
  } from "@typespec/compiler/testing";
7
- import { HttpTestLibrary } from "@typespec/http/testing";
8
7
 
9
- export async function createTypespecCliTestHost(
10
- options: { libraries: "Http"[] } = { libraries: [] },
11
- ) {
12
- const libraries = [];
13
- if (options.libraries.includes("Http")) {
14
- libraries.push(HttpTestLibrary);
15
- }
16
- return createTestHost({
17
- libraries,
18
- });
8
+ export async function createTypespecCliTestHost() {
9
+ return createTestHost({});
19
10
  }
20
11
 
21
12
  export async function createEmitterFrameworkTestRunner(options: { autoUsings?: string[] } = {}) {
@@ -25,11 +16,8 @@ export async function createEmitterFrameworkTestRunner(options: { autoUsings?: s
25
16
  });
26
17
  }
27
18
 
28
- export async function getProgram(
29
- code: string,
30
- options: { libraries: "Http"[] } = { libraries: [] },
31
- ): Promise<Program> {
32
- const host = await createTypespecCliTestHost(options);
19
+ export async function getProgram(code: string): Promise<Program> {
20
+ const host = await createTypespecCliTestHost();
33
21
  const wrapper = createTestWrapper(host, {
34
22
  compilerOptions: {
35
23
  noEmit: true,