Skip to content
Draft
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
4440ec3
feat: add typespec-azurite-emitter-pilot package
Oct 5, 2026
b52be27
test: validate pilot emitter output against real Azure/Azurite shapes
Oct 5, 2026
3c5d805
fix: import model types referenced in operations.ts from models.ts
Oct 5, 2026
c70b779
fix: expose header property name alongside wire name in response meta…
Oct 5, 2026
1d4c018
docs: update README gap list for response header metadata fix
Oct 5, 2026
80e8b36
docs: ground the Alloy-vs-plain-string rationale in actual GraphQL/ht…
Oct 5, 2026
0a6be11
feat: validate pilot emitter against the real, unchanged Azure Storag…
Oct 5, 2026
e30776f
fix: re-vendor routes.tsp/client.tsp as true byte-for-byte copies
Oct 5, 2026
2eddc7b
chore: prettier formatting touch-up in PROVENANCE.md
Oct 5, 2026
4bb7411
fix: resolve CI lint and spell-check failures from the real-spec work
Oct 5, 2026
bb90e78
revert: move real Storage Queue spec validation to the companion Azur…
Oct 5, 2026
c811616
chore: rename @azure-tools/typespec-azurite-emitter-pilot to @azure-t…
Oct 5, 2026
b06808c
Add @makeRequired decorator for azurite.tsp-style overlay tightening
Oct 5, 2026
caabd43
Add interfaceName to generated operation metadata for generic resourc…
Oct 5, 2026
0a7a83e
Refine Azurite emitter overlay support
Oct 6, 2026
d0f7217
Simplify TypeKit usage in Azurite emitter
Oct 6, 2026
c1414a1
Remove redundant dryRun guard
Oct 6, 2026
04e5e03
Emit Azurite dispatch metadata
Oct 6, 2026
d68cf5e
Keep Azurite bridge metadata out of emitter
Oct 6, 2026
216691e
Honor TCGC client names in Azurite emitter
Oct 6, 2026
a40c579
Localize Azurite operation naming
Oct 6, 2026
52a9eed
Resolve Azurite operation names up front
Oct 6, 2026
c5d884f
Apply TCGC client names consistently
Oct 6, 2026
2c9ceb3
Move Azurite naming helpers to utils
Oct 6, 2026
b3474c9
Generate Azurite serialization specs
Oct 6, 2026
fb7416d
Generate Azurite serialization helpers
Oct 6, 2026
6c2c7a9
Emit direct Azurite serialization functions
Oct 6, 2026
21ffef7
Clean up Azurite generated model names
Oct 6, 2026
ff10d3a
Share Azurite serialization helpers
Oct 6, 2026
0a568d3
Generate Azurite XML body serialization
Oct 6, 2026
82d768d
Migrate Azurite emitter rendering to Alloy
Oct 7, 2026
4ab4d66
Share Azurite doc comment renderer
Oct 7, 2026
76b7ac0
Use Alloy TypeScript declaration components
Oct 7, 2026
ed3de0a
Reuse emitter framework output helpers
Oct 7, 2026
6cc6a3c
Use typed declarations and Alloy render matchers
Oct 7, 2026
e1a53ac
Remove custom TypeScript type renderer
Oct 7, 2026
64f801e
Remove unused doc comment wrapper
Oct 7, 2026
72b964b
Simplify Alloy refkey declarations
Oct 7, 2026
8198b9c
Reuse typed operation declarations
Oct 7, 2026
56f03c6
Inline pass-through operation renderers
Oct 7, 2026
ad546a5
Clean up Azurite emitter transform residue
Oct 7, 2026
300221e
Align Azurite serialization contracts
Oct 7, 2026
1b6f1f2
Use TS name policy for Azurite emitter types
Oct 7, 2026
3f91916
Simplify Azurite generated file header
Oct 7, 2026
4471cb4
Thin Azurite serialization generation
Oct 7, 2026
954690e
Compact Azurite serialization descriptors
Oct 7, 2026
ffe504e
Consolidate Azurite service metadata
Oct 7, 2026
f362606
Colocate Azurite runtime descriptors
Oct 7, 2026
1f52811
Validate Azurite numeric descriptors
Oct 7, 2026
0071600
Restore Azurite visibility timeout overlay
Oct 7, 2026
f9f41db
Address Azurite emitter render review
Oct 8, 2026
5619f46
Refactor Azurite model build context
Oct 8, 2026
c148bed
Introduce Azurite emitter context
Oct 8, 2026
90ec7a8
Diagnose Azurite operation name collisions
Oct 8, 2026
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
7 changes: 7 additions & 0 deletions .chronus/changes/azurite-emitter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
changeKind: feature
packages:
- "@azure-tools/typespec-azurite-emitter"
---

Add @azure-tools/typespec-azurite-emitter, a TypeSpec emitter generating Azurite server artifacts (models, route metadata, handler interfaces) from HTTP service definitions.
21 changes: 21 additions & 0 deletions packages/typespec-azurite-emitter/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) Microsoft Corporation. All rights reserved.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE
80 changes: 80 additions & 0 deletions packages/typespec-azurite-emitter/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# @azure-tools/typespec-azurite-emitter

Prototype TypeSpec emitter for generating the Queue server artifacts Azurite needs from a
compiled HTTP service plus an `azurite.tsp` overlay.

The package demonstrates a small but reusable emitter structure:

1. `src/build-model.ts` reads `@typespec/http` operations and TypeSpec models into an
emitter-owned server model.
2. `src/render/` writes three TypeScript files from that model:
- `models.ts` — data-model interfaces.
- `operations.ts` — request/response types plus route metadata.
- `handlers.ts` — handler interface methods with `(params, context)` signatures.

## Usage

```bash
tsp compile . --emit @azure-tools/typespec-azurite-emitter
```

or in `tspconfig.yaml`:

```yaml
emit:
- "@azure-tools/typespec-azurite-emitter"
options:
"@azure-tools/typespec-azurite-emitter":
outputDir: "." # optional, relative to the emitter output dir
```

## Azurite overlays

An Azurite-owned overlay can import the shared Storage TypeSpec and apply emulator-specific
changes without editing the shared source. This package includes `@makeOptional` for required
properties that the emulator accepts as optional:

```tsp
import "@azure-tools/typespec-azurite-emitter";
import "./main.tsp";

using Azurite;
using Storage.Queues;

@@makeOptional(Storage.Queues.AccessPolicy.start);
@@makeOptional(Storage.Queues.AccessPolicy.expiry);
@@makeOptional(Storage.Queues.AccessPolicy.permission);
```

Core TypeSpec augment decorators can be used for ordinary constraints, for example relaxing the
Queue visibility-timeout maximum in the overlay:

```tsp
@@maxValue(Storage.Queues.VisibilityTimeoutParameter.visibilityTimeout, 2147483647);
```

## Tests

- `test/build-model.test.ts` validates the intermediate model, including operation metadata,
referenced models, `Record<T>`, anonymous models, operation-name collisions, and overlay
changes.
- `test/render.test.ts` validates rendering from a hand-built server model.
- `test/e2e.test.ts` compiles the fixture through the emitter and checks the generated files.
- `test/azurite-compat.test.ts` checks that generated handler and route-metadata shapes contain
what Azurite's Queue runtime needs to wire dispatch and handlers.

Run:

```bash
pnpm --filter @azure-tools/typespec-azurite-emitter test
pnpm --filter @azure-tools/typespec-azurite-emitter build
pnpm --filter @azure-tools/typespec-azurite-emitter lint
```

## Current scope

This package is intentionally small. It covers the artifact shape and emitter architecture needed
for a Queue handoff, not a full Storage implementation. The companion Azurite PR validates the
generated Queue files against Azurite's real runtime. Full XML/model mapper generation, Blob,
Table/OData, streaming, multipart bodies, versioning, pagination, and richer enum/union rendering
are future work.
19 changes: 19 additions & 0 deletions packages/typespec-azurite-emitter/generated-defs/Azurite.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import type {
DecoratorContext,
DecoratorValidatorCallbacks,
ModelProperty,
} from "@typespec/compiler";

/**
* Marks a model property as optional for Azurite without editing the shared service TypeSpec.
*
* @param target The model property to make optional.
*/
export type MakeOptionalDecorator = (
context: DecoratorContext,
target: ModelProperty,
) => DecoratorValidatorCallbacks | void;

export type AzuriteDecorators = {
makeOptional: MakeOptionalDecorator;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// An error in the imports would mean that the decorator is not exported or
// doesn't have the right name.

import { $decorators } from "@azure-tools/typespec-azurite-emitter";
import type { AzuriteDecorators } from "./Azurite.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 _decs: AzuriteDecorators = $decorators["Azurite"];
12 changes: 12 additions & 0 deletions packages/typespec-azurite-emitter/lib/decorators.tsp
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import "../dist/src/index.js";

using Reflection;

namespace Azurite;

/**
* Marks a model property as optional for Azurite without editing the shared service TypeSpec.
*
* @param target The model property to make optional.
*/
extern dec makeOptional(target: ModelProperty);
1 change: 1 addition & 0 deletions packages/typespec-azurite-emitter/lib/main.tsp
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import "./decorators.tsp";
66 changes: 66 additions & 0 deletions packages/typespec-azurite-emitter/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
{
"name": "@azure-tools/typespec-azurite-emitter",
"version": "0.1.0",
"description": "TypeSpec emitter generating Azurite server artifacts (models, route metadata, handler interfaces).",
"type": "module",
"license": "MIT",
"author": "Microsoft Corporation",
"keywords": [
"typespec",
"emitter",
"azurite"
],
"repository": {
"type": "git",
"url": "git+https://github.com/Azure/typespec-azure.git"
},
"bugs": {
"url": "https://github.com/Azure/typespec-azure/issues"
},
"engines": {
"node": ">=22.0.0"
},
"main": "dist/src/index.js",
"types": "dist/src/index.d.ts",
"tspMain": "lib/main.tsp",
"files": [
"lib/**",
"dist/**",
"!dist/test/**"
],
"exports": {
".": {
"typespec": "./lib/main.tsp",
"import": "./dist/src/index.js"
}
},
"scripts": {
"build": "pnpm gen-extern-signature && tsc -p tsconfig.build.json",
"watch": "tsc -p tsconfig.build.json --watch",
"clean": "rimraf ./dist ./temp",
"gen-extern-signature": "tspd --enable-experimental gen-extern-signature .",
"lint": "oxlint . --deny-warnings",
"lint:fix": "oxlint . --fix",
"test": "vitest run",
"test:watch": "vitest -w",
"test:ui": "vitest --ui",
"test:ci": "vitest run --coverage --reporter=junit --reporter=default"
},
"peerDependencies": {
"@azure-tools/typespec-client-generator-core": "workspace:^",
"@typespec/compiler": "workspace:^",
"@typespec/http": "workspace:^"
},
"devDependencies": {
"@azure-tools/typespec-client-generator-core": "workspace:^",
"@types/node": "catalog:",
"@typespec/compiler": "workspace:^",
"@typespec/http": "workspace:^",
"@typespec/tspd": "workspace:^",
"@vitest/coverage-v8": "catalog:",
"@vitest/ui": "catalog:",
"rimraf": "catalog:",
"typescript": "catalog:",
"vitest": "catalog:"
}
}
Loading
Loading