Resolve blank line added at the end of embedded code block (#936)

This commit is contained in:
Timothee Guerin 2022-08-29 11:02:20 -07:00 коммит произвёл GitHub
Родитель 057c124720
Коммит 8a0b35d915
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
13 изменённых файлов: 75 добавлений и 97 удалений

Просмотреть файл

@ -144,7 +144,6 @@ namespace Example {
@route("/message")
op getMessage(): string;
}
```
You can compile it to OpenAPI 3.0 by using the following command:

Просмотреть файл

@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@cadl-lang/compiler",
"comment": "Formatter: Cadl doesn't include blank line at the end of embeded markdown codeblock",
"type": "patch"
}
],
"packageName": "@cadl-lang/compiler"
}

Просмотреть файл

@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@cadl-lang/openapi",
"comment": "",
"type": "none"
}
],
"packageName": "@cadl-lang/openapi"
}

Просмотреть файл

@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@cadl-lang/openapi3",
"comment": "",
"type": "none"
}
],
"packageName": "@cadl-lang/openapi3"
}

Просмотреть файл

@ -58,7 +58,6 @@ enum Color {
Blue: "blue",
Green: "green",
}
```
Another is to use the union operation to define the enum values inline, e.g.:
@ -94,7 +93,6 @@ namespace Pets {
op create(@body pet: Pet): Pet; // uses path "/pets"
op read(@path petId: int32): Pet; // uses path "/pets/{petId}"
}
```
## Path Item Object
@ -245,7 +243,6 @@ model Snake {
name: string;
// snakes have no legs
}
```
Cadl also supports single inheritance of models with the `extends` keyword. This construct can be used to produce an `allOf` with a single element (the parent schema) in OpenAPI. For example:
@ -262,7 +259,6 @@ model Cat extends Pet {
model Dog extends Pet {
bark: string;
}
```
Cadl does not current provide a means to produce an `allOf` with more than one element -- these are generally treated as "composition" in code generators and thus better represented in Cadl with the spread operator.
@ -285,7 +281,6 @@ model PetId {
namespace Pets {
op read(...PetId): Pet | Error;
}
```
results in a `$ref` to the named parameter `PetId` in either `parameters` or `components.parameters`.
@ -330,5 +325,4 @@ For example:
namespace Pets {
@extension("x-streaming-operation", true) op read(...PetId): Pet | Error;
}
```

Просмотреть файл

@ -16,14 +16,12 @@ For example, the following used to define a request body of type `string`, but n
```cadl
op create(body: string): void;
```
To get the previous behavior, the parameter now needs to be explicitly marked with `@body`:
```cadl
op create(@body body: string): void;
```
## OkResponse is no longer a template
@ -34,35 +32,30 @@ Since 200 is the default status code for non-empty bodies, you can usually repla
```cadl
op get(id: string): OkResponse<Pet>;
```
Can be:
```cadl
op get(id: string): Pet;
```
In certain situations where the body type is not (necessarily) a model, you will need to use the new `Body<T>` type. For example.
```cadl
op list(): OkResponse<Pet[]>;
```
Can become:
```cadl
op list(): OkResponse & Body<Pet[]>;
```
Since 200 status code is used by default, this could also be:
```cadl
op list(): Pet[];
```
Generic models based on `OkResponse<T>` may also require `Body<T>`. For example:
@ -72,7 +65,6 @@ model MyResponse<T> {
...OkResponse<T>;
@header example: string;
}
```
Since T is not constrainted to be a model, it might be an intrinsic type, an array, or the like, the template should be changed to use `Body<T>`:
@ -83,7 +75,6 @@ model MyResponse<T> {
...Body<T>;
@header example: string;
}
```
In general, the prior `OkResponse<T>` is equivalent to `OkResponse & Body<T>` now or, equivalently, `{ ...OkResponse, ...Body<T> }`. In practice there are many situations where you can leave out OkResponse altogether and use plain `T` rather than `Body<T>`.
@ -110,7 +101,6 @@ Resolving operation routes now follows the following logic:
```cadl
op test(): void;
```
✅ Stay the same
@ -125,7 +115,6 @@ op test(): void;
namespace DemoService;
op test(): void;
```
⚠️ Output stays the same but add warning that no routes are emitted
@ -141,7 +130,6 @@ namespace DemoService;
@route("/")
op test(): void;
```
⚠️ Now the same as previous case, no routes emitted and emit warning
@ -160,7 +148,6 @@ namespace DemoService;
@route("/")
op test(): void;
```
#### Operation in service namespace
@ -170,7 +157,6 @@ op test(): void;
namespace Foo;
op test(): void;
```
✅ Stay the same
@ -196,7 +182,6 @@ namespace MyLib {
@route("my-lib")
op test(): void;
}
```
⚠️ Other namespace routes are not included anymore
@ -224,7 +209,6 @@ namespace Foo.MyLib {
@route("my-lib")
op test(): void;
}
```
## Remove Map type
@ -237,7 +221,6 @@ namespace Foo.MyLib {
model Foo {
options: Map<string, string>;
}
```
#### Replace with `Record<T>`
@ -246,7 +229,6 @@ model Foo {
model Foo {
options: Record<string>;
}
```
### Map using non-string key type
@ -255,7 +237,6 @@ model Foo {
model Foo {
options: Map<int32, string>;
}
```
#### Replace with `object`
@ -264,7 +245,6 @@ model Foo {
model Foo {
options: object;
}
```
## `@path` may not decorate optional properties or parameters without a default
@ -278,7 +258,6 @@ model Foo {
@path
name?: string;
}
```
Was a bad practice, but was allowed in previous versions. This will now throw an error diagnostic.
@ -290,7 +269,6 @@ model Foo {
@path
name: string;
}
```
### Resolve by adding a default value
@ -300,5 +278,4 @@ model Foo {
@path
name?: string = "singleton";
}
```

Просмотреть файл

@ -39,7 +39,6 @@ model Dog {
favoriteToy?: string;
bestTreat?: string = "chicken";
}
```
#### Built-in Models
@ -95,7 +94,6 @@ model Dog {
species: string;
name: string;
}
```
#### Extends
@ -108,7 +106,6 @@ model Animal {
}
model Dog extends Animal {}
```
#### Is
@ -128,7 +125,6 @@ model StringThing is Thing<string>;
model StringThing {
property: string;
}
```
### Enums
@ -141,7 +137,6 @@ enum Color {
Blue,
Green,
}
```
In this case, we haven't specified how the constants will be represented, allowing for different choices in different scenarios. For example, the OpenAPI emitter will choose string values "Red", "Green", "Blue". Another protocol might prefer to assign incrementing numeric values 0, 1, 2.
@ -159,7 +154,6 @@ enum Priority {
High: 100,
Low: 0,
}
```
#### Templates
@ -175,7 +169,6 @@ model Page<T> {
model DogPage {
...Page<Dog>;
}
```
A template parameter can be given a default value with `= <value>`.
@ -185,7 +178,6 @@ model Page<T = string> {
size: number;
item: T[];
}
```
#### Type Aliases
@ -194,7 +186,6 @@ Sometimes it's convenient to alias a model template instantiation or type produc
```cadl
alias DogPage = Page<Dog>;
```
Unlike `model`, `alias` does not create a new entity, and as such will not change generated code in any way. An alias merely describes a source code shorthand to avoid repeating the right-hand side in multiple places.
@ -211,7 +202,6 @@ model BestDog {
age: 14;
best: true;
}
```
String literal types can also be created using the triple-quote syntax which enables multi-line strings:
@ -224,7 +214,6 @@ model Dog {
And so on
""";
}
```
### Type Operators
@ -237,7 +226,6 @@ Unions describe a type that must be exactly one of the union's constituents. Cre
```cadl
alias GoodBreed = Beagle | GermanShepherd | GoldenRetriever;
```
##### Named unions
@ -250,7 +238,6 @@ union GoodBreed {
shepherd: GermanShepherd,
retriever: GoldenRetriever,
}
```
The above example is equivalent to the `GoodBreed` alias above, except that emitters can actually see `GoodBreed` as a named entity and also see the `beagle`, `shepherd`, and `retriever` names for the options. It also becomes possible to apply [decorators](#Decorators) to each of the options when using this form.
@ -261,7 +248,6 @@ Intersections describe a type that must include all the intersection's constitue
```cadl
alias Dog = Animal & Pet;
```
#### Arrays
@ -270,7 +256,6 @@ Arrays describe lists of things. Create an Array type with the `[]` operator.
```cadl
alias Pack = Dog[];
```
### Operations
@ -279,14 +264,12 @@ Operations describe service endpoints and consist of an operation name, paramete
```cadl
op getDog(name: string): Dog;
```
The operation's parameters describe a model, so anything you can do in a model you can do in a parameter list as well, including using the spread operator:
```cadl
op getDog(...commonParams, name: string): Dog;
```
Often an endpoint returns one of any number of models. For example, there might be a return type for when an item is found, and a return type for when an item isn't found. Unions are used to describe this pattern:
@ -297,7 +280,6 @@ model DogNotFound {
}
op getDog(name: string): Dog | DogNotFound;
```
### Namespaces & Usings
@ -310,7 +292,6 @@ namespace Models {
}
op getDog(): Models.Dog;
```
You can also put an entire Cadl file into a namespace by using the blockless namespace syntax:
@ -319,14 +300,12 @@ You can also put an entire Cadl file into a namespace by using the blockless nam
// models.cadl
namespace Models;
model Dog {}
```
```cadl
// main.cadl
import "./models.cadl";
op getDog(): Models.Dog;
```
Namespace declarations can declare multiple namespaces at once by using a dotted member expression. There's no need to declare nested namespace blocks if you don't want to.
@ -341,7 +320,6 @@ namespace C.D.E {
}
alias M = A.B.C.D.E.M;
```
It can be convenient to add references to a namespace's declarations to your local namespace, especially when namespaces can become deeply nested. The `using` statement lets us do this:
@ -350,7 +328,6 @@ It can be convenient to add references to a namespace's declarations to your loc
// models.cadl
namespace Service.Models;
model Dog {}
```
```cadl
@ -358,7 +335,6 @@ model Dog {}
import "./models.cadl";
using ServiceModels;
op getDog(): Dog; // here we can use Dog directly.
```
The bindings introduced by a `using` statement are local to the namespace they are declared in. They do not become part of the namespace themselves.
@ -375,7 +351,6 @@ namespace Test2 {
alias C = Test2.A; // not ok
alias C = Test2.B; // ok
```
### Interfaces
@ -390,7 +365,6 @@ interface A {
interface B {
b(): string;
}
```
And the keyword `extends` can be used to compose operations from other interfaces into a new interface:
@ -406,7 +380,6 @@ interface C {
b(): string;
c(): string;
}
```
### Imports
@ -419,20 +392,17 @@ The path you import must either begin with "./" or "../" or otherwise be an abso
// main.cadl
import "./models";
op getDog(): Dog;
```
```cadl
// models/main.cadl
import "./dog.cadl";
```
```cadl
// models/dog.cadl
namespace Models;
model Dog {}
```
### Decorators
@ -463,7 +433,6 @@ model Dog {
@logType("Name type")
name: string;
}
```
After running this Cadl program, the following will be printed to the console:
@ -697,7 +666,6 @@ model ReadDog {
model WriteDog {
...Dog;
}
```
#### @withDefaultKeyVisibility
@ -782,7 +750,6 @@ Lastly, you need to import the libraries into your Cadl program. By convention,
// in main.cadl
import "@cadl-lang/rest";
import "@cadl-lang/openapi3";
```
#### Using emitter libraries
@ -870,7 +837,6 @@ Here's an example that uses these to define a Pet Store service:
@Cadl.Rest.produces("application/json", "image/png")
@Cadl.Rest.consumes("application/json")
namespace PetStore;
```
The `server` keyword can take a third parameter with parameters as necessary:
@ -893,7 +859,6 @@ using Cadl.Http;
namespace Pets {
}
```
To define an operation on this resource, you need to provide the HTTP verb for the route using the `@get`, `@head` `@post`, `@put`, `@patch`, or `@delete` decorators. Alternatively, you can name your operation `list`, `create`, `read`, `update`, `delete`, or `deleteAll` and the appropriate verb will be used automatically. Lets add an operation to our `Pets` resource:
@ -906,7 +871,6 @@ namespace Pets {
// or you could also use
@get op listPets(): Pet[];
}
```
##### Automatic route generation
@ -959,7 +923,6 @@ namespace Pets {
op list(@query skip: int32, @query top: int32): Pet[];
op read(@path petId: int32): Pet;
}
```
Path parameters are appended to the URL unless a substitution with that parameter name exists on the resource path. For example, we might define a sub-resource using the following Cadl. Note how the path parameter for our sub-resource's list operation corresponds to the substitution in the URL.
@ -969,7 +932,6 @@ Path parameters are appended to the URL unless a substitution with that paramete
namespace PetToys {
op list(@path petId: int32): Toy[];
}
```
#### Request & response bodies
@ -988,7 +950,6 @@ namespace Pets {
@post
op create(@body pet: Pet): {};
}
```
Note that in the absence of explicit `@body`:
@ -1006,7 +967,6 @@ namespace Pets {
@post
op create(...Pet): {};
}
```
#### Polymorphism with discriminators
@ -1035,7 +995,6 @@ model Dog extends Pet {
kind: "dog";
bark: string;
}
```
#### Headers
@ -1055,7 +1014,6 @@ namespace Pets {
@post
op create(@body pet: Pet): {};
}
```
#### Status codes
@ -1080,7 +1038,6 @@ namespace Pets {
@statusCode statusCode: 204;
};
}
```
#### Built-in response shapes
@ -1104,7 +1061,6 @@ namespace Pets {
@post
op create(...Pet): NoContentResponse;
}
```
Note that the default status code is 200 for non-empty bodies and 204 for empty bodies. Similarly, explicit `Body<T>` is not required when T is known to be a model. So the following terser form is equivalent:
@ -1117,7 +1073,6 @@ namespace Pets {
@post
op create(...Pet): {};
}
```
Finally, another common style is to make helper response types that are
@ -1151,7 +1106,6 @@ namespace Pets {
@post
op create(...Pet): CreateResponse;
}
```
### CADL Config

Просмотреть файл

@ -75,7 +75,6 @@ model S {
foo: string;
bar: int64; // int64 is NOT assignable to int32
}
```
## Record<T>
@ -113,7 +112,6 @@ model S {
foo: 123;
bar: 456;
}
```
#### Why is the last case not assignable to `Record<int32>`?
@ -126,7 +124,6 @@ model S {
foo: 123;
bar: 456;
}
```
The reason is `model S` here is not assignable but the model expression `{ foo: 123; bar: 456; }` is, is that model S could be extended with additional properties that could then not be compatible.
@ -137,7 +134,6 @@ If you for example now add a new model
model Foo is S {
otherProp: string;
}
```
Now here `Foo` is assignable to `S` following the [model with property logic](#model-with-properties) and if `S` was assignable to `Record<int32>`, `Foo` would be able to be passed through as well but this is now invalid as `otherProp` is not an `int32` property.

Просмотреть файл

@ -85,7 +85,14 @@ export function printCadl(
const directives = shouldPrintDirective(node) ? printDirectives(path, options, print) : "";
const printedNode = printNode(path, options, print);
const value = needsParens(path, options) ? ["(", printedNode, ")"] : printedNode;
return [directives, value];
const parts: Doc[] = [directives, value];
if (node.kind === SyntaxKind.CadlScript) {
// For CadlScript(root of cadl document) we had a new line at the end.
// This must be done here so the hardline entry can be the last item of the doc array returned by the printer
// so the markdown(and other embeded formatter) can omit that extra line.
parts.push(hardline);
}
return parts;
}
function shouldPrintDirective(node: Node) {
@ -106,7 +113,6 @@ export function printNode(
case SyntaxKind.CadlScript:
return [
printStatementSequence(path as AstPath<CadlScriptNode>, options, print, "statements"),
line,
];
// Statements

Просмотреть файл

@ -2,16 +2,25 @@ import { strictEqual, throws } from "assert";
import prettier from "prettier";
import * as plugin from "../../formatter/index.js";
function format(code: string): string {
type TestParser = "cadl" | "markdown";
function format(code: string, parser: TestParser = "cadl"): string {
const output = prettier.format(code, {
parser: "cadl",
parser,
plugins: [plugin],
});
return output;
}
function assertFormat({ code, expected }: { code: string; expected: string }) {
const result = format(code);
function assertFormat({
code,
expected,
parser,
}: {
code: string;
expected: string;
parser?: TestParser;
}) {
const result = format(code, parser ?? "cadl");
strictEqual(result.trim(), expected.trim());
}
@ -1575,4 +1584,28 @@ projection model#proj {
});
});
});
describe("when embeded", () => {
it("doesn't include blank line at the end (in markdown)", () => {
assertFormat({
parser: "markdown",
code: `
This is markdown
\`\`\`cadl
op test(): string;
\`\`\`
`,
expected: `
This is markdown
\`\`\`cadl
op test(): string;
\`\`\`
`,
});
});
});
});

Просмотреть файл

@ -16,7 +16,6 @@ npm install @cadl-lang/openapi
import "@cadl-lang/openapi";
using OpenAPI;
```
## References
@ -39,7 +38,6 @@ Decorator that can be used on a response model to specify the `default` status c
model MyNonErrorResponse {}
op foo(): MyNonErrorResponse;
```
### `@extension`
@ -66,7 +64,6 @@ model Foo {}
}
)
model Foo {}
```
### `@externalDocs`
@ -84,7 +81,6 @@ Arguments:
```cadl
@externalDocs("https://example.com", "More info there")
model Foo {}
```
### `@operationId`
@ -100,7 +96,6 @@ Arguments:
```cadl
@operationId("custom_Foo")
op foo(): string;
```
## See also

Просмотреть файл

@ -46,7 +46,6 @@ union MyUnion {
cat: Cat,
dog: Dog,
}
```
## Decorators

Просмотреть файл

@ -14,14 +14,12 @@ The path you import must either begin with `"./"` or `"../"` or otherwise be an
```cadl
import "./models/foo.cadl";
```
## Import Js file
```cadl
import "./decorators.js";
```
## Import a library
@ -30,7 +28,6 @@ The import value can be name one of the package dependencies. In that case cadl
```cadl
import "@cadl-lang/rest";
```
```json
@ -48,10 +45,8 @@ If the import value is a directory it will lookup if that directoy is a node pac
```cadl
import "./models"; // same as `import "./models/main.cadl";
```
```cadl
import "./path/to/local/module"; // Assuming this path is a cadl package, it will load it using the cadlMain file.
```