[monorepo] lint .mts/.cts files (#37001)

* [monorepo] lint .mts/.cts files

ESLint's `files` globs listed `{js,jsx,mjs,cjs,ts,tsx}` but never the
module-scoped TypeScript extensions, so every `.mts` file in the repo was
silently skipped with "File ignored because no matching configuration was
supplied" -- 21 files today, all in services/web, and more as backend code
migrates to TypeScript (`.mts` is the extension runtime-loaded backend TS
has to use, since services/web has no `"type": "module"`).

Each extension list now carries the c/m variants of the languages it
already allowed, canonicalised to one of:

    {js,cjs,mjs}                      JS only
    {js,cjs,mjs,jsx}                  JS + JSX
    {js,cjs,mjs,ts,cts,mts}           JS + TS, no JSX
    {ts,cts,mts,tsx}                  TS only
    {js,cjs,mjs,jsx,ts,cts,mts,tsx}   everything

No list gains a language it did not already have, and none gains JSX
where it was previously excluded, so backend globs keep excluding
jsx/tsx and TS-only rule blocks keep excluding JS.

Both the extension declaration and the plugin/parser block in
services/web/eslint.config.mjs are widened together: widening only the
rule blocks makes `@overleaf/*` rules match files the plugin
registration does not, which fails with "could not find plugin
@overleaf".

The root global-ignores shim (`services/**/*.{mjs,cjs,ts,tsx}` and
friends) is deliberately left alone -- it replicates ESLint v8's file
walker so pre-existing debt in never-linted files stays off the build.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Fix eslint errors

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
GitOrigin-RevId: 084d0d054db9db6b5e3dd26de56d14358ab5edf7
This commit is contained in:
Antoine Clausse
2026-09-17 12:07:47 +00:00
committed by Copybot
co-authored by Claude Opus 5
parent a234c3cb27
commit 943edd29f3
3 changed files with 26 additions and 24 deletions
@@ -1,3 +1,5 @@
/* eslint-disable no-console */
import fs from 'node:fs/promises'
import { createWriteStream } from 'node:fs'
import { basename, join } from 'node:path'
@@ -1,3 +1,5 @@
/* eslint-disable no-console */
import path from 'node:path'
import fs from 'node:fs/promises'
import icons from './unfilled-symbols.mjs'
@@ -179,7 +179,7 @@ export const elementContext = new ContextTracker({
// tokenizer for \verb|...| commands
export const verbTokenizer = new ExternalTokenizer(
(input, stack) => {
input => {
if (input.next === '*'.charCodeAt(0)) input.advance()
const delimiter = input.next
if (delimiter === -1) return // hit end of file
@@ -198,7 +198,7 @@ export const verbTokenizer = new ExternalTokenizer(
// tokenizer for \lstinline|...| commands
export const lstinlineTokenizer = new ExternalTokenizer(
(input, stack) => {
input => {
let delimiter = input.next
if (delimiter === -1) return // hit end of file
if (/\s/.test(String.fromCharCode(delimiter))) {
@@ -317,7 +317,7 @@ export const argumentListWithOptionalTokenizer = lookaheadTokenizer(next => {
const CHAR_AT_SYMBOL = _char('@')
export const csnameTokenizer = new ExternalTokenizer((input, stack) => {
export const csnameTokenizer = new ExternalTokenizer(input => {
let offset = 0
let end = -1
// look at the first character, we are looking for acceptable control sequence names
@@ -349,26 +349,24 @@ export const csnameTokenizer = new ExternalTokenizer((input, stack) => {
const END_DOCUMENT_MARK = '\\end{document}'.split('').reverse()
export const trailingContentTokenizer = new ExternalTokenizer(
(input, stack) => {
if (input.next === -1) return // no trailing content
// Look back for end-document mark, bail out if any characters do not match
for (let i = 1; i < END_DOCUMENT_MARK.length + 1; i++) {
if (String.fromCharCode(input.peek(-i)) !== END_DOCUMENT_MARK[i - 1]) {
return
}
export const trailingContentTokenizer = new ExternalTokenizer(input => {
if (input.next === -1) return // no trailing content
// Look back for end-document mark, bail out if any characters do not match
for (let i = 1; i < END_DOCUMENT_MARK.length + 1; i++) {
if (String.fromCharCode(input.peek(-i)) !== END_DOCUMENT_MARK[i - 1]) {
return
}
while (input.next === CHAR_SPACE || input.next === CHAR_NEWLINE) {
const next = input.advance()
if (next === -1) return input.acceptToken(TrailingWhitespaceOnly) // trailing whitespace only
}
// accept the all content up to the end of the document
while (input.advance() !== -1) {
//
}
return input.acceptToken(TrailingContent)
}
)
while (input.next === CHAR_SPACE || input.next === CHAR_NEWLINE) {
const next = input.advance()
if (next === -1) return input.acceptToken(TrailingWhitespaceOnly) // trailing whitespace only
}
// accept the all content up to the end of the document
while (input.advance() !== -1) {
//
}
return input.acceptToken(TrailingContent)
})
const refCommands = new Set([
'\\fullref',
@@ -616,7 +614,7 @@ const otherKnowncommands = {
}
// specializer for control sequences
// return new tokens for specific control sequences
export const specializeCtrlSeq = (name, terms) => {
export const specializeCtrlSeq = name => {
if (name === '\\begin') return Begin
if (name === '\\end') return End
if (refCommands.has(name)) {
@@ -728,7 +726,7 @@ const otherKnownEnvNames = {
description: ListEnvName,
}
export const specializeEnvName = (name, terms) => {
export const specializeEnvName = name => {
if (tabularEnvNames.has(name)) {
return TabularEnvName
}
@@ -752,6 +750,6 @@ const otherKnownCtrlSyms = {
'\\\\': LineBreakCtrlSym,
}
export const specializeCtrlSym = (name, terms) => {
export const specializeCtrlSym = name => {
return otherKnownCtrlSyms[name] || -1
}