<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: faissalrez</title>
    <description>The latest articles on DEV Community by faissalrez (@faissalrez).</description>
    <link>https://dev.to/faissalrez</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4232954%2F31e35978-16e7-452a-99f4-4a8d7677ee93.png</url>
      <title>DEV Community: faissalrez</title>
      <link>https://dev.to/faissalrez</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/faissalrez"/>
    <language>en</language>
    <item>
      <title>Show svelte-check's errors in your GitLab merge requests (and GitHub pull requests)</title>
      <dc:creator>faissalrez</dc:creator>
      <pubDate>Sun, 08 Nov 2026 01:09:17 +0000</pubDate>
      <link>https://dev.to/faissalrez/show-svelte-checks-errors-in-your-gitlab-merge-requests-and-github-pull-requests-1akg</link>
      <guid>https://dev.to/faissalrez/show-svelte-checks-errors-in-your-gitlab-merge-requests-and-github-pull-requests-1akg</guid>
      <description>&lt;p&gt;If your SvelteKit project runs &lt;code&gt;svelte-check&lt;/code&gt; in CI, you've probably seen this: the job fails, and the type errors are somewhere in the job log. Reviewers have to open the log, scroll, and map each line back to the diff. Meanwhile, ESLint's errors show up right in the merge request, because ESLint has formatters for GitLab and GitHub.&lt;/p&gt;

&lt;p&gt;svelte-check doesn't, and that's on purpose: its maintainers &lt;a href="https://github.com/sveltejs/language-tools/issues/2487" rel="noopener noreferrer"&gt;prefer not to add output formats&lt;/a&gt;, and point to its machine-readable output instead. So I wrote the conversion: &lt;a href="https://github.com/faissalrez/svelte-check-reporter" rel="noopener noreferrer"&gt;svelte-check-reporter&lt;/a&gt;. This post explains how it works, and the parts that weren't obvious.&lt;/p&gt;

&lt;h2&gt;
  
  
  What svelte-check gives you
&lt;/h2&gt;

&lt;p&gt;With &lt;code&gt;--output machine-verbose&lt;/code&gt;, svelte-check prints one JSON diagnostic per line, after a timestamp:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1762500000000 START "/builds/my-app"
1762500001000 {"type":"ERROR","filename":"src/lib/cart.ts","start":{"line":3,"character":56},"end":{"line":3,"character":61},"message":"Property 'prise' does not exist on type 'Product'. Did you mean 'price'?","code":2551}
1762500001000 COMPLETED 12 FILES 1 ERRORS 0 WARNINGS 1 FILES_WITH_PROBLEMS
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Everything a report needs is there: the file, the range, the message, the code, and whether it's an error or a warning.&lt;/p&gt;

&lt;h2&gt;
  
  
  GitLab: a Code Quality report
&lt;/h2&gt;

&lt;p&gt;GitLab shows problems in a merge request from a &lt;a href="https://docs.gitlab.com/ci/testing/code_quality/" rel="noopener noreferrer"&gt;Code Quality report&lt;/a&gt;, a JSON file that a job declares as an artifact:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;check&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;node:24-alpine&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;npm ci&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;npx svelte-kit sync&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;npx svelte-check --output machine-verbose | npx svelte-check-reporter --output-file gl-codequality.json&lt;/span&gt;
  &lt;span class="na"&gt;artifacts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;
    &lt;span class="na"&gt;reports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;codequality&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gl-codequality.json&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;GitLab compares the merge request's report with the target branch's. The widget then lists only the problems the merge request adds, and the ones it fixes:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fb84lc7lrfekvycw65ucy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fb84lc7lrfekvycw65ucy.png" alt="The Code Quality widget of a GitLab merge request: 3 new findings and 1 fixed finding" width="800" height="440"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And the Changes tab marks each new problem in the margin of the diff:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxdk2868h42spin1gl94u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxdk2868h42spin1gl94u.png" alt="Code Quality markers in a GitLab merge request's diff, with one finding opened" width="800" height="537"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Two details in that job matter:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;when: always&lt;/code&gt;: the job fails when svelte-check finds errors, which is exactly when you want the report uploaded.&lt;/li&gt;
&lt;li&gt;The job must also run on the target branch. Without a report there, GitLab has nothing to compare with.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The tricky part: the fingerprint
&lt;/h2&gt;

&lt;p&gt;To tell new problems from existing ones, GitLab matches them across pipelines by a &lt;code&gt;fingerprint&lt;/code&gt; field. It's up to the report to compute it, and the obvious choice is wrong.&lt;/p&gt;

&lt;p&gt;If the fingerprint includes the line number, adding one line at the top of a file changes the fingerprint of every error below it. GitLab then reports all of them as new, and all the old ones as fixed. On a project with existing errors, every merge request would look like it broke everything.&lt;/p&gt;

&lt;p&gt;So the fingerprint is a hash of the file, the error code and the message, without the line. That raises the opposite problem: two identical errors in the same file, say the same typo twice, would get the same fingerprint. They're told apart by their order in the file: the first one is #1, the second #2. Moving code around doesn't change that order, unless you swap two identical errors, which doesn't matter.&lt;/p&gt;

&lt;p&gt;This is the same approach as &lt;a href="https://github.com/remcohaszing/eslint-formatter-codeclimate" rel="noopener noreferrer"&gt;eslint-formatter-codeclimate&lt;/a&gt;, and it's what makes the widget useful on a real project. One more detail: the reporter can prefix messages (&lt;code&gt;--prefix '[svelte-check] '&lt;/code&gt;) to tell them apart from other tools' in the widget, and the prefix isn't part of the fingerprint, so adding it later doesn't mark everything as new.&lt;/p&gt;

&lt;h2&gt;
  
  
  GitHub: annotations or code scanning
&lt;/h2&gt;

&lt;p&gt;On GitHub, there are two ways to put errors on a pull request's diff.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Annotations&lt;/strong&gt; need nothing but the command, in any repository:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npx svelte-check --output machine-verbose | npx svelte-check-reporter --format github&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fll8xudqisayxr2sj95c5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fll8xudqisayxr2sj95c5.png" alt="A Svelte warning and a type error annotated on a GitHub pull request's diff" width="800" height="446"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;They have two limits: GitHub doesn't compare them with the base branch, so existing errors are annotated too, and it shows at most &lt;a href="https://docs.github.com/en/rest/checks/runs#create-a-check-run" rel="noopener noreferrer"&gt;10 error and 10 warning annotations per step&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Code scanning&lt;/strong&gt; takes a SARIF file, uploaded with &lt;code&gt;github/codeql-action/upload-sarif&lt;/code&gt; and the &lt;code&gt;security-events: write&lt;/code&gt; permission. It compares each pull request with the base branch, so it only comments on the problems a pull request adds, without a limit:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyswz7wbhww6z6sjn8j23.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyswz7wbhww6z6sjn8j23.png" alt="A code scanning comment on a type error in a GitHub pull request" width="800" height="282"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Pick one: both put problems on the same lines, so using both shows each one twice. The &lt;a href="https://github.com/faissalrez/svelte-check-reporter#github-code-scanning" rel="noopener noreferrer"&gt;README&lt;/a&gt; has the full workflow, including the push to &lt;code&gt;main&lt;/code&gt; that gives code scanning its baseline.&lt;/p&gt;

&lt;h2&gt;
  
  
  Small things that bit me
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Lines are 0-based&lt;/strong&gt; in &lt;code&gt;machine-verbose&lt;/code&gt;, unlike &lt;code&gt;--output machine&lt;/code&gt;, which is 1-based. GitLab, GitHub and SARIF all expect 1-based lines. The svelte-check team &lt;a href="https://github.com/sveltejs/language-tools/issues/2830" rel="noopener noreferrer"&gt;won't change it&lt;/a&gt;, since it would break existing tools.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;An empty report can lie.&lt;/strong&gt; If svelte-check crashes, there's no &lt;code&gt;COMPLETED&lt;/code&gt; line, and converting what's there gives an empty report: a clean-looking merge request. The reporter fails instead.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Warnings don't fail the job&lt;/strong&gt;, as with svelte-check: only errors do.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save-dev&lt;/span&gt; svelte-check-reporter
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;a href="https://github.com/faissalrez/svelte-check-reporter" rel="noopener noreferrer"&gt;README&lt;/a&gt; has the setup for each integration, and the demo project shows the result in real &lt;a href="https://github.com/faissalrez/svelte-check-reporter-demo/pulls" rel="noopener noreferrer"&gt;GitHub pull requests&lt;/a&gt; and a &lt;a href="https://gitlab.com/faissalrez/svelte-check-reporter-demo/-/merge_requests/1" rel="noopener noreferrer"&gt;GitLab merge request&lt;/a&gt;. Feedback and issues are welcome.&lt;/p&gt;

</description>
      <category>svelte</category>
      <category>gitlab</category>
      <category>ci</category>
      <category>typescript</category>
    </item>
  </channel>
</rss>
