@typespec/spec-coverage-sdk 0.1.0-alpha.16-dev.0 → 0.1.0-alpha.16-dev.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/client.d.ts CHANGED
@@ -14,8 +14,10 @@ export declare class SpecCoverageClient {
14
14
  export declare class SpecManifestOperations {
15
15
  #private;
16
16
  constructor(container: ContainerClient);
17
- upload(manifest: ScenarioManifest | ScenarioManifest[]): Promise<void>;
18
- get(): Promise<ScenarioManifest[]>;
17
+ upload(name: string, manifest: ScenarioManifest): Promise<void>;
18
+ uploadIfVersionNew(name: string, manifest: ScenarioManifest): Promise<"uploaded" | "skipped">;
19
+ get(name: string, version?: string): Promise<ScenarioManifest>;
20
+ tryGet(name: string, version?: string): Promise<ScenarioManifest | undefined>;
19
21
  }
20
22
  export declare class SpecCoverageOperations {
21
23
  #private;
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EACL,mBAAmB,EAGnB,eAAe,EACf,0BAA0B,EAC3B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,cAAc,EACd,iBAAiB,EACjB,sBAAsB,EACtB,gBAAgB,EACjB,MAAM,YAAY,CAAC;AAEpB,qBAAa,kBAAkB;;IAE7B,QAAQ,EAAE,sBAAsB,CAAC;IACjC,QAAQ,EAAE,sBAAsB,CAAC;gBAG/B,kBAAkB,EAAE,MAAM,EAC1B,OAAO,CAAC,EAAE;QACR,UAAU,CAAC,EAAE,0BAA0B,GAAG,mBAAmB,GAAG,eAAe,CAAC;QAChF,aAAa,CAAC,EAAE,MAAM,CAAC;KACxB;IAWU,iBAAiB;CAK/B;AAED,qBAAa,sBAAsB;;gBAIrB,SAAS,EAAE,eAAe;IAKzB,MAAM,CAAC,QAAQ,EAAE,gBAAgB,GAAG,gBAAgB,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAStE,GAAG,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC;CAGhD;AAED,qBAAa,sBAAsB;;gBAGrB,SAAS,EAAE,eAAe;IAIzB,MAAM,CAAC,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAoBnF,oBAAoB,CAC/B,aAAa,EAAE,MAAM,EACrB,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,sBAAsB,GAAG,SAAS,CAAC;YA4ChC,WAAW;CAY1B"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EACL,mBAAmB,EAGnB,eAAe,EACf,0BAA0B,EAC3B,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,cAAc,EACd,iBAAiB,EACjB,sBAAsB,EACtB,gBAAgB,EACjB,MAAM,YAAY,CAAC;AAEpB,qBAAa,kBAAkB;;IAE7B,QAAQ,EAAE,sBAAsB,CAAC;IACjC,QAAQ,EAAE,sBAAsB,CAAC;gBAG/B,kBAAkB,EAAE,MAAM,EAC1B,OAAO,CAAC,EAAE;QACR,UAAU,CAAC,EAAE,0BAA0B,GAAG,mBAAmB,GAAG,eAAe,CAAC;QAChF,aAAa,CAAC,EAAE,MAAM,CAAC;KACxB;IAWU,iBAAiB;CAK/B;AAED,qBAAa,sBAAsB;;gBAGrB,SAAS,EAAE,eAAe;IAIzB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAe/D,kBAAkB,CAC7B,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,gBAAgB,GACzB,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;IAcrB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAK9D,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC;CAe3F;AAoBD,qBAAa,sBAAsB;;gBAGrB,SAAS,EAAE,eAAe;IAIzB,MAAM,CAAC,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAoBnF,oBAAoB,CAC/B,aAAa,EAAE,MAAM,EACrB,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,sBAAsB,GAAG,SAAS,CAAC;YA4ChC,WAAW;CAY1B"}
package/dist/client.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { BlobServiceClient, } from "@azure/storage-blob";
2
+ import { eq as semverEq, gt as semverGt, valid as semverValid } from "semver";
2
3
  export class SpecCoverageClient {
3
4
  #container;
4
5
  manifest;
@@ -15,23 +16,70 @@ export class SpecCoverageClient {
15
16
  }
16
17
  }
17
18
  export class SpecManifestOperations {
18
- #blob;
19
19
  #container;
20
20
  constructor(container) {
21
21
  this.#container = container;
22
- this.#blob = this.#container.getBlockBlobClient("manifest.json");
23
22
  }
24
- async upload(manifest) {
23
+ async upload(name, manifest) {
24
+ await this.#upload(name, "latest", manifest);
25
+ await this.#upload(name, manifest.version, manifest);
26
+ }
27
+ async #upload(name, version, manifest) {
28
+ const blob = this.#container.getBlockBlobClient(this.#blobName(name, version));
25
29
  const content = JSON.stringify(manifest, null, 2);
26
- await this.#blob.upload(content, content.length, {
30
+ await blob.upload(content, content.length, {
27
31
  blobHTTPHeaders: {
28
32
  blobContentType: "application/json; charset=utf-8",
29
33
  },
30
34
  });
31
35
  }
32
- async get() {
33
- return readJsonBlob(this.#blob);
36
+ async uploadIfVersionNew(name, manifest) {
37
+ const existingVersion = await this.tryGet(name, manifest.version);
38
+ if (existingVersion) {
39
+ return "skipped";
40
+ }
41
+ const existingLatest = await this.tryGet(name);
42
+ if (existingLatest && !isVersionNewer(manifest.version, existingLatest.version)) {
43
+ return "skipped";
44
+ }
45
+ await this.upload(name, manifest);
46
+ return "uploaded";
47
+ }
48
+ async get(name, version) {
49
+ const blob = this.#container.getBlockBlobClient(this.#blobName(name, version));
50
+ return readJsonBlob(blob);
51
+ }
52
+ async tryGet(name, version) {
53
+ const blob = this.#container.getBlockBlobClient(this.#blobName(name, version));
54
+ try {
55
+ return await readJsonBlob(blob);
56
+ }
57
+ catch (e) {
58
+ if ("code" in e && e.code === "BlobNotFound") {
59
+ return undefined;
60
+ }
61
+ throw e;
62
+ }
34
63
  }
64
+ #blobName(name, version) {
65
+ return `manifests/${name}/${version ?? "latest"}.json`;
66
+ }
67
+ }
68
+ function areVersionsEquivalent(left, right) {
69
+ const leftValid = semverValid(left);
70
+ const rightValid = semverValid(right);
71
+ if (leftValid && rightValid) {
72
+ return semverEq(leftValid, rightValid);
73
+ }
74
+ return left === right;
75
+ }
76
+ function isVersionNewer(candidate, existing) {
77
+ const candidateValid = semverValid(candidate);
78
+ const existingValid = semverValid(existing);
79
+ if (candidateValid && existingValid) {
80
+ return semverGt(candidateValid, existingValid);
81
+ }
82
+ return !areVersionsEquivalent(candidate, existing);
35
83
  }
36
84
  export class SpecCoverageOperations {
37
85
  #container;
@@ -113,8 +161,21 @@ function getCoverageContainer(storageAccountName, credential, containerName) {
113
161
  }
114
162
  async function readJsonBlob(blobClient) {
115
163
  const blob = await blobClient.download();
116
- const body = await blob.blobBody;
117
- const content = await body.text();
118
- return JSON.parse(content);
164
+ if (blob.blobBody) {
165
+ const body = await blob.blobBody;
166
+ const content = await body.text();
167
+ return JSON.parse(content);
168
+ }
169
+ else if (blob.readableStreamBody) {
170
+ const stream = blob.readableStreamBody;
171
+ let content = "";
172
+ for await (const chunk of stream) {
173
+ content += chunk;
174
+ }
175
+ return JSON.parse(content);
176
+ }
177
+ else {
178
+ throw new Error("Blob has no body");
179
+ }
119
180
  }
120
181
  //# sourceMappingURL=client.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@typespec/spec-coverage-sdk",
3
- "version": "0.1.0-alpha.16-dev.0",
3
+ "version": "0.1.0-alpha.16-dev.2",
4
4
  "description": "Spec utility to manage the reported coverage",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
@@ -19,14 +19,15 @@
19
19
  "homepage": "https://github.com/microsoft/typespec#readme",
20
20
  "dependencies": {
21
21
  "@azure/identity": "~4.13.0",
22
- "@azure/storage-blob": "~12.30.0",
23
- "@types/node": "~25.0.2"
22
+ "@azure/storage-blob": "~12.31.0",
23
+ "@types/node": "~25.3.0",
24
+ "@types/semver": "^7.5.8",
25
+ "semver": "^7.7.1"
24
26
  },
25
27
  "devDependencies": {
26
- "rimraf": "~6.1.2",
27
- "typescript": "~5.9.2"
28
+ "rimraf": "~6.1.3",
29
+ "typescript": "~5.9.3"
28
30
  },
29
- "peerDependencies": {},
30
31
  "scripts": {
31
32
  "watch": "tsc -p ./tsconfig.build.json --watch",
32
33
  "build": "tsc -p ./tsconfig.build.json",
package/src/client.ts CHANGED
@@ -6,6 +6,7 @@ import {
6
6
  ContainerClient,
7
7
  StorageSharedKeyCredential,
8
8
  } from "@azure/storage-blob";
9
+ import { eq as semverEq, gt as semverGt, valid as semverValid } from "semver";
9
10
  import {
10
11
  CoverageReport,
11
12
  GeneratorMetadata,
@@ -42,26 +43,82 @@ export class SpecCoverageClient {
42
43
  }
43
44
 
44
45
  export class SpecManifestOperations {
45
- #blob: BlockBlobClient;
46
46
  #container: ContainerClient;
47
47
 
48
48
  constructor(container: ContainerClient) {
49
49
  this.#container = container;
50
- this.#blob = this.#container.getBlockBlobClient("manifest.json");
51
50
  }
52
51
 
53
- public async upload(manifest: ScenarioManifest | ScenarioManifest[]): Promise<void> {
52
+ public async upload(name: string, manifest: ScenarioManifest): Promise<void> {
53
+ await this.#upload(name, "latest", manifest);
54
+ await this.#upload(name, manifest.version, manifest);
55
+ }
56
+
57
+ async #upload(name: string, version: string, manifest: ScenarioManifest): Promise<void> {
58
+ const blob = this.#container.getBlockBlobClient(this.#blobName(name, version));
54
59
  const content = JSON.stringify(manifest, null, 2);
55
- await this.#blob.upload(content, content.length, {
60
+ await blob.upload(content, content.length, {
56
61
  blobHTTPHeaders: {
57
62
  blobContentType: "application/json; charset=utf-8",
58
63
  },
59
64
  });
60
65
  }
61
66
 
62
- public async get(): Promise<ScenarioManifest[]> {
63
- return readJsonBlob<ScenarioManifest[]>(this.#blob);
67
+ public async uploadIfVersionNew(
68
+ name: string,
69
+ manifest: ScenarioManifest,
70
+ ): Promise<"uploaded" | "skipped"> {
71
+ const existingVersion = await this.tryGet(name, manifest.version);
72
+ if (existingVersion) {
73
+ return "skipped";
74
+ }
75
+ const existingLatest = await this.tryGet(name);
76
+ if (existingLatest && !isVersionNewer(manifest.version, existingLatest.version)) {
77
+ return "skipped";
78
+ }
79
+
80
+ await this.upload(name, manifest);
81
+ return "uploaded";
82
+ }
83
+
84
+ public async get(name: string, version?: string): Promise<ScenarioManifest> {
85
+ const blob = this.#container.getBlockBlobClient(this.#blobName(name, version));
86
+ return readJsonBlob<ScenarioManifest>(blob);
87
+ }
88
+
89
+ public async tryGet(name: string, version?: string): Promise<ScenarioManifest | undefined> {
90
+ const blob = this.#container.getBlockBlobClient(this.#blobName(name, version));
91
+ try {
92
+ return await readJsonBlob<ScenarioManifest>(blob);
93
+ } catch (e: any) {
94
+ if ("code" in e && e.code === "BlobNotFound") {
95
+ return undefined;
96
+ }
97
+ throw e;
98
+ }
64
99
  }
100
+
101
+ #blobName(name: string, version?: string) {
102
+ return `manifests/${name}/${version ?? "latest"}.json`;
103
+ }
104
+ }
105
+
106
+ function areVersionsEquivalent(left: string, right: string): boolean {
107
+ const leftValid = semverValid(left);
108
+ const rightValid = semverValid(right);
109
+ if (leftValid && rightValid) {
110
+ return semverEq(leftValid, rightValid);
111
+ }
112
+ return left === right;
113
+ }
114
+
115
+ function isVersionNewer(candidate: string, existing: string): boolean {
116
+ const candidateValid = semverValid(candidate);
117
+ const existingValid = semverValid(existing);
118
+ if (candidateValid && existingValid) {
119
+ return semverGt(candidateValid, existingValid);
120
+ }
121
+ return !areVersionsEquivalent(candidate, existing);
65
122
  }
66
123
 
67
124
  export class SpecCoverageOperations {
@@ -168,7 +225,18 @@ function getCoverageContainer(
168
225
 
169
226
  async function readJsonBlob<T>(blobClient: BlockBlobClient): Promise<T> {
170
227
  const blob = await blobClient.download();
171
- const body = await blob.blobBody;
172
- const content = await body!.text();
173
- return JSON.parse(content);
228
+ if (blob.blobBody) {
229
+ const body = await blob.blobBody;
230
+ const content = await body!.text();
231
+ return JSON.parse(content);
232
+ } else if (blob.readableStreamBody) {
233
+ const stream = blob.readableStreamBody;
234
+ let content = "";
235
+ for await (const chunk of stream) {
236
+ content += chunk;
237
+ }
238
+ return JSON.parse(content);
239
+ } else {
240
+ throw new Error("Blob has no body");
241
+ }
174
242
  }