Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DO NOT MERGE] Emitter Framework #4480

Draft
wants to merge 148 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 102 commits
Commits
Show all changes
148 commits
Select commit Hold shift + click to select a range
24325fe
Initial setup
bterlson Jul 23, 2024
a9d3e0a
Port mutator
joheredi Jul 23, 2024
8aae4b5
Add basic support for function-declaration
joheredi Jul 23, 2024
a35098d
Test emitter works
bterlson Jul 23, 2024
c16789e
fix package lock
joheredi Jul 23, 2024
1143cbc
Support Union
joheredi Jul 24, 2024
6e5f7bb
Beef up sample
bterlson Jul 23, 2024
0ad093c
Sample improvements, bug fixes
bterlson Jul 24, 2024
ac54d1d
Support model interface
joheredi Jul 24, 2024
1a1b386
fix jsx imports
joheredi Jul 24, 2024
dafc751
Fix conflict
joheredi Jul 24, 2024
2de2aa8
Adopt interface
bterlson Jul 24, 2024
ef8640a
Begin port of CLI emitter sample
bterlson Jul 30, 2024
670f228
Fix some bugs
bterlson Jul 30, 2024
b3d8e76
Fix some bugs
bterlson Jul 30, 2024
3602092
finish porting CLI emitter
bterlson Aug 2, 2024
dd854e3
cli emitter now works
bterlson Aug 7, 2024
a2c2650
It works
bterlson Aug 14, 2024
d8d3241
Scaffold http-client-javascript
joheredi Aug 19, 2024
573774a
Try to rename
joheredi Aug 19, 2024
dab0008
Support literate tests
joheredi Aug 19, 2024
cdac11b
Update test
joheredi Aug 19, 2024
9f220ad
Implement typekits
bterlson Aug 20, 2024
c8113dc
Support emitting array and record
joheredi Aug 20, 2024
1313d5a
Support inline models
joheredi Aug 20, 2024
28dbb1f
update test
joheredi Aug 20, 2024
d0971fb
Update alloy dep
joheredi Aug 20, 2024
5c82f34
Filter out STD and anonymous types.
joheredi Aug 20, 2024
c7d4569
Fix enum component
joheredi Aug 20, 2024
fbe2f11
update sample
joheredi Aug 20, 2024
1a4c319
hosed by circular refs
bterlson Aug 21, 2024
267ffa9
stabs in the dark
bterlson Aug 21, 2024
405192f
fix circular refs
bterlson Aug 22, 2024
8fad521
implement enums
bterlson Aug 22, 2024
c2d6519
use const
bterlson Aug 22, 2024
9eb9288
Merge branch 'main' into alloy
bterlson Aug 22, 2024
0580548
Enable enum in TypeDeclaration
joheredi Aug 22, 2024
a09301d
Support basic and model serializers
joheredi Aug 22, 2024
4fb3a50
Fix some format
joheredi Aug 22, 2024
1735401
Add basic model deserializer
joheredi Aug 23, 2024
7479795
Support utcDateTime
joheredi Aug 23, 2024
cf3495a
update imports and deps
joheredi Aug 23, 2024
9c199f4
support date encoding
joheredi Aug 23, 2024
bd9037e
Implement a few new typekits
bterlson Aug 23, 2024
b536b3e
Implement http typekits
bterlson Aug 23, 2024
3745030
Implement more typekit methods
bterlson Aug 24, 2024
1e886b3
Support utcDateTimeScalars
joheredi Aug 23, 2024
bce5879
fix missing import
joheredi Aug 24, 2024
e1bd386
remove only
joheredi Aug 24, 2024
1704166
Support Record and Array Serializers
joheredi Aug 26, 2024
80abd43
Organize output in folders
joheredi Aug 27, 2024
42b6c11
support basic client context
joheredi Aug 27, 2024
62ed94a
Collect types from interfaces
joheredi Aug 27, 2024
54f8dad
support appending or perpending additional parameters to operation.pa…
joheredi Aug 27, 2024
3238039
Generate http operations
joheredi Aug 28, 2024
b362495
add simple test for httpOperation typekit
joheredi Sep 3, 2024
1fa79c1
Low cost getPlausibleName
joheredi Sep 3, 2024
c2aef71
export model typekit and enhance EF test host
joheredi Sep 3, 2024
d99a487
Add type transform to convert models from client to wire and back
joheredi Sep 3, 2024
22f11e1
Cleanup serializer deserializers
joheredi Sep 4, 2024
0280f18
Add HttpRequest and HttpRequestOptions components
joheredi Sep 5, 2024
13fcd6e
Add httpResponse typekit
joheredi Sep 9, 2024
23853dc
update exports
joheredi Sep 9, 2024
aea55dc
Add getEffectiveModel and getResponses typekits
joheredi Sep 10, 2024
04a331e
Typescript Http Request and Response
joheredi Sep 10, 2024
3233a1e
Update http request components
joheredi Sep 11, 2024
3817643
Add union isExpresion
joheredi Sep 11, 2024
61fe412
Update graph traversal
joheredi Sep 11, 2024
7642e94
Update dependency and fix directories
joheredi Sep 12, 2024
93d4d2a
Move plausible name to type and handle template instances
joheredi Sep 12, 2024
8798f2b
Improve name resolution handling in ef/typescript
joheredi Sep 12, 2024
f628b97
cleanup ts emitter components
joheredi Sep 12, 2024
bfa69a9
Add end to end scenario test
joheredi Sep 12, 2024
b379237
Add Scenario Test Harness
joheredi Sep 13, 2024
d8d535d
Support tags for other languages
joheredi Sep 13, 2024
7be5c3c
Merge pull request #6 from joheredi/alloy-test-harness
joheredi Sep 13, 2024
49bbe3b
Implement getParameters typekit
joheredi Sep 14, 2024
98a9639
Update body handling logic
joheredi Sep 16, 2024
daa06c1
Initial support for discriminated unions
joheredi Sep 16, 2024
da117c4
Generate operations per namespace
joheredi Sep 17, 2024
c94396e
update deps and export barrell
joheredi Sep 17, 2024
c9746d4
Fixes to fetch wrapper
joheredi Sep 17, 2024
e490358
Only one barrell file
joheredi Sep 17, 2024
721da83
Account for bodyRoot
joheredi Sep 17, 2024
d24bd09
Enable alloy prettier pluggin and format js emitter
joheredi Sep 17, 2024
d6f05fc
format
joheredi Sep 17, 2024
5946512
Fix exports
joheredi Sep 18, 2024
18718aa
Handle error and bodyless responses
joheredi Sep 18, 2024
71c8c75
Support options bag and optionality checks
joheredi Sep 18, 2024
8359cde
Refactor ClientContext
joheredi Sep 19, 2024
9c350d9
Formatting
joheredi Sep 19, 2024
ef8741c
Merge remote-tracking branch 'upstream/main' into alloy
joheredi Sep 19, 2024
e37c6d1
Fix breaking changes from TS update
joheredi Sep 19, 2024
0ab6c50
Pull alloy from npmjs
joheredi Sep 20, 2024
a350bf4
Merge remote-tracking branch 'upstream/main' into alloy
joheredi Sep 20, 2024
b3e5fa7
Add Classical Clients
joheredi Sep 23, 2024
01685af
Fix tests and generate clientlet for interfaces
joheredi Sep 23, 2024
f4b0f69
Update alloy deps
joheredi Sep 23, 2024
49ebcb0
Merge remote-tracking branch 'upstream/main' into alloy
joheredi Sep 23, 2024
62e3575
Merge main and move typekits to experimental
joheredi Sep 24, 2024
7e25e03
add todo and petstore output
joheredi Sep 24, 2024
05f18e7
Format after build
joheredi Sep 24, 2024
df60e23
can compile after removing html-program-viewer
Oct 22, 2024
21b93f9
initial commit with ClientLibrary typekit
Oct 24, 2024
f20526b
temp commit
Oct 25, 2024
afed6c6
check out client.tsx changes
Oct 28, 2024
facd479
get model typekit to work
Oct 28, 2024
efb930c
Merge pull request #8 from iscai-msft/clientLibraryTypeKit
iscai-msft Oct 28, 2024
1b33e34
additional typekit sketching
Oct 28, 2024
c6d28c3
Add builtin kit
joheredi Oct 28, 2024
4eb4b23
Add tests
joheredi Oct 28, 2024
f3076ed
working through model and modelproperty kits
Oct 28, 2024
1788e2d
Merge branch 'alloy' of https://github.com/bterlson/typespec into alloy
Oct 28, 2024
5a4c25f
Fix bultin types
joheredi Oct 29, 2024
65e5116
Create ClientLibrary packages for 3p and Azure
joheredi Oct 29, 2024
44665b8
Merge pull request #9 from joheredi/client-library-packages
iscai-msft Oct 29, 2024
48e2643
Format and Test for client-library
joheredi Oct 29, 2024
6d1fda4
before trying nested approach
Oct 30, 2024
fa726a7
Merge branch 'alloy' of https://github.com/bterlson/typespec into alloy
Oct 30, 2024
e955615
Merge branch 'main' into alloy
bterlson Oct 31, 2024
435047f
Add some missing files
bterlson Oct 31, 2024
8701d69
adding tests, stuck on credential
Oct 31, 2024
19b1285
Merge branch 'alloy' of https://github.com/bterlson/typespec into alloy
Oct 31, 2024
4163016
Move Client Library Typekits out of JS emitter
joheredi Oct 31, 2024
f07f5f7
Merge pull request #12 from joheredi/move-client-library
iscai-msft Nov 1, 2024
afe9521
Add ClientLibraryContext
joheredi Nov 1, 2024
2626a68
Fallback when no service defined
joheredi Nov 1, 2024
1a182a2
return credential parameter with string literal type
Nov 4, 2024
d8e286f
format and add usage, access, and name to typekits
Nov 4, 2024
00ec0a1
add accessors for return types onto sdk operation kit
Nov 5, 2024
c99612c
switch to getParams and isPubliclyInitializable
Nov 6, 2024
fddddeb
list clients also takes interface
Nov 6, 2024
c7a4b1c
have getName take a client
Nov 6, 2024
5f59d55
fix getname for client
Nov 6, 2024
0f6b124
have list clients take in namespace or client
Nov 6, 2024
598e0f3
move listSubNamespaces onto listNamespaces
Nov 6, 2024
4a58358
add tests for subclients
Nov 6, 2024
3212e9e
format
Nov 6, 2024
819b157
add tests for getting subclients
Nov 6, 2024
12bd772
switch to clients having a list of constructors
Nov 7, 2024
de30f06
add constructors to client
Nov 8, 2024
2cc861d
fix multiple servers test
Nov 8, 2024
2a21cd5
add properties to the list
Nov 11, 2024
30f7fb5
Merge branch 'main' into alloy
bterlson Nov 12, 2024
e9329b9
Fix circular references
bterlson Nov 13, 2024
c4d34bf
clean up is on client code in model property typekit
Nov 18, 2024
2429714
temporarily use name sort for finding params
Nov 18, 2024
2de2da7
add credential tests
Nov 19, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -63,5 +63,9 @@ grammars/
# auto generated code model files
packages/http-client-csharp/generator/TestProjects/**/tspCodeModel.json

# Alloy components
packages/emitter-framework/**/*.tsx
packages/emitter-sample/**/*.tsx
packages/efnext-cli-sketch/**/*.tsx
# auto generated api view properties files
packages/http-client-java/generator/http-client-generator-test/src/main/**/*.json
15 changes: 14 additions & 1 deletion .prettierrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,27 @@
"tabWidth": 2,
"plugins": [
"./packages/prettier-plugin-typespec/dist/index.js",
"./node_modules/prettier-plugin-organize-imports/index.js"
"./node_modules/prettier-plugin-organize-imports/index.js",
"@alloy-js/prettier-plugin-alloy"
],
"overrides": [
{
"files": "*.tsp",
"options": {
"parser": "typespec"
}
},
{
"files": ["packages/http-client-javascript/**/*.tsx"],
"options": {
"parser": "alloy-ts"
}
},
{
"files": ["packages/http-client-javascript/**/*.js"],
"options": {
"parser": "alloy-js"
}
}
]
}
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
"picocolors": "~1.1.0",
"prettier": "~3.3.3",
"prettier-plugin-organize-imports": "~4.0.0",
"@alloy-js/prettier-plugin-alloy": "0.1.0",
"rimraf": "~6.0.1",
"syncpack": "^13.0.0",
"tsx": "^4.19.1",
Expand All @@ -81,7 +82,8 @@
},
"pnpm": {
"overrides": {
"@fluentui/react-theme": "9.1.17"
"@fluentui/react-theme": "9.1.17",
"esbuild": "0.23"
}
}
}
5 changes: 5 additions & 0 deletions packages/compiler/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@
"types": "./dist/src/emitter-framework/index.d.ts",
"default": "./dist/src/emitter-framework/index.js"
},
"./typekit": {
"types": "./dist/src/typekit/index.d.ts",
"default": "./dist/src/typekit/index.js"
},
"./experimental": {
"types": "./dist/src/experimental/index.d.ts",
"default": "./dist/src/experimental/index.js"
Expand Down Expand Up @@ -86,6 +90,7 @@
"lint:fix": "eslint . --fix"
},
"dependencies": {
"@alloy-js/core": "0.2.0",
"@babel/code-frame": "~7.24.7",
"ajv": "~8.17.1",
"change-case": "~5.4.4",
Expand Down
4 changes: 3 additions & 1 deletion packages/compiler/src/core/emitter-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ export interface EmitFileOptions {
export async function emitFile(program: Program, options: EmitFileOptions): Promise<void> {
// ensure path exists
const outputFolder = getDirectoryPath(options.path);
await program.host.mkdirp(outputFolder);
if (outputFolder) {
await program.host.mkdirp(outputFolder);
}
const content =
options.newLine && options.newLine === "crlf"
? options.content.replace(/(\r\n|\n|\r)/gm, "\r\n")
Expand Down
21 changes: 20 additions & 1 deletion packages/compiler/src/core/program.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { OutputDirectory, render } from "@alloy-js/core";
import { EmitterOptions } from "../config/types.js";
import { createAssetEmitter } from "../emitter-framework/asset-emitter.js";
import { setCurrentProgram } from "../experimental/typekit/define-kit.js";
Expand All @@ -8,6 +9,7 @@ import { createBinder } from "./binder.js";
import { Checker, createChecker } from "./checker.js";
import { createSuppressCodeFix } from "./compiler-code-fixes/suppress.codefix.js";
import { compilerAssert } from "./diagnostics.js";
import { emitFile } from "./emitter-utils.js";
import { resolveTypeSpecEntrypoint } from "./entrypoint-resolution.js";
import { ExternalError } from "./external-error.js";
import { getLibraryUrlsLoaded } from "./library.js";
Expand Down Expand Up @@ -569,12 +571,29 @@ export async function compile(
},
};
try {
await emitter.emitFunction(context);
const result = (await emitter.emitFunction(context)) as any;
if (typeof result === "function") {
// assume this is an alloy component
const tree = render(result);
await writeOutputDirectory(tree, context.emitterOutputDir);
}
} catch (error: unknown) {
throw new ExternalError({ kind: "emitter", metadata: emitter.metadata, error });
}
}

async function writeOutputDirectory(dir: OutputDirectory, emitterOutputDir: string) {
for (const sub of dir.contents) {
if (Array.isArray(sub.contents)) {
await writeOutputDirectory(sub as OutputDirectory, emitterOutputDir);
} else {
await emitFile(program, {
content: sub.contents as string,
path: joinPaths(emitterOutputDir, sub.path),
});
}
}
}
async function runValidators() {
runCompilerValidators();
for (const validator of validateCbs) {
Expand Down
6 changes: 5 additions & 1 deletion packages/compiler/src/experimental/typekit/define-kit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,11 @@ export function defineKit<T extends Record<string, any>>(
source: StripGuards<T> & ThisType<TypekitPrototype>,
): void {
for (const [name, fnOrNs] of Object.entries(source)) {
TypekitPrototype[name] = fnOrNs;
let kits = fnOrNs;
if (TypekitPrototype[name] !== undefined) {
kits = { ...TypekitPrototype[name], ...fnOrNs };
}
TypekitPrototype[name] = kits;
}
}

Expand Down
32 changes: 32 additions & 0 deletions packages/compiler/src/experimental/typekit/kits/array.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { isArrayModelType, Model, Type } from "../../../index.js";
import { defineKit } from "../define-kit.js";

export interface ArrayKit {
array: {
/**
* Check if the given `type` is an Array.
*
* @param type The type to check.
*/
is(type: Type): type is Model;
getElementType(type: Model): Type;
};
}

declare module "../define-kit.js" {
interface TypekitPrototype extends ArrayKit {}
}

defineKit<ArrayKit>({
array: {
is(type) {
return type.kind === "Model" && isArrayModelType(this.program, type);
},
getElementType(type) {
if (!this.array.is(type)) {
throw new Error("Type is not an array.");
}
return type.indexer!.value;
},
},
});
70 changes: 70 additions & 0 deletions packages/compiler/src/experimental/typekit/kits/enum-member.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import type { Enum, EnumMember, Type } from "../../../core/types.js";
// eslint-disable-next-line @typescript-eslint/no-unused-vars

import { defineKit } from "../define-kit.js";
import { decoratorApplication, DecoratorArgs } from "../utils.js";

interface EnumMemberDescriptor {
/**
* The name of the enum member.
*/
name: string;
/**
* Decorators to apply to the enum member.
*/
decorators?: DecoratorArgs[];

/**
* The value of the enum member. If not supplied, the value will be the same
* as the name.
*/
value?: string | number;

/**
* The enum that the member belongs to. If not provided here, it is assumed
* that it will be set in `enum.build`.
*/
enum?: Enum;
}

interface EnumMemberKit {
enumMember: {
/**
* Create an enum type. The enum type will be finished (i.e. decorators are
* run).
*/
create(desc: EnumMemberDescriptor): EnumMember;

/**
* Check if `type` is an enum member type.
*
* @param type the type to check.
*/
is(type: Type): type is EnumMember;
};
}

declare module "../define-kit.js" {
interface TypekitPrototype extends EnumMemberKit {}
}

defineKit<EnumMemberKit>({
enumMember: {
create(desc) {
const member: EnumMember = this.program.checker.createType({
kind: "EnumMember",
name: desc.name,
value: desc.value,
decorators: decoratorApplication(desc.decorators),
node: undefined as any,
enum: desc.enum as any, // initialized in enum.build if not provided here
});
this.program.checker.finishType(member);
return member;
},

is(type) {
return type.kind === "EnumMember";
},
},
});
127 changes: 127 additions & 0 deletions packages/compiler/src/experimental/typekit/kits/enum.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import type { Enum, EnumMember, Type, Union } from "../../../core/types.js";
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import { type UnionKit } from "./union.js";

import { createRekeyableMap } from "../../../utils/misc.js";
import { defineKit } from "../define-kit.js";
import { decoratorApplication, DecoratorArgs } from "../utils.js";

interface EnumDescriptor {
/**
* The name of the enum declaration.
*/
name: string;

/**
* Decorators to apply to the enum.
*/
decorators?: DecoratorArgs[];

/**
* The members of the enum. If a member is an object, each property will be
* converted to an EnumMember with the same name and value.
*/
members?: Record<string, string | number> | EnumMember[];
}

interface EnumMemberDescriptor {

Check warning on line 27 in packages/compiler/src/experimental/typekit/kits/enum.ts

View workflow job for this annotation

GitHub Actions / Lint

'EnumMemberDescriptor' is defined but never used. Allowed unused vars must match /^_/u
/**
* The name of the enum member.
*/
name: string;
/**
* Decorators to apply to the enum member.
*/
decorators?: DecoratorArgs[];

/**
* The value of the enum member. If not supplied, the value will be the same
* as the name.
*/
value?: string | number;

/**
* The enum that the member belongs to. If not provided here, it is assumed
* that it will be set in `enum.build`.
*/
enum?: Enum;
}

interface EnumKit {
enum: {
/**
* Build an enum type. The enum type will be finished (i.e. decorators are
* run).
*/
create(desc: EnumDescriptor): Enum;

/**
* Build an equivalent enum from the given union. Union variants which are
* not valid enum members are skipped. You can check if a union is a valid
* enum with {@link UnionKit.union}'s `isEnumValue`.
*/
createFromUnion(type: Union): Enum;

/**
* Check if `type` is an enum type.
*
* @param type the type to check.
*/
is(type: Type): type is Enum;
};
}

declare module "../define-kit.js" {
interface TypekitPrototype extends EnumKit {}
}

defineKit<EnumKit>({
enum: {
create(desc) {
const en: Enum = this.program.checker.createType({
kind: "Enum",
name: desc.name,
decorators: decoratorApplication(desc.decorators),
members: createRekeyableMap(),
node: undefined as any,
});

if (Array.isArray(desc.members)) {
for (const member of desc.members) {
member.enum = en;
en.members.set(member.name, member);
}
} else {
for (const [name, member] of Object.entries(desc.members ?? {})) {
en.members.set(name, this.enumMember.create({ name, value: member, enum: en }));
}
}

this.program.checker.finishType(en);
return en;
},

is(type) {
return type.kind === "Enum";
},

createFromUnion(type) {
if (!type.name) {
throw new Error("Cannot create an enum from an anonymous union.");
}

const enumMembers: EnumMember[] = [];
for (const variant of type.variants.values()) {
if (
(variant.name && typeof variant.name === "symbol") ||
(!this.literal.isString(variant.type) && !this.literal.isNumeric(variant.type))
) {
continue;
}
enumMembers.push(this.enumMember.create({ name: variant.name, value: variant.type.value }));
}

return this.enum.create({ name: type.name, members: enumMembers });
},
},
});
4 changes: 4 additions & 0 deletions packages/compiler/src/experimental/typekit/kits/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
export * from "./array.js";
export * from "./enum-member.js";
export * from "./enum.js";
export * from "./literal.js";
export * from "./model-property.js";
export * from "./model.js";
export * from "./realm.js";
export * from "./record.js";
export * from "./scalar.js";
export * from "./type.js";
export * from "./union-variant.js";
Expand Down
Loading
Loading