@typespec/spec-api 0.1.0-alpha.14-dev.4 → 0.1.0-alpha.14

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/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # @typespec/spec-api
2
2
 
3
+ ## 0.1.0-alpha.14
4
+
5
+ ### Features
6
+
7
+ - [#10011](https://github.com/microsoft/typespec/pull/10011) Add matcher framework for flexible value comparison in scenarios. `match.dateTime()` enables semantic datetime comparison that handles precision and timezone differences across languages.
8
+
9
+ ### Bug Fixes
10
+
11
+ - [#9995](https://github.com/microsoft/typespec/pull/9995) Remove prettier used for ValidationError message, in validateXmlBodyEquals.
12
+
13
+
3
14
  ## 0.1.0-alpha.13
4
15
 
5
16
  ### Bump dependencies
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@typespec/spec-api",
3
- "version": "0.1.0-alpha.14-dev.4",
3
+ "version": "0.1.0-alpha.14",
4
4
  "description": "Spec api to implement mock api",
5
5
  "type": "module",
6
6
  "exports": {
@@ -217,6 +217,62 @@ describe("integration with expandDyns", () => {
217
217
  });
218
218
  });
219
219
 
220
+ describe("integration with expandDyns({ resolveMatchers: false })", () => {
221
+ const config: ResolverConfig = { baseUrl: "http://localhost:3000" };
222
+
223
+ it("should preserve matcher objects instead of resolving them to plain strings", () => {
224
+ const content = { timestamp: match.dateTime.rfc3339("2022-08-26T18:38:00.000Z") };
225
+ const expanded = expandDyns(content, config, { resolveMatchers: false });
226
+ // Matcher must survive as a matcher, not be converted to a plain string
227
+ expect(isMatcher(expanded.timestamp)).toBe(true);
228
+ });
229
+
230
+ it("should allow matchValues to do semantic datetime comparison after expandDyns with resolveMatchers:false", () => {
231
+ // Regression test: query params/headers with datetime matchers must use semantic comparison.
232
+ // Without resolveMatchers:false, expandDyns converts the matcher to the plain string
233
+ // "2022-08-26T18:38:00.000Z", and a strict === comparison against the actual value
234
+ // "2022-08-26T18:38:00Z" (no milliseconds) would fail even though they represent the
235
+ // same point in time.
236
+ const queryDef = { input: match.dateTime.utcRfc3339("2022-08-26T18:38:00.000Z") };
237
+ const expanded = expandDyns(queryDef, config, { resolveMatchers: false });
238
+
239
+ // The actual query string received from an HTTP request (no milliseconds)
240
+ const actualQueryValue = "2022-08-26T18:38:00Z";
241
+
242
+ // Simulates what createHandler does: isMatcher → deepEqual → matchValues → matcher.check()
243
+ expect(isMatcher(expanded.input)).toBe(true);
244
+ expectPass(matchValues(actualQueryValue, expanded.input, "$", config));
245
+ });
246
+
247
+ it("should allow matchValues to do semantic datetime comparison for header values after expandDyns with resolveMatchers:false", () => {
248
+ // Regression test: headers with datetime matchers must use semantic comparison, same as query params.
249
+ // Without resolveMatchers:false the matcher is serialized early and isMatcher() returns false,
250
+ // so the code falls through to containsHeader() with String(value) — a strict string equality
251
+ // that fails for semantically equivalent but format-different datetime strings.
252
+ const headerDef = { "x-ms-date": match.dateTime.rfc7231("Fri, 26 Aug 2022 18:38:00 GMT") };
253
+ const expanded = expandDyns(headerDef, config, { resolveMatchers: false });
254
+
255
+ // isMatcher must still be true so createHandler routes through deepEqual / matchValues
256
+ expect(isMatcher(expanded["x-ms-date"])).toBe(true);
257
+ // Semantic check passes for the exact same RFC 7231 string
258
+ expectPass(matchValues("Fri, 26 Aug 2022 18:38:00 GMT", expanded["x-ms-date"], "$", config));
259
+ });
260
+
261
+ it("should demonstrate why resolveMatchers:true (default) breaks semantic query param matching", () => {
262
+ // With the default resolveMatchers:true, the matcher is eagerly converted to a plain string.
263
+ // A strict string comparison then fails for semantically equivalent but format-different values.
264
+ const queryDef = { input: match.dateTime.utcRfc3339("2022-08-26T18:38:00.000Z") };
265
+ const expandedWithResolve = expandDyns(queryDef, config); // resolveMatchers: true (default)
266
+
267
+ // The matcher is gone — replaced by its serialized string
268
+ expect(isMatcher(expandedWithResolve.input)).toBe(false);
269
+ expect(expandedWithResolve.input).toBe("2022-08-26T18:38:00.000Z");
270
+
271
+ // Strict string comparison fails for an equivalent datetime without milliseconds
272
+ expect(expandedWithResolve.input === "2022-08-26T18:38:00Z").toBe(false);
273
+ });
274
+ });
275
+
220
276
  describe("integration with json() Resolver", () => {
221
277
  const config: ResolverConfig = { baseUrl: "http://localhost:3000" };
222
278