Skip to content

Commit

Permalink
Add PickProperties type and @withPickedProperties decorator
Browse files Browse the repository at this point in the history
  • Loading branch information
elliots committed Jun 3, 2024
1 parent 405addf commit 4f8d616
Show file tree
Hide file tree
Showing 8 changed files with 159 additions and 7 deletions.
17 changes: 17 additions & 0 deletions docs/standard-library/built-in-data-types.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,23 @@ model OptionalProperties<Source>
| Source | An object whose spread properties are all optional. |


#### Properties
None

### `PickProperties` {#PickProperties}

Represents a collection of properties with only the specified keys included.
```typespec
model PickProperties<Source, Keys>
```

#### Template Parameters
| Name | Description |
|------|-------------|
| Source | An object whose properties are spread. |
| Keys | The property keys to include. |


#### Properties
None

Expand Down
18 changes: 18 additions & 0 deletions docs/standard-library/built-in-decorators.md
Original file line number Diff line number Diff line change
Expand Up @@ -933,6 +933,24 @@ Returns the model with the given properties omitted.



### `@withPickedProperties` {#@withPickedProperties}

Returns the model with only the given properties included.
```typespec
@withPickedProperties(pick: string | Union)
```

#### Target

`Model`

#### Parameters
| Name | Type | Description |
|------|------|-------------|
| pick | `string \| Union` | List of properties to include |



### `@withUpdateableProperties` {#@withUpdateableProperties}

Returns the model with non-updateable properties removed.
Expand Down
11 changes: 11 additions & 0 deletions packages/compiler/generated-defs/TypeSpec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,17 @@ export type WithoutOmittedPropertiesDecorator = (
omit: Type
) => void;

/**
* Returns the model with only the given properties included.
*
* @param pick List of properties to include
*/
export type WithPickedPropertiesDecorator = (
context: DecoratorContext,
target: Model,
pick: Type
) => void;

/**
* Returns the model with any default values removed.
*/
Expand Down
4 changes: 4 additions & 0 deletions packages/compiler/generated-defs/TypeSpec.ts-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import {
$visibility,
$withDefaultKeyVisibility,
$withOptionalProperties,
$withPickedProperties,
$withUpdateableProperties,
$withVisibility,
$withoutDefaultValues,
Expand Down Expand Up @@ -76,6 +77,7 @@ import type {
VisibilityDecorator,
WithDefaultKeyVisibilityDecorator,
WithOptionalPropertiesDecorator,
WithPickedPropertiesDecorator,
WithUpdateablePropertiesDecorator,
WithVisibilityDecorator,
WithoutDefaultValuesDecorator,
Expand All @@ -88,6 +90,7 @@ type Decorators = {
$withOptionalProperties: WithOptionalPropertiesDecorator;
$withUpdateableProperties: WithUpdateablePropertiesDecorator;
$withoutOmittedProperties: WithoutOmittedPropertiesDecorator;
$withPickedProperties: WithPickedPropertiesDecorator;
$withoutDefaultValues: WithoutDefaultValuesDecorator;
$withDefaultKeyVisibility: WithDefaultKeyVisibilityDecorator;
$summary: SummaryDecorator;
Expand Down Expand Up @@ -131,6 +134,7 @@ const _: Decorators = {
$withOptionalProperties,
$withUpdateableProperties,
$withoutOmittedProperties,
$withPickedProperties,
$withoutDefaultValues,
$withDefaultKeyVisibility,
$summary,
Expand Down
43 changes: 36 additions & 7 deletions packages/compiler/lib/std/decorators.tsp
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,10 @@ extern dec error(target: Model);
* scalar uuid extends string;
* ```
*/
extern dec format(target: string | bytes | ModelProperty, format: valueof string);
extern dec format(
target: string | bytes | ModelProperty,
format: valueof string
);

/**
* Specify the the pattern this string should respect using simple regular expression syntax.
Expand Down Expand Up @@ -251,7 +254,10 @@ extern dec maxValue(target: numeric | ModelProperty, value: valueof numeric);
* scalar distance is float64;
* ```
*/
extern dec minValueExclusive(target: numeric | ModelProperty, value: valueof numeric);
extern dec minValueExclusive(
target: numeric | ModelProperty,
value: valueof numeric
);

/**
* Specify the maximum value this numeric type should be, exclusive of the given
Expand All @@ -264,7 +270,10 @@ extern dec minValueExclusive(target: numeric | ModelProperty, value: valueof num
* scalar distance is float64;
* ```
*/
extern dec maxValueExclusive(target: numeric | ModelProperty, value: valueof numeric);
extern dec maxValueExclusive(
target: numeric | ModelProperty,
value: valueof numeric
);

/**
* Mark this string as a secret value that should be treated carefully to avoid exposure
Expand Down Expand Up @@ -304,7 +313,11 @@ extern dec tag(target: Namespace | Interface | Operation, tag: valueof string);
* }
* ```
*/
extern dec friendlyName(target: unknown, name: valueof string, formatArgs?: unknown);
extern dec friendlyName(
target: unknown,
name: valueof string,
formatArgs?: unknown
);

/**
* Provide a set of known values to a string type.
Expand Down Expand Up @@ -396,7 +409,11 @@ extern dec projectedName(
* ^ error cannot use subtype
* ```
*/
extern dec encodedName(target: unknown, mimeType: valueof string, name: valueof string);
extern dec encodedName(
target: unknown,
mimeType: valueof string,
name: valueof string
);

/**
* Specify the property to be used to discriminate this type.
Expand Down Expand Up @@ -604,6 +621,12 @@ extern dec withoutDefaultValues(target: Model);
*/
extern dec withoutOmittedProperties(target: Model, omit: string | Union);

/**
* Returns the model with only the given properties included.
* @param pick List of properties to include
*/
extern dec withPickedProperties(target: Model, pick: string | Union);

//---------------------------------------------------------------------------
// Debugging
//---------------------------------------------------------------------------
Expand All @@ -624,10 +647,16 @@ extern dec inspectTypeName(target: unknown, text: valueof string);
* Sets which visibilities apply to parameters for the given operation.
* @param visibilities List of visibility strings which apply to this operation.
*/
extern dec parameterVisibility(target: Operation, ...visibilities: valueof string[]);
extern dec parameterVisibility(
target: Operation,
...visibilities: valueof string[]
);

/**
* Sets which visibilities apply to the return type for the given operation.
* @param visibilities List of visibility strings which apply to this operation.
*/
extern dec returnTypeVisibility(target: Operation, ...visibilities: valueof string[]);
extern dec returnTypeVisibility(
target: Operation,
...visibilities: valueof string[]
);
12 changes: 12 additions & 0 deletions packages/compiler/lib/std/types.tsp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,18 @@ model OmitProperties<Source, Keys extends string> {
...Source;
}

/**
* Represents a collection of properties with only the specified keys included.
*
* @template Source An object whose properties are spread.
* @template Keys The property keys to include.
*/
@doc("The template for picking properties.")
@withPickedProperties(Keys)
model PickProperties<Source, Keys extends string> {
...Source;
}

/**
* Represents a collection of properties with default values omitted.
*
Expand Down
24 changes: 24 additions & 0 deletions packages/compiler/src/lib/decorators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import type {
VisibilityDecorator,
WithDefaultKeyVisibilityDecorator,
WithOptionalPropertiesDecorator,
WithPickedPropertiesDecorator,
WithUpdateablePropertiesDecorator,
WithVisibilityDecorator,
WithoutDefaultValuesDecorator,
Expand Down Expand Up @@ -879,6 +880,29 @@ export const $withoutOmittedProperties: WithoutOmittedPropertiesDecorator = (
filterModelPropertiesInPlace(target, (prop) => !omitNames.has(prop.name));
};

// -- @withPickedProperties decorator ----------------------

export const $withPickedProperties: WithPickedPropertiesDecorator = (
context: DecoratorContext,
target: Model,
pickedProperties: Type
) => {
// Get the property or properties to pick
const pickedNames = new Set<string>();
if (pickedProperties.kind === "String") {
pickedNames.add(pickedProperties.value);
} else if (pickedProperties.kind === "Union") {
for (const variant of pickedProperties.variants.values()) {
if (variant.type.kind === "String") {
pickedNames.add(variant.type.value);
}
}
}

// Remove all properties not picked
filterModelPropertiesInPlace(target, (prop) => pickedNames.has(prop.name));
};

// -- @withoutDefaultValues decorator ----------------------

export const $withoutDefaultValues: WithoutDefaultValuesDecorator = (
Expand Down
37 changes: 37 additions & 0 deletions packages/compiler/test/decorators/decorators.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -782,6 +782,43 @@ describe("compiler: built-in decorators", () => {
});
});

describe("@withPickedProperties", () => {
it("picks a model property when given a string literal", async () => {
const { TestModel } = await runner.compile(
`
model OriginalModel {
pickMe: string;
notMe: string;
}
@test
model TestModel is PickProperties<OriginalModel, "pickMe"> {
}`
);

const properties = TestModel.kind === "Model" ? Array.from(TestModel.properties.keys()) : [];
deepStrictEqual(properties, ["pickMe"]);
});

it("picks model properties when given a union containing strings", async () => {
const { TestModel } = await runner.compile(
`
model OriginalModel {
pickMe: string;
pickMeToo: string;
notMe: string;
}
@test
model TestModel is PickProperties<OriginalModel, "pickMe" | "pickMeToo"> {
}`
);

const properties = TestModel.kind === "Model" ? Array.from(TestModel.properties.keys()) : [];
deepStrictEqual(properties, ["pickMe", "pickMeToo"]);
});
});

describe("@withDefaultKeyVisibility", () => {
it("sets the default visibility on a key property when not already present", async () => {
const { TestModel } = (await runner.compile(
Expand Down

0 comments on commit 4f8d616

Please sign in to comment.