Giter Club home page Giter Club logo

cadl's Introduction

TypeSpec

Official Docs | Try TypeSpec Online | Getting Started | Language Overview

TypeSpec is a language for defining cloud service APIs and shapes. TypeSpec is a highly extensible language with primitives that can describe API shapes common among REST, OpenAPI, gRPC, and other protocols.

TypeSpec is excellent for generating many different API description formats, client and service code, documentation, and many other assets. All this while keeping your TypeSpec definition as a single source of truth.

Using TypeSpec, you can create reusable patterns for all aspects of an API and package those reusable patterns into libraries. These patterns establish "guardrails" for API designers and makes it easier to follow best practices than to deviate from them. TypeSpec also has a rich linter framework with the ability to flag anti-patterns as well as an emitter framework that lets you control of the output to ensure it follows the patterns you want.

npm install -g @typespec/compiler

Tools

The TypeSpec VS Code extension can be installed from the VS Code marketplace or directly on the command line:

tsp code install

The TypeSpec VS Extension can be installed from the VS Marketplace or directly on the command line:

tsp vs install

TypeSpec to OpenAPI 3.0 Example

This example uses the @typespec/http, @typespec/rest, and @typespec/openapi3 libraries to define a basic REST service and generate an OpenAPI 3.0 document from it.

Run the following command and select "Generic REST API":

tsp init

Hit enter a few times to confirm the defaults.

Copy the contents below into your main.tsp:

import "@typespec/http";
import "@typespec/rest";
import "@typespec/openapi3";

using TypeSpec.Http;
using TypeSpec.Rest;

/** This is a pet store service. */
@service({
  title: "Pet Store Service",
})
@server("https://example.com", "The service endpoint")
namespace PetStore;

@route("/pets")
interface Pets {
  list(): Pet[];
}

model Pet {
  @minLength(100)
  name: string;

  @minValue(0)
  @maxValue(100)
  age: int32;

  kind: "dog" | "cat" | "fish";
}

Install the dependencies of main.tsp:

tsp install

Compile it to OpenAPI 3.0:

tsp compile main.tsp --emit @typespec/openapi3

You can find the emitted OpenAPI output in ./tsp-output/openapi.json.

Advanced Scenarios

Installing nightly version

On every commit to the main branch, packages with changes are automatically published to npm with the @next tag. The packages section shows which version corresponds to the next tag for each package.

To use a nightly version of the packages, go over each one of the packages in the package.json file and update it to either the latest published @next version or @latest, whichever is the newest. You can also use the tag latest or next instead of an explicit version.

After updating the package.json file you can run npm update --force. Force is required as there might be some incompatible version requirement.

Example

// Stable setup
"dependencies": {
  "@typespec/compiler": "~0.30.0",
  "@typespec/http": "~0.14.0",
  "@typespec/rest": "~0.14.0",
  "@typespec/openapi": "~0.9.0",
}

// Consume next version
// In this example: compiler and openapi have changes but rest library has none
"dependencies": {
  "@typespec/compiler": "~0.31.0-dev.5",
  "@typespec/http": "~0.14.0",
  "@typespec/rest": "~0.14.0", // No changes to @typespec/rest library so need to stay the latest.
  "@typespec/openapi": "~0.10.0-dev.2",
}

Packages

Name Changelog Latest Next
Core functionality
@typespec/compiler Changelog
TypeSpec Libraries
@typespec/http Changelog
@typespec/rest Changelog
@typespec/openapi Changelog
@typespec/openapi3 Changelog
@typespec/versioning Changelog
TypeSpec Tools
@typespec/prettier-plugin-typespec Changelog
typespec-vs Changelog
typespec-vscode Changelog
tmlanguage-generator Changelog

@next version of the package are the latest versions available on the main branch.

cadl's People

Contributors

abatishchev avatar allenjzhang avatar archerzz avatar bterlson avatar connorjs avatar daviwil avatar dependabot[bot] avatar dtuyishime avatar fearthecowboy avatar github-actions[bot] avatar hallipr avatar jamesc avatar jg1255 avatar jianyexi avatar johanste avatar leni-msft avatar lmazuel avatar lonyehan avatar lukaszkokot avatar m-nash avatar mario-guerra avatar markcowl avatar microsoftopensource avatar mikeharder avatar mikekistler avatar nguerrera avatar petermarcu avatar timotheeguerin avatar tjprescott avatar witemple-msft avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

cadl's Issues

Can't emit both description and summary to OpenAPI

OpenAPI 2 and 3 have distinct summary and description fields, but we only have one @doc so there's no way to use both. When something takes a summary and description, we seem to use @doc as summary. And when it only takes a description we use @doc as description.

Completion improvements

  • Add competition for keywords
  • Map kind: CompletionItemKind to cadl types which will give icons to the completition
    Function type:
    image
    Interface type
    image

Invalid use of template show wrong error line

When passing tempalte args to a non templated type it show the error where the model is defined not used.

Repro

import "@cadl-lang/rest";

model Foo extends Cadl.Http.CreatedResponse<SearchIndex> {

}
C:\dev\azsdk\cadl-azure\core\packages\rest\lib\http.cadl:25:1 - error invalid-template-args: Can't pass template arguments to non-templated type

Convert samples to unit tests where appropriate

Some of our "samples" pre-date the compilation unit test harness we have now. And they're not really samples that someone would want to emulate, more like edge cases that we can't regress. One example is the 'recursive' sample. We should go through the samples and convert those that would be better as unit tests to unit tests.

  • recursive.cadl #35

Add support for enum default

model A {
  optionalEnum?: OptionalEnum = OptionalEnum.foo;
}

enum OptionalEnum {
  foo = "foo",
  bar,
}

See PR for initial implementation and issues #128

Add support for default template values

When trying to standardize on operations for a service, you frequently want to have a overridable default behavior. Consider an interface:

interface Operations<Resource, Error> {
    create(name:str, @body properties: Resource): Resource | Error
}

...but you also have a preferred (standard) error contract model that you want people to use in the vast majority of cases. While you can now specialize the template:

model StandardError { ... };

interface OperationsWithStandardError<Resource> mixes Operations<Resource, StandardError> {
}

you start running into an explosion of specializations as soon as you have more than one template argument that you want to default (e.g. standard filter parameters for list operations, client driven pagination parameters etc.).

// Library has models for default + alternate schemes for pagination
model TopSkip {
    @query top?: int;
    @query skip?: int;
}

model SkipToken {
    @header skipToken?: str;
}

// My service definition
interface AzureOperations<Resource, Error=StandardError, ClientDrivenPagination=TopSkip, CorrelationIds=ClientRequestId> {
  ...
}

// My service uses skipToken headers rather than top/skip query parameters
interface MyServiceOperations<Resource> mixes AzureOperations<ClientDrivenPagination=SkipToken> {}

CADL should be more opiniated on duplicated paths created by alternative syntax

I can compile this with no problem, though they all point to the same path:

@route("/pets")
namespace Pets {
  @doc("Operation with no decorator at all")
  op read(@path petId: int32): Pet;

  @doc("Operation with path in the decorator")
  @get("{petId}") op read2(@path petId: int32): Pet;

  @doc("Operation with no path in the decorator")
  @get op read3(@path petId: int32): Pet;
}

And the Swagger emitter will just keep the last one:

  "paths": {
    "/pets/{petId}": {
      "get": {
        "operationId": "Pets_read3",
        "summary": "Operation with no path in the decorator",
        "parameters": [
          {
            "name": "petId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No content"
          }
        }
      }
    }
  }

I believe CADL should be able to validate that we are defining several times the same operations on the same path.

Should we allow multiple path segments or `@key` properties in a model definition?

This came up as part of #110

Currently, multiple path segments designated on a model is disallowed. Is there a need to allow multiple path segments for a key:

  • For composite keys (i.e. when there are multiple keys, but no parent resource)
    • possible example: Compute VM Gallery
    • How do we express ordering in the path segments without a route string (for autoroute)?
  • If there are alternate paths to accessing the resource
    • this is a common pattern for ODATA APIs

Additionally, should we separate '@key' from path segments, and should we allow multiple `@key' properties in a model

  • This comes up in arrays of complex types. The 'id' of a particular instance may be made up of multiple properties (e.g. firstName, lastName)
    • should we allow this
    • Is there any important ordering in keys (last name, first name, for example) that we want to preserve?

Formatter: Quotes around identifiers

Quotes around property names are allowed but looks bad if not needed.
Should do the same as prettier does with js/ts which is only keep quotes if it is needed(Without the quote it isn't a valid identifier. E.g. api-version)

All non-default status codes without `@doc` on Response type are described as "successful"

Here's an API returning 404.

import "@cadl-lang/rest";
import "@cadl-lang/openapi3";

using Cadl.Http;

@route("/example")
namespace Example {
  op get(): { @header statusCode: 404; };
}

Here is the output. We describe this as "a successful response" even though it is not really. Should we have default descriptions based on the numeric range of the response code?

{
  "openapi": "3.0.0",
  "info": {
    "title": "(title)",
    "version": "0000-00-00"
  },
  "tags": [],
  "paths": {
    "/example/get": {
      "get": {
        "operationId": "Example_get",
        "parameters": [],
        "responses": {
          "404": {
            "description": "A successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {},
                  "x-cadl-name": "(anonymous model)"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {}
}

Formatter: Format enum members with decorator on fields

When an enum has decorator it removes new lines between entries which makes it look very busy and harder to read.
image


@doc("Defines the data type of a field in a search index.")
enum SearchFieldDataType {
  @doc("Indicates that a field contains a string.")
  String: "Edm.String",
  @doc("Indicates that a field contains a 32-bit signed integer.")
  Int32: "Edm.Int32",
  @doc("Indicates that a field contains a 64-bit signed integer.")
  Int64: "Edm.Int64",
  @doc("Indicates that a field contains an IEEE double-precision floating point number.")
  Double: "Edm.Double",
  @doc("Indicates that a field contains a Boolean value (true or false).")
  Boolean: "Edm.Boolean",
  @doc("Indicates that a field contains a date/time value, including timezone information.")
  DateTimeOffset: "Edm.DateTimeOffset",
  @doc("Indicates that a field contains a geo-location in terms of longitude and latitude.")
  GeographyPoint: "Edm.GeographyPoint",
  @doc("Indicates that a field contains one or more complex objects that in turn have sub-fields of other types.")
  ComplexType: "Edm.ComplexType",
}

Should either:

  • Use the same logic as model members(Put space betweeen decorator and above property)
  • Use same logic as namespace. Keep at least one new line if the user placed one.

Makes more sense to go for 1. IMO

Cadl developer doc comments

Certain things in Cadl libraries exist to help the Cadl developer write a spec and their documentation should be shown in the IDE, but should not bleed through emitters to the end user. One example is #126 and I believe the various resource operation mixin interfaces are like this too.

We need a way to distinguish these docs from @doc. We could make a different decorator or use a jsdoc style for instead for these.

EDIT Proposal: https://gist.github.com/nguerrera/01158db039e103dd37201c66978ce10b

Represent duration

One format autorest supported for string schemas was duration.
We have plainTime, plainDate and zonedDatetime but lacking model to represent duration.

One of the schemas in the body-complex sample is using it.

Comment in empty model format outside

model Foo {
  // Some comment
} 

gets formatted to

model Foo {
  // Some comment
} 

probably needs to check before formatting model to be empty if it contains a comment

Define streaming APIs(Server side events, log stream, etc.)

Extracted from https://github.com/Azure/cadl-azure/issues/886

Scenarios to think about:

Supported Scenario Content-Types OpenAPI equivalent
โœ”๏ธ raw text file / raw text return text/plain โœ”๏ธ
โœ”๏ธ file download application/octet-stream, image/png, video/mp4 โœ”๏ธ
โŒ Server side events text/event-stream โŒ OpenAPI#396
โŒ log streaming application/octet-stream โŒ
โŒ json log streaming application/stream+json โŒ

Current proposal https://gist.github.com/timotheeguerin/39ba871ab9d13832cc6227e680df2096

OpenAPI emitters can't handle template pattern with recursion

Compile this:

import "@cadl-lang/openapi3";
import "@cadl-lang/rest";

using Cadl.Http;

model ErrorTemplate<T> {
  @doc("Error code.") code: T;
  innererror?: InnerError;
}

model Error is ErrorTemplate<ErrorCode> {}
model InnerError is ErrorTemplate<InnerErrorCode> {}

enum ErrorCode {
  A,
  B,
  C
}

enum InnerErrorCode {
  C,
  D,
  E
}

@route("/")
namespace N {
  op M(): Error;
}

Get this:

TypeError: Cannot set properties of undefined (setting 'description')
    at getSchemaForModel (file:///C:/Temp/aqe/node_modules/@cadl-lang/openapi3/dist/src/openapi.js:811:58)
    at getSchemaForType (file:///C:/Temp/aqe/node_modules/@cadl-lang/openapi3/dist/src/openapi.js:661:20)
    at emitReferences (file:///C:/Temp/aqe/node_modules/@cadl-lang/openapi3/dist/src/openapi.js:625:35)
    at Object.emitOpenAPI (file:///C:/Temp/aqe/node_modules/@cadl-lang/openapi3/dist/src/openapi.js:157:13)
    at $onBuild (file:///C:/Temp/aqe/node_modules/@cadl-lang/openapi3/dist/src/openapi.js:11:19)
    at createProgram (file:///C:/Temp/aqe/node_modules/@cadl-lang/compiler/dist/core/program.js:60:19)
    at async compile (file:///C:/Temp/aqe/node_modules/@cadl-lang/compiler/dist/core/program.js:475:12)
    at async Object.handler (file:///C:/Temp/aqe/node_modules/@cadl-lang/compiler/dist/core/cli.js:67:25)

If you remove the `@doc("Error code") comment, it doesn't crash, but still gives this:

main.cadl:6:21 - error @cadl-lang/openapi3/invalid-schema: Couldn't get schema for type TemplateParameter

The behavior in both cases is the same for cadl-autorest as cadl-lang/openapi3 so we should fix both.

Experience problems with collisions between namespaces

Consider this:

using A;
using B;

namespace A {
  model M {} // error here
}

namespace B {
  model M {} // and here
}

model Foo {
  m: M; 
}
C:\t\main.cadl:5:3 - error duplicate-symbol: Duplicate name: "M"
C:\t\main.cadl:9:3 - error duplicate-symbol: Duplicate name: "M"

This is misleading because M is not "duplicated" until you use both namespaces. It also means you can't have using A and using B together even when you never reference the colliding names or always fully qualify them.

Now look at morally equivalent C#, where I would argue the experience is much better. I think we should make things work this way.

using A;
using B;

namespace A {
  class M {}
}

namespace B {
  class M {}
}

class Foo {
  M m; // error here
}
C:\t\Program.cs(13,3,13,4): error CS0104: 'M' is an ambiguous reference between 'A.M' and 'B.M'

Add documentation to `@doc` and other documentation components that they could contain markdown or other formatting

Rich text formatting in descriptions/documentation

Documentation for APIs often involve more than just raw text. Common reasons to use rich text formatting include rendering of tables or embedding links into the generated reference documentation.

For an example, see the APIM List By Tags endpoint which illustrates the attempt to use (valid) openapi descriptions that contains a table in the API documentation as well as the issue with tools treating description fields as plain text (broken rendering).

OpenAPI support for rich text

OpenAPI allows for rich text formatting in description fields using CommonMark. As evident from the example above, there are gaps in our toolset with regards to how rich text is handled.

Possible solution

  • Only support CommonMark for input.
  • Add new @richDoc decorator for rich documentation that takes a format parameter. The only supported value (for now) is CommonMark.
@richDoc(
"""
|One|Two|
|-|-|
|1|2|
|3|4|
""", "CommonMark")
model ModelWithTableDocs {};

Alternate solution

Change the @doc decorator so that it accepts CommonMark instead of raw text. For the most part, that is an extension to its current decorator definition (in most cases, you don't have accidental markup in the raw text), but it adds complexity to emitters since they have to sniff the format/convert to something they can manage or risk broken rendering as shown above.

Challenges/questions:

  • There are many rich language definitions *in adition to CommonMark), as well as different dialects within a dialect. Is it enough to support just CommonMark?
  • Client and service library code emitters want to emit descriptions as docstring/comments in generated code. Some langauges (e.g. Python) have idiomatic formats for rich text (in the case of Python, reStructuredText) but most languages expect plain text in their descriptions. Do we expect multiple formats in the specification or do we provide converters?

Add basic end-to-end test to make sure package resolution works in real project

In this PR #157 I broke cadl compile . multiple times(with different issues) without any tests catching it. I think this is due to all our tests using the local linked library. The result of this can be quite bad as we'd release a completely unusable version of the compiler without noticing.

Proposal:

  1. Package all the packages.
  2. Install @cadl-lang/compiler package as global
  3. Test 1:
    • Run cadl compile . on basic main.cadl referencing latest published version of compiler and libraries
    • Run cadl compile . on basic main.cadl referencing the packaged version from step 1.

[OpenAPI 3] Can't return headers with no body, can't return no body with status code != 204

As soon as you have any headers, even the pseudo-header for the status code, the response model becomes a schema for content in the body. If the response model has only headers, there should be no content.

The only way I can find to have no content on the response is to have no properties at all in the response model.

@route("/repro")
namespace Repro {
  op create(@body body: string): {};
}

This generates:

{
 "paths": {
    "/repro": {
      "post": {
        "operationId": "Repro_create",
        "parameters": [],
        "responses": {
          "204": {
            "description": "No content"
          }
        }
      }
    }
  }

But then change it to this:

@route("/repro")
namespace Repro {
  op create(): AcceptedResponse;
}

And get this:

{
  "paths": {
    "/repro": {
      "post": {
        "operationId": "Repro_create",
        "parameters": [],
        "responses": {
          "202": {
            "description": "The request has been received but not yet acted upon.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Cadl.Http.AcceptedResponse"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Cadl.Http.AcceptedResponse": {
        "type": "object",
        "properties": {},
        "description": "The request has been received but not yet acted upon."
      }
    }
  }
}

AcceptedResponse is defined as follows.

model AcceptedResponse {
  @header statusCode: 202;
}

The problem seems to be around here:

https://github.com/microsoft/cadl/blob/34ff2a96445a8f60314799938d223c53e3db3bde/packages/openapi3/src/openapi.ts#L462-L465

We need to ignore header properties (including pseudo-header for status code) when deciding that there's no body. And then we need to make sure to keep the explicit status code if any and not overwrite it with 204 as we would if this part of the code were ignoring headers. Also, looking at the code, I don't think it's right to require the response model to have no base type to have no body. I think we should look at all the properties including inherited properties and see if there are only headers. It's weird to me if if model R extends EmptyOrHeadersOnly {} and model R {...ModelWithOnlyHeaders} /model R is ModelWithOnlyHeaders were different in this respect.

This issue is unique to the OpenAPI 3. We should compare the code with cadl-autorest and if we make any refinements beyond what cadl-autorest currently does, we should align cadl-autorest with those refinements.

Multiple @key on a model crashes the compiler

import "@cadl-lang/rest";
import "@cadl-lang/openapi3";

using Cadl.Rest;
using Cadl.Rest.Resource;

interface Pets mixes ResourceOperations<Pet, {}> {}

model Pet {
  @segment("stores")
  @key
  storeId: int64;

  @segment("pets")
  @key
  id: int64;
}
Unhandled promise rejection!
Internal compiler error!
File issue at https://github.com/microsoft/cadl

Error: More than one key found on model type Pet
    at file:///C:/dev/azsdk/cadl-dogfood/node_modules/@cadl-lang/rest/dist/resource.js:41:23
    at Map.forEach (<anonymous>)
    at getResourceTypeKey (file:///C:/dev/azsdk/cadl-dogfood/node_modules/@cadl-lang/rest/dist/resource.js:38:29)
    at cloneKeyProperties (file:///C:/dev/azsdk/cadl-dogfood/node_modules/@cadl-lang/rest/dist/resource.js:67:25)
    at $copyResourceKeyParameters (file:///C:/dev/azsdk/cadl-dogfood/node_modules/@cadl-lang/rest/dist/resource.js:108:9)
    at applyDecoratorToType (file:///C:/dev/azsdk/cadl-dogfood/node_modules/@cadl-lang/compiler/dist/core/checker.js:1268:13)
    at createType (file:///C:/dev/azsdk/cadl-dogfood/node_modules/@cadl-lang/compiler/dist/core/checker.js:1257:17)
    at checkModelStatement (file:///C:/dev/azsdk/cadl-dogfood/node_modules/@cadl-lang/compiler/dist/core/checker.js:819:13)
    at checkModel (file:///C:/dev/azsdk/cadl-dogfood/node_modules/@cadl-lang/compiler/dist/core/checker.js:762:20)
    at getTypeForNode (file:///C:/dev/azsdk/cadl-dogfood/node_modules/@cadl-lang/compiler/dist/core/checker.js:147:24)

not exactly sure if that's supposed to not be allowed but either way it shouldn't crash

Generic interface cause error in openapi3 emitter

When defining an interface with a template parameter it cause an error

interface Adoptable<TResource> {
  @Cadl.Http.post adpot(
    ...ResourceParameters<TResource>
  ): TResource | PetStoreError;
}
interface Dogs mixes ResourceOperations<Dog, PetStoreError>, Adoptable<Dog> {}
interface Cats mixes ResourceOperations<Cat, PetStoreError>, Adoptable<Cat> {}

model Cat {}
model Dog {}

error:

C:\dev\azsdk\cadl-dogfood\main.cadl:25:23 - error @cadl-lang/openapi3/invalid-schema: Couldn't get schema for type TemplateParameter

This eror doesn't happen if Adoptable is moved to another file and imported

Solution might just be making sure the emitter doesn't pull template interfaces

`using Cadl;` cause aggregate error

Including using Cadl; in the spec cause an aggregate error

AggregateError: Multiple errors. See errors array.
    at computeTargetLocation (file:///C:/dev/azsdk/cadl/packages/compiler/dist/core/diagnostics.js:73:15)
    at logDiagnostics (file:///C:/dev/azsdk/cadl/packages/compiler/dist/core/diagnostics.js:83:29)
    at onCompileFinished (file:///C:/dev/azsdk/cadl/packages/compiler/dist/core/cli.js:152:13)
    at async Object.handler (file:///C:/dev/azsdk/cadl/packages/compiler/dist/core/cli.js:67:25) {
  errors: [
    Error: Error(s) occurred trying to resolve target: [object Object]
        at computeTargetLocation (file:///C:/dev/azsdk/cadl/packages/compiler/dist/core/diagnostics.js:72:33)
        at logDiagnostics (file:///C:/dev/azsdk/cadl/packages/compiler/dist/core/diagnostics.js:83:29)
        at onCompileFinished (file:///C:/dev/azsdk/cadl/packages/compiler/dist/core/cli.js:152:13)
        at async Object.handler (file:///C:/dev/azsdk/cadl/packages/compiler/dist/core/cli.js:67:25),
    AssertionError [ERR_ASSERTION]: Cannot obtain source file of unbound node.
        at new AssertionError (internal/assert/assertion_error.js:456:5)
        at compilerAssert (file:///C:/dev/azsdk/cadl/packages/compiler/dist/core/diagnostics.js:221:19)
        at getSourceLocationOfNode (file:///C:/dev/azsdk/cadl/packages/compiler/dist/core/diagnostics.js:149:5)
        at getSourceLocation (file:///C:/dev/azsdk/cadl/packages/compiler/dist/core/diagnostics.js:135:12)
        at computeTargetLocation (file:///C:/dev/azsdk/cadl/packages/compiler/dist/core/diagnostics.js:64:24)
        at logDiagnostics (file:///C:/dev/azsdk/cadl/packages/compiler/dist/core/diagnostics.js:83:29)
        at onCompileFinished (file:///C:/dev/azsdk/cadl/packages/compiler/dist/core/cli.js:152:13)
        at async Object.handler (file:///C:/dev/azsdk/cadl/packages/compiler/dist/core/cli.js:67:25) {
      generatedMessage: false,
      code: 'ERR_ASSERTION',
      actual: undefined,
      expected: undefined,
      operator: undefined
    }
  ]
}

Formatter improvements

List of things that could be formatted better:

1. Decorator with a single value being very long could be formatted in a single line instead of splitting

@doc("with a very long comment ......")

formats to

@doc(
  "with a very long comment ......"
)

2. Mixes too long line


interface DocumentModels mixes ResourceOperations<ModelSummary, ErrorResponse>, ResourceOperations<ModelSummary, ErrorResponse>, ResourceOperations<ModelSummary, ErrorResponse>, ResourceOperations<ModelSummary, ErrorResponse> {}

Try to format to this?

interface DocumentModels mixes 
    ResourceOperations<ModelSummary, ErrorResponse>, 
    ResourceOperations<ModelSummary, ErrorResponse>, 
    ResourceOperations<ModelSummary, ErrorResponse>, 
    ResourceOperations<ModelSummary, ErrorResponse> {
          
}

3. Interface should keep empty lines between operation

Like namespaces it shouldn't concat all operation together but preserve an empty line if there is 1+ between operation

Passing union of string to @doc crash openapi emitter with circular reference in json

model Foo {
  @doc("foo" | "bar")
  test: string;
}

This happened when using wanting to use quotes but forgetting to escape and it happens to produce a valid Cadl syntax.

Error:

TypeError: Converting circular structure to JSON
    --> starting at object with constructor 'Object'
    |     property 'options' -> object with constructor 'Array'
    |     index 0 -> object with constructor 'Object'
    --- property 'parent' closes the circle
    at JSON.stringify (<anonymous>)
    at Object.emitOpenAPI (file:///C:/dev/azsdk/cadl-azure/packages/cadl-autorest/dist/src/openapi.js:172:100)
    at $onBuild (file:///C:/dev/azsdk/cadl-azure/packages/cadl-autorest/dist/src/openapi.js:13:19)
    at async createProgram (file:///C:/dev/azsdk/cadl-azure/core/packages/compiler/dist/core/program.js:60:13)
    at async compile (file:///C:/dev/azsdk/cadl-azure/core/packages/compiler/dist/core/program.js:479:12)
    at async Object.handler (file:///C:/dev/azsdk/cadl-azure/core/packages/compiler/dist/core/cli.js:67:25)

The problem with @doc specifically might just be to verify the value passed is a string and nothing else.

union statement should support unnamed unions

The union statement was introduced to support "named unions" (a la Rust and Swift). But we also allow union to define regular "unnamed" unions by simply omitting the variant names, e.g.:

union Pet { Cat, Dog }

The compiler currently complains about this syntax:

error token-expected: ':' expected.

Errors not shown in IDE when document is on disk (not "untitled")

Single quotes are not valid in Cadl but they are not flagged in the VSCode extension.

Simple recreate:

import "@cadl-lang/rest";
import "@cadl-lang/openapi3";

using Cadl.Http;

model Pet {
  name: string;
}

model CreatedResponse {
  @statusCode code: '201';
}

@route("/Pets")
namespace Pets {
  op create(): CreatedResponse & Pet;
}

This fails to compile with:

Diagnostics were reported during compilation:

/Users/mikekistler/Projects/Microsoft/cadl/packages/samples/scratch/bug.cadl:11:21 - error invalid-character: Invalid character.
/Users/mikekistler/Projects/Microsoft/cadl/packages/samples/scratch/bug.cadl:11:21 - error token-expected: Expression expected.
/Users/mikekistler/Projects/Microsoft/cadl/packages/samples/scratch/bug.cadl:11:25 - error invalid-character: Invalid character.
/Users/mikekistler/Projects/Microsoft/cadl/packages/samples/scratch/bug.cadl:11:22 - error token-expected: Statement expected.
/Users/mikekistler/Projects/Microsoft/cadl/packages/samples/scratch/bug.cadl:12:1 - error token-expected: Statement expected.

But no warnings are shown in VSCode.

The code compiles cleanly when the single quotes are changed to double quotes.

Simplify specifying cadl-server location in VS Code settings

Today you have to specify a path to a cadl-server(.cmd) executable. This is hard for two reasons:

  1. Even if you have that, it's deep and hard to find
  2. If you want to run against a local build of the package, as we do, you don't even have that.

Our workaround for (2) to use the .bin/cadl-server in packages/samples that consumes packages/compiler.

It would be better if you could just specify the package path and it worked.

Add a contributing.md

Should have some base instructions around building, running tests, and creating PRs for OSS contributors.

Properties disappear from OpenAPI in certain template patterns with recursion

Compile this:

import "@cadl-lang/openapi3";
import "@cadl-lang/rest";

using Cadl.Http;

model ErrorBase {
  innererror: InnerError;
}

model Error is ErrorBase {
  code: ErrorCode; 
}

model InnerError is ErrorBase {
  code: InnerErrorCode; 
}

enum ErrorCode {
  A,
  B,
  C
}

enum InnerErrorCode {
  C,
  D,
  E
}

@route("/")
namespace N {
  op M(): Error;
}

Get this:

{
  "schemas": {
    "Error": {
      "type": "object",
      "properties": {
        "innererror": {
          "$ref": "#/components/schemas/InnerError"
        },
        "code": {
          "$ref": "#/components/schemas/ErrorCode"
        }
      },
      "required": [
        "innererror",
        "code"
      ]
    },
    "InnerError": {
      "type": "object",
      "properties": {
        "code": {
          "$ref": "#/components/schemas/InnerErrorCode"
        }
      },
      "required": [
        "code"
      ]
    },
    "ErrorCode": {
      "type": "string",
      "enum": [
        "A",
        "B",
        "C"
      ]
    },
    "InnerErrorCode": {
      "type": "string",
      "enum": [
        "C",
        "D",
        "E"
      ]
    }
  }
}

Notice that InnerError model is missing the innererror property. The same thing happens with cadl-autorest. This might be an issue in the compiler and not the emitter and it might be related to #133

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.