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

Add new way to define decorator implementation with $decorators export #4139

Merged
merged 24 commits into from
Aug 12, 2024
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
8 changes: 8 additions & 0 deletions .chronus/changes/decorators-export-2024-7-12-2-29-0.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking
changeKind: fix
packages:
- "@typespec/bundler"
---

Allow bundling libraries that don't import their `main` file from the TypeSpec
16 changes: 16 additions & 0 deletions .chronus/changes/decorators-export-2024-7-9-21-2-11.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking
changeKind: feature
packages:
- "@typespec/compiler"
---

Add new way to define decorator implementation with `$decorators` export.
```ts
export const $decorators = {
"TypeSpec.OpenAPI": {
useRef: $useRef,
oneOf: $oneOf,
},
};
```
15 changes: 15 additions & 0 deletions .chronus/changes/decorators-export-2024-7-9-22-3-58.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking
changeKind: feature
packages:
- "@typespec/http"
- "@typespec/json-schema"
- "@typespec/openapi"
- "@typespec/openapi3"
- "@typespec/protobuf"
- "@typespec/rest"
- "@typespec/versioning"
- "@typespec/xml"
---

Internals: Migrate to new api for declaring decorator implementation
16 changes: 15 additions & 1 deletion docs/extending-typespec/create-decorators.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,21 @@ const tagName: string = "widgets";

## JavaScript decorator implementation

Decorators can be implemented in JavaScript by prefixing the function name with `$`. A decorator function must have the following parameters:
Decorators can be implemented in JavaScript in 2 ways:

1. Prefixing the function name with `$`. e.g `export function $doc(target, name) {...}` **Great to get started/play with decorators**
2. Exporting all decorators for your library using `$decorators` variable. **Recommended**
timotheeguerin marked this conversation as resolved.
Show resolved Hide resolved

```ts
export const $decorators = {
// Namespace
"MyOrg.MyLib": {
doc: docDecoratorFn,
},
};
```

A decorator implementation takes the following parameters:

- `1`: `context` of type `DecoratorContext`
- `2`: `target` The TypeSpec type target. (`Namespace`, `Interface`, etc.)
Expand Down
7 changes: 4 additions & 3 deletions packages/bundler/src/bundler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,22 +147,23 @@ async function createRollupConfig(definition: TypeSpecBundleDefinition): Promise
const program = await compile(NodeHost, libraryPath, {
noEmit: true,
});
const jsFiles: string[] = [];
const jsFiles = new Set([resolvePath(libraryPath, definition.packageJson.main)]);
for (const file of program.jsSourceFiles.keys()) {
if (file.startsWith(libraryPath)) {
jsFiles.push(file);
jsFiles.add(file);
}
}
const typespecFiles: Record<string, string> = {
[normalizePath(join(libraryPath, "package.json"))]: JSON.stringify(definition.packageJson),
};

for (const [filename, sourceFile] of program.sourceFiles) {
typespecFiles[filename] = sourceFile.file.text;
}
const content = createBundleEntrypoint({
libraryPath,
mainFile: definition.main,
jsSourceFileNames: jsFiles,
jsSourceFileNames: [...jsFiles],
typespecSourceFiles: typespecFiles,
});

Expand Down
45 changes: 45 additions & 0 deletions packages/compiler/generated-defs/TypeSpec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -749,3 +749,48 @@ export type ReturnTypeVisibilityDecorator = (
target: Operation,
...visibilities: string[]
) => void;

export type TypeSpecDecorators = {
encode: EncodeDecorator;
doc: DocDecorator;
withOptionalProperties: WithOptionalPropertiesDecorator;
withUpdateableProperties: WithUpdateablePropertiesDecorator;
withoutOmittedProperties: WithoutOmittedPropertiesDecorator;
withPickedProperties: WithPickedPropertiesDecorator;
withoutDefaultValues: WithoutDefaultValuesDecorator;
withDefaultKeyVisibility: WithDefaultKeyVisibilityDecorator;
summary: SummaryDecorator;
returnsDoc: ReturnsDocDecorator;
errorsDoc: ErrorsDocDecorator;
deprecated: DeprecatedDecorator;
service: ServiceDecorator;
error: ErrorDecorator;
format: FormatDecorator;
pattern: PatternDecorator;
minLength: MinLengthDecorator;
maxLength: MaxLengthDecorator;
minItems: MinItemsDecorator;
maxItems: MaxItemsDecorator;
minValue: MinValueDecorator;
maxValue: MaxValueDecorator;
minValueExclusive: MinValueExclusiveDecorator;
maxValueExclusive: MaxValueExclusiveDecorator;
secret: SecretDecorator;
list: ListDecorator;
tag: TagDecorator;
friendlyName: FriendlyNameDecorator;
knownValues: KnownValuesDecorator;
key: KeyDecorator;
overload: OverloadDecorator;
projectedName: ProjectedNameDecorator;
encodedName: EncodedNameDecorator;
discriminator: DiscriminatorDecorator;
example: ExampleDecorator;
opExample: OpExampleDecorator;
visibility: VisibilityDecorator;
withVisibility: WithVisibilityDecorator;
inspectType: InspectTypeDecorator;
inspectTypeName: InspectTypeNameDecorator;
parameterVisibility: ParameterVisibilityDecorator;
returnTypeVisibility: ReturnTypeVisibilityDecorator;
};
181 changes: 3 additions & 178 deletions packages/compiler/generated-defs/TypeSpec.ts-test.ts
Original file line number Diff line number Diff line change
@@ -1,180 +1,5 @@
/** An error here would mean that the decorator is not exported or doesn't have the right name. */
import {
$deprecated,
$discriminator,
$doc,
$encode,
$encodedName,
$error,
$errorsDoc,
$example,
$format,
$friendlyName,
$inspectType,
$inspectTypeName,
$key,
$knownValues,
$list,
$maxItems,
$maxLength,
$maxValue,
$maxValueExclusive,
$minItems,
$minLength,
$minValue,
$minValueExclusive,
$opExample,
$overload,
$parameterVisibility,
$pattern,
$projectedName,
$returnTypeVisibility,
$returnsDoc,
$secret,
$service,
$summary,
$tag,
$visibility,
$withDefaultKeyVisibility,
$withOptionalProperties,
$withPickedProperties,
$withUpdateableProperties,
$withVisibility,
$withoutDefaultValues,
$withoutOmittedProperties,
} from "../src/index.js";
import type {
DeprecatedDecorator,
DiscriminatorDecorator,
DocDecorator,
EncodeDecorator,
EncodedNameDecorator,
ErrorDecorator,
ErrorsDocDecorator,
ExampleDecorator,
FormatDecorator,
FriendlyNameDecorator,
InspectTypeDecorator,
InspectTypeNameDecorator,
KeyDecorator,
KnownValuesDecorator,
ListDecorator,
MaxItemsDecorator,
MaxLengthDecorator,
MaxValueDecorator,
MaxValueExclusiveDecorator,
MinItemsDecorator,
MinLengthDecorator,
MinValueDecorator,
MinValueExclusiveDecorator,
OpExampleDecorator,
OverloadDecorator,
ParameterVisibilityDecorator,
PatternDecorator,
ProjectedNameDecorator,
ReturnTypeVisibilityDecorator,
ReturnsDocDecorator,
SecretDecorator,
ServiceDecorator,
SummaryDecorator,
TagDecorator,
VisibilityDecorator,
WithDefaultKeyVisibilityDecorator,
WithOptionalPropertiesDecorator,
WithPickedPropertiesDecorator,
WithUpdateablePropertiesDecorator,
WithVisibilityDecorator,
WithoutDefaultValuesDecorator,
WithoutOmittedPropertiesDecorator,
} from "./TypeSpec.js";

type Decorators = {
$encode: EncodeDecorator;
$doc: DocDecorator;
$withOptionalProperties: WithOptionalPropertiesDecorator;
$withUpdateableProperties: WithUpdateablePropertiesDecorator;
$withoutOmittedProperties: WithoutOmittedPropertiesDecorator;
$withPickedProperties: WithPickedPropertiesDecorator;
$withoutDefaultValues: WithoutDefaultValuesDecorator;
$withDefaultKeyVisibility: WithDefaultKeyVisibilityDecorator;
$summary: SummaryDecorator;
$returnsDoc: ReturnsDocDecorator;
$errorsDoc: ErrorsDocDecorator;
$deprecated: DeprecatedDecorator;
$service: ServiceDecorator;
$error: ErrorDecorator;
$format: FormatDecorator;
$pattern: PatternDecorator;
$minLength: MinLengthDecorator;
$maxLength: MaxLengthDecorator;
$minItems: MinItemsDecorator;
$maxItems: MaxItemsDecorator;
$minValue: MinValueDecorator;
$maxValue: MaxValueDecorator;
$minValueExclusive: MinValueExclusiveDecorator;
$maxValueExclusive: MaxValueExclusiveDecorator;
$secret: SecretDecorator;
$list: ListDecorator;
$tag: TagDecorator;
$friendlyName: FriendlyNameDecorator;
$knownValues: KnownValuesDecorator;
$key: KeyDecorator;
$overload: OverloadDecorator;
$projectedName: ProjectedNameDecorator;
$encodedName: EncodedNameDecorator;
$discriminator: DiscriminatorDecorator;
$example: ExampleDecorator;
$opExample: OpExampleDecorator;
$visibility: VisibilityDecorator;
$withVisibility: WithVisibilityDecorator;
$inspectType: InspectTypeDecorator;
$inspectTypeName: InspectTypeNameDecorator;
$parameterVisibility: ParameterVisibilityDecorator;
$returnTypeVisibility: ReturnTypeVisibilityDecorator;
};

import { $decorators } from "../src/index.js";
import type { TypeSpecDecorators } from "./TypeSpec.js";
/** An error here would mean that the exported decorator is not using the same signature. Make sure to have export const $decName: DecNameDecorator = (...) => ... */
const _: Decorators = {
$encode,
$doc,
$withOptionalProperties,
$withUpdateableProperties,
$withoutOmittedProperties,
$withPickedProperties,
$withoutDefaultValues,
$withDefaultKeyVisibility,
$summary,
$returnsDoc,
$errorsDoc,
$deprecated,
$service,
$error,
$format,
$pattern,
$minLength,
$maxLength,
$minItems,
$maxItems,
$minValue,
$maxValue,
$minValueExclusive,
$maxValueExclusive,
$secret,
$list,
$tag,
$friendlyName,
$knownValues,
$key,
$overload,
$projectedName,
$encodedName,
$discriminator,
$example,
$opExample,
$visibility,
$withVisibility,
$inspectType,
$inspectTypeName,
$parameterVisibility,
$returnTypeVisibility,
};
const _: TypeSpecDecorators = $decorators["TypeSpec"];
2 changes: 1 addition & 1 deletion packages/compiler/lib/std/decorators.tsp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import "../../dist/src/lib/decorators.js";
import "../../dist/src/lib/tsp-index.js";

using TypeSpec.Reflection;

Expand Down
Loading
Loading