nebius/SWE-rebench-V2-PRs huggingface dataset:
Repository: st3v3nmw/obsidian-spaced-repetition
Pull request #1142 (2024-10-20 08:54:29)

fix(multiline cards): the Qn should start from the immediate empty line above it
Fix issue reported in  https://github.com/st3v3nmw/obsidian-spaced-repetition/issues/1136.

![image](https://github.com/user-attachments/assets/978450e1-3f08-44b0-bf89-2c96140f170e)

![image](https://github.com/user-attachments/assets/4efe6545-46f7-4845-ab95-a1cb890e7f7d)



Patch:
diff --git a/src/parser.ts b/src/parser.ts
index b0e71f0..c748bf9 100644
--- a/src/parser.ts
+++ b/src/parser.ts
@@ -120,7 +120,7 @@ export function parse(text: string, options: ParserOptions): ParsedQuestionInfo[
             // We've probably reached the end of a card
             (isEmptyLine && !options.multilineCardEndMarker) ||
             // Empty line & we're not picking up any card
-            (isEmptyLine && cardText.length == 0) ||
+            (isEmptyLine && cardType == null) ||
             // We've reached the end of a multi line card &
             //  we're using custom end markers
             hasMultilineCardEndMarker


Test patch:
diff --git a/tests/unit/parser.test.ts b/tests/unit/parser.test.ts
index 9cb6d75..17dbaab 100644
--- a/tests/unit/parser.test.ts
+++ b/tests/unit/parser.test.ts
@@ -298,6 +298,40 @@ test("Test parsing of multi line reversed cards", () => {
             clozePatterns: [],
         }),
     ).toEqual([[CardType.MultiLineReversed, "Question\n@@@\nAnswer", 0, 2]]);
+    expect(
+        parseT(
+            `line 1
+
+
+line 2
+
+Question 1?
+??
+Answer to question 1
+????
+line 3
+
+line 4
+
+Question 2?
+??
+Answer to question 2
+????
+Line 5
+`,
+            {
+                singleLineCardSeparator: ":::",
+                singleLineReversedCardSeparator: "::::",
+                multilineCardSeparator: "??",
+                multilineReversedCardSeparator: "???",
+                multilineCardEndMarker: "????",
+                clozePatterns: [],
+            },
+        ),
+    ).toEqual([
+        [CardType.MultiLineBasic, "Question 1?\n??\nAnswer to question 1", 5, 7],
+        [CardType.MultiLineBasic, "Question 2?\n??\nAnswer to question 2", 13, 15],
+    ]);
 
     // empty string or whitespace character provided
     expect(
Repository: sql-formatter-org/sql-formatter
Pull request #269 (2022-06-30 09:07:14)

Support create table/view optional arguments
Issue: https://github.com/sql-formatter-org/sql-formatter/issues/267

Create table syntax: https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#syntax_2
Create view syntax: https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#syntax_7


Patch:
diff --git a/src/languages/bigquery.formatter.ts b/src/languages/bigquery.formatter.ts
index a6c76ecc..036cbe67 100644
--- a/src/languages/bigquery.formatter.ts
+++ b/src/languages/bigquery.formatter.ts
@@ -718,11 +718,21 @@ const reservedCommands = [
   'SET SCHEMA', // added
   'CREATE SCHEMA',
   'CREATE TABLE',
+  'CREATE TABLE IF NOT EXISTS',
+  'CREATE TEMP TABLE',
+  'CREATE TEMP TABLE IF NOT EXISTS',
+  'CREATE TEMPORARY TABLE',
+  'CREATE TEMPORARY TABLE IF NOT EXISTS',
+  'CREATE OR REPLACE TABLE',
+  'CREATE OR REPLACE TEMP TABLE',
+  'CREATE OR REPLACE TEMPORARY TABLE',
   'CREATE TABLE LIKE',
   'CREATE TABLE COPY',
   'CREATE SNAPSHOT TABLE',
   'CREATE TABLE CLONE',
   'CREATE VIEW',
+  'CREATE VIEW IF NOT EXISTS',
+  'CREATE OR REPLACE VIEW',
   'CREATE MATERIALIZED VIEW',
   'CREATE EXTERNAL TABLE',
   'CREATE FUNCTION',


Test patch:
diff --git a/test/bigquery.test.ts b/test/bigquery.test.ts
index d896d101..a034a708 100644
--- a/test/bigquery.test.ts
+++ b/test/bigquery.test.ts
@@ -166,4 +166,55 @@ describe('BigQueryFormatter', () => {
         Items;
     `);
   });
+
+  it('supports create view optional arguments', () => {
+    const createViewVariations = [
+      'CREATE VIEW',
+      'CREATE OR REPLACE VIEW',
+      'CREATE VIEW IF NOT EXISTS',
+    ];
+
+    createViewVariations.forEach((createViewVariation: string) => {
+      expect(
+        format(`
+        ${createViewVariation} my_dataset.my_view AS (
+          SELECT t1.col1, t1.col2 FROM my_dataset.my_table)`)
+      ).toBe(dedent`
+        ${createViewVariation}
+          my_dataset.my_view AS (
+            SELECT
+              t1.col1,
+              t1.col2
+            FROM
+              my_dataset.my_table
+          )
+      `);
+    });
+  });
+
+  it('supports create table optional arguments', () => {
+    const createTableVariations = [
+      'CREATE TABLE',
+      'CREATE TABLE IF NOT EXISTS',
+      'CREATE TEMP TABLE',
+      'CREATE TEMP TABLE IF NOT EXISTS',
+      'CREATE TEMPORARY TABLE',
+      'CREATE TEMPORARY TABLE IF NOT EXISTS',
+      'CREATE OR REPLACE TABLE',
+      'CREATE OR REPLACE TEMP TABLE',
+      'CREATE OR REPLACE TEMPORARY TABLE',
+    ];
+
+    createTableVariations.forEach((createTableVariation: string) => {
+      expect(
+        format(`
+        ${createTableVariation} mydataset.newtable (
+          a INT64 NOT NULL
+        )`)
+      ).toBe(dedent`
+        ${createTableVariation}
+          mydataset.newtable (a INT64 NOT NULL)
+      `);
+    });
+  });
 });
Repository: sql-formatter-org/sql-formatter
Pull request #280 (2022-07-05 07:57:47)

Fix formatting of BigQuery FROM clause operators
These operators were previously misclassified as RESERVED_COMMANDs:

- [UNNEST](https://cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax#unnest_operator)
- [PIVOT](https://cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax#pivot_operator)
- [UNPIVOT](https://cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax#unpivot_operator)
- [TABLESAMPLE SYSTEM](https://cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax#tablesample_operator)

Refs #279 


Patch:
diff --git a/src/languages/bigquery.formatter.ts b/src/languages/bigquery.formatter.ts
index a170958b..94d97ec9 100644
--- a/src/languages/bigquery.formatter.ts
+++ b/src/languages/bigquery.formatter.ts
@@ -544,6 +544,7 @@ const reservedFunctions = {
     'TO_BASE64',
   ],
   other: ['BQ.JOBS.CANCEL', 'BQ.REFRESH_MATERIALIZED_VIEW'],
+  pivot: ['PIVOT', 'UNPIVOT'],
 };
 
 /**
@@ -635,14 +636,14 @@ const reservedKeywords = {
     'SOME',
     // 'STRUCT',
     'TABLE',
-    // 'TABLESAMPLE',
+    'TABLESAMPLE SYSTEM',
     'THEN',
     'TO',
     'TREAT',
     'TRUE',
     'UNBOUNDED',
     // 'UNION',
-    // 'UNNEST',
+    'UNNEST',
     // 'USING',
     // 'WHEN',
     // 'WHERE',
@@ -689,10 +690,6 @@ const reservedCommands = [
   // DQL, https://cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax
   'SELECT',
   'FROM',
-  'UNNEST',
-  'PIVOT',
-  'UNPIVOT',
-  'TABLESAMPLE SYSTEM',
   'WHERE',
   'GROUP BY',
   'HAVING',


Test patch:
diff --git a/test/bigquery.test.ts b/test/bigquery.test.ts
index 68d2d53f..cb4ed3a9 100644
--- a/test/bigquery.test.ts
+++ b/test/bigquery.test.ts
@@ -220,4 +220,53 @@ describe('BigQueryFormatter', () => {
       `);
     });
   });
+
+  // Issue #279
+  describe('supports FROM clause operators:', () => {
+    it('UNNEST operator', () => {
+      expect(format('SELECT * FROM UNNEST ([1, 2, 3]);')).toBe(dedent`
+        SELECT
+          *
+        FROM
+          UNNEST ([1, 2, 3]);
+      `);
+    });
+
+    it('PIVOT operator', () => {
+      expect(format(`SELECT * FROM Produce PIVOT(sales FOR quarter IN (Q1, Q2, Q3, Q4));`))
+        .toBe(dedent`
+        SELECT
+          *
+        FROM
+          Produce PIVOT(
+            sales
+            FOR
+              quarter IN (Q1, Q2, Q3, Q4)
+          );
+      `);
+    });
+
+    it('UNPIVOT operator', () => {
+      expect(format(`SELECT * FROM Produce UNPIVOT(sales FOR quarter IN (Q1, Q2, Q3, Q4));`))
+        .toBe(dedent`
+        SELECT
+          *
+        FROM
+          Produce UNPIVOT(
+            sales
+            FOR
+              quarter IN (Q1, Q2, Q3, Q4)
+          );
+      `);
+    });
+
+    it('TABLESAMPLE SYSTEM operator', () => {
+      expect(format(`SELECT * FROM dataset.my_table TABLESAMPLE SYSTEM (10 PERCENT);`)).toBe(dedent`
+        SELECT
+          *
+        FROM
+          dataset.my_table TABLESAMPLE SYSTEM (10 PERCENT);
+      `);
+    });
+  });
 });
Repository: sql-formatter-org/sql-formatter
Pull request #372 (2022-08-03 16:48:42)

Fix isToken.SELECT predicate
Fixing the SELECT clause detection.

A bit of a step-back from having previously eliminated the need to compare keywords with regexes. Another sign that this one-token-can-contain-multiple-words is not really a proper path forward.




Patch:
diff --git a/src/lexer/token.ts b/src/lexer/token.ts
index b697419a..4d371cbd 100644
--- a/src/lexer/token.ts
+++ b/src/lexer/token.ts
@@ -61,7 +61,8 @@ export const isToken = {
   END: testToken({ value: 'END', type: TokenType.RESERVED_CASE_END }),
   FROM: testToken({ value: 'FROM', type: TokenType.RESERVED_COMMAND }),
   LIMIT: testToken({ value: 'LIMIT', type: TokenType.RESERVED_COMMAND }),
-  SELECT: testToken({ value: 'SELECT', type: TokenType.RESERVED_COMMAND }),
+  SELECT: (token: Token) =>
+    /^SELECT\b/.test(token.value) && token.type === TokenType.RESERVED_COMMAND,
   SET: testToken({ value: 'SET', type: TokenType.RESERVED_COMMAND }),
   STRUCT: testToken({ value: 'STRUCT', type: TokenType.RESERVED_KEYWORD }),
   TABLE: testToken({ value: 'TABLE', type: TokenType.RESERVED_KEYWORD }),


Test patch:
diff --git a/test/unit/Parser.test.ts b/test/unit/Parser.test.ts
index 2b93b0d3..1f3fdeee 100644
--- a/test/unit/Parser.test.ts
+++ b/test/unit/Parser.test.ts
@@ -4,7 +4,7 @@ import Tokenizer from 'src/lexer/Tokenizer';
 describe('Parser', () => {
   const parse = (sql: string) => {
     const tokens = new Tokenizer({
-      reservedCommands: ['SELECT', 'FROM', 'WHERE', 'LIMIT', 'CREATE TABLE'],
+      reservedCommands: ['SELECT', 'SELECT DISTINCT', 'FROM', 'WHERE', 'LIMIT', 'CREATE TABLE'],
       reservedDependentClauses: ['WHEN', 'ELSE'],
       reservedSetOperations: ['UNION'],
       reservedJoins: ['JOIN'],
@@ -392,4 +392,30 @@ describe('Parser', () => {
       ]
     `);
   });
+
+  it('parses SELECT DISTINCT *', () => {
+    expect(parse('SELECT DISTINCT *')).toMatchInlineSnapshot(`
+      Array [
+        Object {
+          "children": Array [
+            Object {
+              "children": Array [
+                Object {
+                  "type": "all_columns_asterisk",
+                },
+              ],
+              "nameToken": Object {
+                "text": "SELECT DISTINCT",
+                "type": "RESERVED_COMMAND",
+                "value": "SELECT DISTINCT",
+              },
+              "type": "clause",
+            },
+          ],
+          "hasSemicolon": false,
+          "type": "statement",
+        },
+      ]
+    `);
+  });
 });
Repository: sql-formatter-org/sql-formatter
Pull request #389 (2022-08-11 14:12:29)

Throw error when unsupported aliasAs config used
Forgot to add this check when I originally removed the `aliasAs` config.


Patch:
diff --git a/src/sqlFormatter.ts b/src/sqlFormatter.ts
index 9af73677..ff28617e 100644
--- a/src/sqlFormatter.ts
+++ b/src/sqlFormatter.ts
@@ -89,6 +89,9 @@ function validateConfig(cfg: FormatOptions): FormatOptions {
   if ('newlineBeforeCloseParen' in cfg) {
     throw new ConfigError('newlineBeforeCloseParen config is no more supported.');
   }
+  if ('aliasAs' in cfg) {
+    throw new ConfigError('aliasAs config is no more supported.');
+  }
 
   if (cfg.expressionWidth <= 0) {
     throw new ConfigError(


Test patch:
diff --git a/test/sqlFormatter.test.ts b/test/sqlFormatter.test.ts
index c289bdb3..ef17aeba 100644
--- a/test/sqlFormatter.test.ts
+++ b/test/sqlFormatter.test.ts
@@ -42,4 +42,10 @@ describe('sqlFormatter', () => {
       format('SELECT *', { newlineBeforeCloseParen: true } as any);
     }).toThrow('newlineBeforeCloseParen config is no more supported.');
   });
+
+  it('throws error when aliasAs config option used', () => {
+    expect(() => {
+      format('SELECT *', { aliasAs: 'always' } as any);
+    }).toThrow('aliasAs config is no more supported.');
+  });
 });
Repository: pmcelhaney/counterfact
Pull request #187 (2022-09-10 14:20:56)

make response[statusCode].random() use the OpenAPI examples if found


Patch:
diff --git a/src/response-builder.js b/src/response-builder.js
index 58e8239..245b9a1 100644
--- a/src/response-builder.js
+++ b/src/response-builder.js
@@ -2,6 +2,10 @@ import jsf from "json-schema-faker";
 
 jsf.option("useExamplesValue", true);
 
+function oneOf(array) {
+  return array[Math.floor(Math.random() * array.length)];
+}
+
 export function createResponseBuilder(operation) {
   return new Proxy(
     {},
@@ -71,7 +75,9 @@ export function createResponseBuilder(operation) {
             content: Object.keys(content).map((type) => ({
               type,
 
-              body: jsf.generate(content[type].schema),
+              body: content[type].examples
+                ? oneOf(content[type].examples)
+                : jsf.generate(content[type].schema),
             })),
           };
         },


Test patch:
diff --git a/test/response-builder.test.js b/test/response-builder.test.js
index 334f815..37aad3e 100644
--- a/test/response-builder.test.js
+++ b/test/response-builder.test.js
@@ -72,6 +72,8 @@ describe("a response builder", () => {
                 type: "string",
                 examples: ["hello"],
               },
+
+              examples: ["example text response"],
             },
           },
         },
@@ -95,7 +97,7 @@ describe("a response builder", () => {
       expect(response.status).toBe(200);
       expect(response.content).toStrictEqual([
         { type: "application/json", body: { value: "hello" } },
-        { type: "text/plain", body: "hello" },
+        { type: "text/plain", body: "example text response" },
       ]);
     });
Repository: pmcelhaney/counterfact
Pull request #202 (2022-09-17 17:39:47)

fixed an issue where random() wasn't reading example responses properly


Patch:
diff --git a/.changeset/poor-suns-exercise.md b/.changeset/poor-suns-exercise.md
new file mode 100644
index 0000000..9a729ad
--- /dev/null
+++ b/.changeset/poor-suns-exercise.md
@@ -0,0 +1,5 @@
+---
+"counterfact": patch
+---
+
+fix an issue where random() wasn't reading the examples right
diff --git a/src/response-builder.js b/src/response-builder.js
index 245b9a1..f123e51 100644
--- a/src/response-builder.js
+++ b/src/response-builder.js
@@ -2,8 +2,12 @@ import jsf from "json-schema-faker";
 
 jsf.option("useExamplesValue", true);
 
-function oneOf(array) {
-  return array[Math.floor(Math.random() * array.length)];
+function oneOf(items) {
+  if (Array.isArray(items)) {
+    return items[Math.floor(Math.random() * items.length)];
+  }
+
+  return oneOf(Object.values(items));
 }
 
 export function createResponseBuilder(operation) {


Test patch:
diff --git a/test/response-builder.test.js b/test/response-builder.test.js
index 37aad3e..90eb575 100644
--- a/test/response-builder.test.js
+++ b/test/response-builder.test.js
@@ -73,7 +73,7 @@ describe("a response builder", () => {
                 examples: ["hello"],
               },
 
-              examples: ["example text response"],
+              examples: { text: "example text response" },
             },
           },
         },
Repository: pmcelhaney/counterfact
Pull request #229 (2022-09-28 23:26:52)

encode non-alphanumeric name as valid variable names


Patch:
diff --git a/.changeset/pink-tomatoes-listen.md b/.changeset/pink-tomatoes-listen.md
new file mode 100644
index 0000000..e1d6339
--- /dev/null
+++ b/.changeset/pink-tomatoes-listen.md
@@ -0,0 +1,5 @@
+---
+"counterfact": patch
+---
+
+encode non-alphanumeric name as valid variable names
diff --git a/src/typescript-generator/coder.js b/src/typescript-generator/coder.js
index ffc1900..d9359f3 100644
--- a/src/typescript-generator/coder.js
+++ b/src/typescript-generator/coder.js
@@ -27,7 +27,11 @@ export class Coder {
     return new this.constructor(requirement);
   }
 
-  *names(name = this.requirement.url.split("/").at(-1)) {
+  *names(rawName = this.requirement.url.split("/").at(-1)) {
+    const name = rawName
+      .replace(/^\d/u, (digit) => `_${digit}`)
+      .replace(/[^\w$]/gu, "_");
+
     yield name;
 
     let index = 1;


Test patch:
diff --git a/test/typescript-generator/coder.test.js b/test/typescript-generator/coder.test.js
index 1a974aa..4c3cb31 100644
--- a/test/typescript-generator/coder.test.js
+++ b/test/typescript-generator/coder.test.js
@@ -11,6 +11,17 @@ describe("a Coder", () => {
     expect([one, two, three]).toStrictEqual(["Person", "Person2", "Person3"]);
   });
 
+  it("makes non-alphanumeric names valid variable names", () => {
+    const coder = new Coder({ url: "#/components/schemas/5i.am.strange.1$!" });
+
+    const [one, two] = coder.names();
+
+    expect([one, two]).toStrictEqual([
+      "_5i_am_strange_1$_",
+      "_5i_am_strange_1$_2",
+    ]);
+  });
+
   it("generates a list of potential names given a starting point", () => {
     const coder = new Coder({ url: "#/components/schemas/Person" });
Repository: pmcelhaney/counterfact
Pull request #324 (2022-11-30 15:22:57)

fix crash when a path is not found


Patch:
diff --git a/.changeset/nine-berries-reply.md b/.changeset/nine-berries-reply.md
new file mode 100644
index 0000000..c37afaa
--- /dev/null
+++ b/.changeset/nine-berries-reply.md
@@ -0,0 +1,5 @@
+---
+"counterfact": patch
+---
+
+fix crash when a path is not found
diff --git a/src/server/registry.js b/src/server/registry.js
index 333a4a8..d1f901f 100644
--- a/src/server/registry.js
+++ b/src/server/registry.js
@@ -114,7 +114,8 @@ export class Registry {
     if (!execute) {
       return () => ({
         status: 404,
-        body: `Could not find a ${httpRequestMethod} method at ${url}\nGot as far as ${handler.matchedPath}`,
+        body: `Could not find a ${httpRequestMethod} method matching ${url}\n`,
+        contentType: "text/plain",
       });
     }
 


Test patch:
diff --git a/test/server/dispatcher.test.js b/test/server/dispatcher.test.js
index 93231e3..540d4ee 100644
--- a/test/server/dispatcher.test.js
+++ b/test/server/dispatcher.test.js
@@ -535,9 +535,7 @@ describe("given an invalid path", () => {
     expect(response.status).toBe(404);
 
     expect(response.body).toBe(
-      "Could not find a PUT method at " +
-        "/your/left/foot/in/and/your/right/foot/out\n" +
-        "Got as far as /your/{side}/{bodyPart}/in/and/your"
+      "Could not find a PUT method matching /your/left/foot/in/and/your/right/foot/out\n"
     );
   });
 });
Repository: pmcelhaney/counterfact
Pull request #502 (2023-08-17 16:39:40)

fix an issue where OperationTypeCoder wasn't looking at the produces property in the root


Patch:
diff --git a/.changeset/hungry-actors-work.md b/.changeset/hungry-actors-work.md
new file mode 100644
index 0000000..595104a
--- /dev/null
+++ b/.changeset/hungry-actors-work.md
@@ -0,0 +1,5 @@
+---
+"counterfact": patch
+---
+
+fix another bug where OpenAPI2 puts the produces proprty in the root
diff --git a/src/typescript-generator/operation-type-coder.js b/src/typescript-generator/operation-type-coder.js
index 384f0f2..5021ff3 100644
--- a/src/typescript-generator/operation-type-coder.js
+++ b/src/typescript-generator/operation-type-coder.js
@@ -101,7 +101,8 @@ export class OperationTypeCoder extends Coder {
 
     const responseType = new ResponseTypeCoder(
       this.requirement.get("responses"),
-      this.requirement.get("produces")?.data
+      this.requirement.get("produces")?.data ??
+        this.requirement.specification?.rootRequirement?.get("produces")?.data
     ).write(script);
 
     const proxyType = "(url: string) => { proxyUrl: string }";


Test patch:
diff --git a/test/typescript-generator/__snapshots__/operation-type-coder.test.js.snap b/test/typescript-generator/__snapshots__/operation-type-coder.test.js.snap
index f6f0b26..a178d77 100644
--- a/test/typescript-generator/__snapshots__/operation-type-coder.test.js.snap
+++ b/test/typescript-generator/__snapshots__/operation-type-coder.test.js.snap
@@ -53,15 +53,27 @@ exports[`an OperationTypeCoder generates a complex post operation (OpenAPI 2 wit
   response: ResponseBuilderFactory<{
     200: {
       headers: {};
-      content: {};
+      content: {
+        \\"application/json\\": {
+          schema: Type;
+        };
+      };
     };
     400: {
       headers: {};
-      content: {};
+      content: {
+        \\"application/json\\": {
+          schema: Type;
+        };
+      };
     };
     [statusCode in Exclude<HttpStatusCode, 200 | 400>]: {
       headers: {};
-      content: {};
+      content: {
+        \\"application/json\\": {
+          schema: Type;
+        };
+      };
     };
   }>;
   proxy: (url: string) => { proxyUrl: string };
Repository: pmcelhaney/counterfact
Pull request #504 (2023-08-17 17:00:27)

fix a bug where random() doesn't work when produces is in the root


Patch:
diff --git a/.changeset/silly-spiders-invite.md b/.changeset/silly-spiders-invite.md
new file mode 100644
index 0000000..8fef177
--- /dev/null
+++ b/.changeset/silly-spiders-invite.md
@@ -0,0 +1,5 @@
+---
+"counterfact": patch
+---
+
+fix an issue where the random() function doesn't recognize it should use OpenAPI2
diff --git a/src/server/dispatcher.js b/src/server/dispatcher.js
index 97932ed..c862dff 100644
--- a/src/server/dispatcher.js
+++ b/src/server/dispatcher.js
@@ -44,7 +44,17 @@ export class Dispatcher {
   }
 
   operationForPathAndMethod(path, method) {
-    return this.openApiDocument?.paths?.[path]?.[method.toLowerCase()];
+    const operation =
+      this.openApiDocument?.paths?.[path]?.[method.toLowerCase()];
+
+    if (this.openApiDocument?.produces) {
+      return {
+        produces: this.openApiDocument.produces,
+        ...operation,
+      };
+    }
+
+    return operation;
   }
 
   async request({ method, path, headers, body, query, req }) {


Test patch:
diff --git a/test/server/dispatcher.test.js b/test/server/dispatcher.test.js
index 540d4ee..ebce8f0 100644
--- a/test/server/dispatcher.test.js
+++ b/test/server/dispatcher.test.js
@@ -538,4 +538,25 @@ describe("given an invalid path", () => {
       "Could not find a PUT method matching /your/left/foot/in/and/your/right/foot/out\n"
     );
   });
+
+  it("attaches the root produces array to an operation", () => {
+    const registry = new Registry();
+
+    registry.add("/your/{side}/{bodyPart}/in/and/your/left/foot/out", {
+      PUT() {
+        return {
+          status: 201,
+          body: "ok",
+        };
+      },
+    });
+
+    const dispatcher = new Dispatcher(registry, new ContextRegistry(), {
+      produces: ["text/plain"],
+    });
+
+    const operation = dispatcher.operationForPathAndMethod("/hello", "GET");
+
+    expect(operation.produces).toStrictEqual(["text/plain"]);
+  });
 });