Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@typespec/compiler",
"comment": "Allow use of defaults on non-optional properties.",
"type": "none"
}
],
"packageName": "@typespec/compiler"
}
19 changes: 19 additions & 0 deletions docs/extending-typespec/emitters-basics.md
Original file line number Diff line number Diff line change
Expand Up @@ -186,3 +186,22 @@ Since an emitter is a node library, you could use standard `fs` APIs to write fi
Instead, use the compiler [`host` interface](#todo) to access the file system. The API is equivalent to the node API but works in a wider range of scenarios.

In order to know where to emit files, the emitter context has a `emitterOutputDir` property that is automatically resolved using the `emitter-output-dir` built-in emitter options. This is set to `{cwd}/tsp-output/{emitter-name}` by default, but can be overridden by the user. Do not use the `compilerOptions.outputDir`

## Handling Default Values

Several TypeSpec types have a `default` property that can be used to specify a default value. For example, the following model has a default value of `true` for the `isActive` property:

```tsp
model User {
isActive?: boolean = true;
}
```

These values can be accessed in the emitter using the `default` property on the `ModelProperty` type.

```ts
const modelProp: ModelProperty = ...; // the isActive ModelProperty type
const defaultValue = modelProp.default; // value: true
```

It is important that emitters handle default values in a consistent way. Default values SHOULD NOT be used as client-side default values. Instead, they should be used as a way to specify a default value for the server-side implementation. For example, if a model property has a default value of `true`, the server-side implementation should use that value if the client does not provide a value. Default values SHOULD be expressed in documentation to properly communicate the service-side default.
6 changes: 0 additions & 6 deletions packages/compiler/core/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,12 +117,6 @@ const diagnostics = {
topLevel: "Imports must be top-level and come prior to namespaces or other declarations.",
},
},
"default-optional": {
severity: "error",
messages: {
default: "Cannot use default with non optional properties",
},
},
"token-expected": {
severity: "error",
messages: {
Expand Down
6 changes: 0 additions & 6 deletions packages/compiler/core/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -853,9 +853,6 @@ function createParser(code: string | SourceFile, options: ParseOptions = {}): Pa
const value = parseExpression();

const hasDefault = parseOptional(Token.Equals);
if (hasDefault && !optional) {
error({ code: "default-optional" });
}
const defaultValue = hasDefault ? parseExpression() : undefined;
return {
kind: SyntaxKind.ModelProperty,
Expand Down Expand Up @@ -2055,9 +2052,6 @@ function createParser(code: string | SourceFile, options: ParseOptions = {}): Pa
const value = parseProjectionExpression();

const hasDefault = parseOptional(Token.Equals);
if (hasDefault && !optional) {
error({ code: "default-optional" });
}
const defaultValue = hasDefault ? parseProjectionExpression() : undefined;
return {
kind: SyntaxKind.ProjectionModelProperty,
Expand Down
8 changes: 4 additions & 4 deletions packages/compiler/test/parser.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ describe("compiler: parser", () => {
prop2: string
};`,

`model Car {
withDefaultButNotOptional: string = "foo"
}`,

`model Car {
optional?: number;
withDefault?: string = "my-default";
Expand Down Expand Up @@ -110,10 +114,6 @@ describe("compiler: parser", () => {
["model Car is Foo extends Bar { }", [/'{' expected/]],
["model Car extends Bar is Foo { }", [/'{' expected/]],
["model Car { withDefaultMissing?: string = }", [/Expression expected/]],
[
`model Car { withDefaultButNotOptional: string = "foo" }`,
[/Cannot use default with non optional properties/],
],
["model", [/Identifier expected/]],
["model Car is Vehicle", [/';', or '{' expected/]],
["model Car;", [/'{', '=', 'extends', or 'is' expected/]],
Expand Down