Przeglądaj źródła

[monorepo] turn throw statements in callback code into callback calls (#33524)

* [eslint-plugin] add rule for throw inside callback code

* [monorepo] enable our custom eslint plugins globally

* [monorepo] fix running make lint from root

* [monorepo] turn throw statements in callback code into callback calls

* [monorepo] add eslint-plugin libraries to all the Dockerfiles

* [monorepo] install eslint-plugin library at the root level

* [linked-url-proxy] add eslint-plugin library into Dockerfile

* [latexqc] add our eslint-plugin to eslint config

GitOrigin-RevId: b05e3ebbefb62370f2422e83880dd3913815270d
Jakob Ackermann 3 miesięcy temu
rodzic
commit
b62d4814c3

+ 1 - 0
libraries/eslint-plugin/index.js

@@ -8,5 +8,6 @@ module.exports = {
     'require-vi-doMock-valid-path': require('./require-vi-doMock-valid-path'),
     'require-loading-label': require('./require-loading-label'),
     'require-cio-snake-case-properties': require('./require-cio-snake-case-properties'),
+    'no-throw-in-callback': require('./no-throw-in-callback'),
   },
 }

+ 52 - 0
libraries/eslint-plugin/no-throw-in-callback.js

@@ -0,0 +1,52 @@
+const CALLBACK_PARAM_NAMES = new Set(['cb', 'callback', 'done', 'next'])
+
+function isCallbackParam(param) {
+  return (
+    param && param.type === 'Identifier' && CALLBACK_PARAM_NAMES.has(param.name)
+  )
+}
+
+module.exports = {
+  meta: {
+    type: 'error',
+    docs: {
+      description: 'Disallow throw statements inside callback-based functions',
+    },
+    messages: {
+      noThrowInCallback:
+        'Pass the error to the callback instead of throwing in callback-based code.',
+    },
+  },
+  create(context) {
+    // Stack tracks whether each enclosing function is a callback-style function.
+    // A callback-style function is non-async and has a last param named cb/callback/done/next.
+    const stack = []
+
+    function enterFunction(node) {
+      const params = node.params
+      const isCallback =
+        !node.async &&
+        params.length > 0 &&
+        isCallbackParam(params[params.length - 1])
+      stack.push(isCallback)
+    }
+
+    function exitFunction() {
+      stack.pop()
+    }
+
+    return {
+      FunctionDeclaration: enterFunction,
+      'FunctionDeclaration:exit': exitFunction,
+      FunctionExpression: enterFunction,
+      'FunctionExpression:exit': exitFunction,
+      ArrowFunctionExpression: enterFunction,
+      'ArrowFunctionExpression:exit': exitFunction,
+      ThrowStatement(node) {
+        if (stack[stack.length - 1]) {
+          context.report({ node, messageId: 'noThrowInCallback' })
+        }
+      },
+    }
+  },
+}

+ 51 - 0
libraries/eslint-plugin/rules.test.js

@@ -1,4 +1,5 @@
 const { RuleTester } = require('eslint')
+const noThrowInCallback = require('./no-throw-in-callback')
 const preferKebabUrl = require('./prefer-kebab-url')
 const noUnnecessaryTrans = require('./no-unnecessary-trans')
 const shouldUnescapeTrans = require('./should-unescape-trans')
@@ -267,3 +268,53 @@ ruleTester.run(
     ],
   }
 )
+
+const noThrowInCallbackMessage =
+  'Pass the error to the callback instead of throwing in callback-based code.'
+ruleTester.run('no-throw-in-callback', noThrowInCallback, {
+  valid: [
+    // Calling the callback with an error is fine
+    { code: `function foo(cb) { cb(new Error()) }` },
+    // async functions may throw (they return a rejected promise)
+    { code: `async function foo(cb) { throw new Error() }` },
+    // Last param not a callback name — not a callback-style function
+    { code: `function foo(data) { throw new Error() }` },
+    // No params at all
+    { code: `function foo() { throw new Error() }` },
+    // throw inside a nested non-callback function is fine
+    { code: `function foo(cb) { [1].map(function() { throw new Error() }) }` },
+    // throw inside a nested async arrow is fine
+    { code: `function foo(cb) { [1].map(async () => { throw new Error() }) }` },
+  ],
+  invalid: [
+    {
+      code: `function foo(cb) { throw new Error() }`,
+      errors: [{ message: noThrowInCallbackMessage }],
+    },
+    {
+      code: `function foo(callback) { throw new Error() }`,
+      errors: [{ message: noThrowInCallbackMessage }],
+    },
+    {
+      code: `function foo(done) { throw new Error() }`,
+      errors: [{ message: noThrowInCallbackMessage }],
+    },
+    {
+      code: `function foo(next) { throw new Error() }`,
+      errors: [{ message: noThrowInCallbackMessage }],
+    },
+    {
+      code: `function foo(data, cb) { throw new Error() }`,
+      errors: [{ message: noThrowInCallbackMessage }],
+    },
+    {
+      code: `const foo = (cb) => { throw new Error() }`,
+      errors: [{ message: noThrowInCallbackMessage }],
+    },
+    // throw in a nested callback-style function inside another callback function
+    {
+      code: `function foo(cb) { bar(function(done) { throw new Error() }) }`,
+      errors: [{ message: noThrowInCallbackMessage }],
+    },
+  ],
+})

+ 1 - 0
package.json

@@ -3,6 +3,7 @@
   "private": true,
   "packageManager": "yarn@4.14.1",
   "devDependencies": {
+    "@overleaf/eslint-plugin": "workspace:*",
     "@prettier/plugin-pug": "^3.4.0",
     "@types/chai": "^4.3.0",
     "@types/chai-as-promised": "^7.1.8",

+ 2 - 0
services/chat/Dockerfile

@@ -19,6 +19,7 @@ RUN mkdir /home/node/.config && chown node:node /home/node/.config
 FROM base AS app
 
 COPY package.json yarn.lock .yarnrc.yml /overleaf/
+COPY libraries/eslint-plugin/package.json /overleaf/libraries/eslint-plugin/package.json
 COPY libraries/fetch-utils/package.json /overleaf/libraries/fetch-utils/package.json
 COPY libraries/logger/package.json /overleaf/libraries/logger/package.json
 COPY libraries/metrics/package.json /overleaf/libraries/metrics/package.json
@@ -32,6 +33,7 @@ COPY .yarn/patches/ /overleaf/.yarn/patches/
 COPY tools/migrations/ /overleaf/tools/migrations/
 
 RUN cd /overleaf && yarn workspaces focus @overleaf/chat overleaf
+COPY libraries/eslint-plugin/ /overleaf/libraries/eslint-plugin/
 COPY libraries/fetch-utils/ /overleaf/libraries/fetch-utils/
 COPY libraries/logger/ /overleaf/libraries/logger/
 COPY libraries/metrics/ /overleaf/libraries/metrics/

+ 1 - 0
services/chat/Makefile

@@ -16,6 +16,7 @@ IMAGE_REPO_FINAL ?= $(IMAGE_REPO):$(BRANCH_NAME_TAG_SAFE)-$(BUILD_NUMBER)
 IMAGE_CACHE ?= $(IMAGE_REPO):cache-$(shell cat \
 	$(MONOREPO)/package.json \
 	$(MONOREPO)/yarn.lock \
+	$(MONOREPO)/libraries/eslint-plugin/package.json \
 	$(MONOREPO)/libraries/fetch-utils/package.json \
 	$(MONOREPO)/libraries/logger/package.json \
 	$(MONOREPO)/libraries/metrics/package.json \

+ 2 - 0
services/clsi/Dockerfile

@@ -23,6 +23,7 @@ RUN mkdir /home/node/.config && chown node:node /home/node/.config
 FROM base AS app
 
 COPY package.json yarn.lock .yarnrc.yml /overleaf/
+COPY libraries/eslint-plugin/package.json /overleaf/libraries/eslint-plugin/package.json
 COPY libraries/fetch-utils/package.json /overleaf/libraries/fetch-utils/package.json
 COPY libraries/logger/package.json /overleaf/libraries/logger/package.json
 COPY libraries/metrics/package.json /overleaf/libraries/metrics/package.json
@@ -35,6 +36,7 @@ COPY services/clsi/package.json /overleaf/services/clsi/package.json
 COPY .yarn/patches/ /overleaf/.yarn/patches/
 
 RUN cd /overleaf && yarn workspaces focus @overleaf/clsi overleaf
+COPY libraries/eslint-plugin/ /overleaf/libraries/eslint-plugin/
 COPY libraries/fetch-utils/ /overleaf/libraries/fetch-utils/
 COPY libraries/logger/ /overleaf/libraries/logger/
 COPY libraries/metrics/ /overleaf/libraries/metrics/

+ 1 - 0
services/clsi/Makefile

@@ -16,6 +16,7 @@ IMAGE_REPO_FINAL ?= $(IMAGE_REPO):$(BRANCH_NAME_TAG_SAFE)-$(BUILD_NUMBER)
 IMAGE_CACHE ?= $(IMAGE_REPO):cache-$(shell cat \
 	$(MONOREPO)/package.json \
 	$(MONOREPO)/yarn.lock \
+	$(MONOREPO)/libraries/eslint-plugin/package.json \
 	$(MONOREPO)/libraries/fetch-utils/package.json \
 	$(MONOREPO)/libraries/logger/package.json \
 	$(MONOREPO)/libraries/metrics/package.json \

+ 2 - 0
services/contacts/Dockerfile

@@ -19,6 +19,7 @@ RUN mkdir /home/node/.config && chown node:node /home/node/.config
 FROM base AS app
 
 COPY package.json yarn.lock .yarnrc.yml /overleaf/
+COPY libraries/eslint-plugin/package.json /overleaf/libraries/eslint-plugin/package.json
 COPY libraries/fetch-utils/package.json /overleaf/libraries/fetch-utils/package.json
 COPY libraries/logger/package.json /overleaf/libraries/logger/package.json
 COPY libraries/metrics/package.json /overleaf/libraries/metrics/package.json
@@ -32,6 +33,7 @@ COPY .yarn/patches/ /overleaf/.yarn/patches/
 COPY tools/migrations/ /overleaf/tools/migrations/
 
 RUN cd /overleaf && yarn workspaces focus @overleaf/contacts overleaf
+COPY libraries/eslint-plugin/ /overleaf/libraries/eslint-plugin/
 COPY libraries/fetch-utils/ /overleaf/libraries/fetch-utils/
 COPY libraries/logger/ /overleaf/libraries/logger/
 COPY libraries/metrics/ /overleaf/libraries/metrics/

+ 1 - 0
services/contacts/Makefile

@@ -16,6 +16,7 @@ IMAGE_REPO_FINAL ?= $(IMAGE_REPO):$(BRANCH_NAME_TAG_SAFE)-$(BUILD_NUMBER)
 IMAGE_CACHE ?= $(IMAGE_REPO):cache-$(shell cat \
 	$(MONOREPO)/package.json \
 	$(MONOREPO)/yarn.lock \
+	$(MONOREPO)/libraries/eslint-plugin/package.json \
 	$(MONOREPO)/libraries/fetch-utils/package.json \
 	$(MONOREPO)/libraries/logger/package.json \
 	$(MONOREPO)/libraries/metrics/package.json \

+ 2 - 0
services/docstore/Dockerfile

@@ -19,6 +19,7 @@ RUN mkdir /home/node/.config && chown node:node /home/node/.config
 FROM base AS app
 
 COPY package.json yarn.lock .yarnrc.yml /overleaf/
+COPY libraries/eslint-plugin/package.json /overleaf/libraries/eslint-plugin/package.json
 COPY libraries/fetch-utils/package.json /overleaf/libraries/fetch-utils/package.json
 COPY libraries/logger/package.json /overleaf/libraries/logger/package.json
 COPY libraries/metrics/package.json /overleaf/libraries/metrics/package.json
@@ -34,6 +35,7 @@ COPY .yarn/patches/ /overleaf/.yarn/patches/
 COPY tools/migrations/ /overleaf/tools/migrations/
 
 RUN cd /overleaf && yarn workspaces focus @overleaf/docstore overleaf
+COPY libraries/eslint-plugin/ /overleaf/libraries/eslint-plugin/
 COPY libraries/fetch-utils/ /overleaf/libraries/fetch-utils/
 COPY libraries/logger/ /overleaf/libraries/logger/
 COPY libraries/metrics/ /overleaf/libraries/metrics/

+ 1 - 0
services/docstore/Makefile

@@ -16,6 +16,7 @@ IMAGE_REPO_FINAL ?= $(IMAGE_REPO):$(BRANCH_NAME_TAG_SAFE)-$(BUILD_NUMBER)
 IMAGE_CACHE ?= $(IMAGE_REPO):cache-$(shell cat \
 	$(MONOREPO)/package.json \
 	$(MONOREPO)/yarn.lock \
+	$(MONOREPO)/libraries/eslint-plugin/package.json \
 	$(MONOREPO)/libraries/fetch-utils/package.json \
 	$(MONOREPO)/libraries/logger/package.json \
 	$(MONOREPO)/libraries/metrics/package.json \

+ 2 - 0
services/document-updater/Dockerfile

@@ -19,6 +19,7 @@ RUN mkdir /home/node/.config && chown node:node /home/node/.config
 FROM base AS app
 
 COPY package.json yarn.lock .yarnrc.yml /overleaf/
+COPY libraries/eslint-plugin/package.json /overleaf/libraries/eslint-plugin/package.json
 COPY libraries/fetch-utils/package.json /overleaf/libraries/fetch-utils/package.json
 COPY libraries/logger/package.json /overleaf/libraries/logger/package.json
 COPY libraries/metrics/package.json /overleaf/libraries/metrics/package.json
@@ -35,6 +36,7 @@ COPY .yarn/patches/ /overleaf/.yarn/patches/
 COPY tools/migrations/ /overleaf/tools/migrations/
 
 RUN cd /overleaf && yarn workspaces focus @overleaf/document-updater overleaf
+COPY libraries/eslint-plugin/ /overleaf/libraries/eslint-plugin/
 COPY libraries/fetch-utils/ /overleaf/libraries/fetch-utils/
 COPY libraries/logger/ /overleaf/libraries/logger/
 COPY libraries/metrics/ /overleaf/libraries/metrics/

+ 1 - 0
services/document-updater/Makefile

@@ -16,6 +16,7 @@ IMAGE_REPO_FINAL ?= $(IMAGE_REPO):$(BRANCH_NAME_TAG_SAFE)-$(BUILD_NUMBER)
 IMAGE_CACHE ?= $(IMAGE_REPO):cache-$(shell cat \
 	$(MONOREPO)/package.json \
 	$(MONOREPO)/yarn.lock \
+	$(MONOREPO)/libraries/eslint-plugin/package.json \
 	$(MONOREPO)/libraries/fetch-utils/package.json \
 	$(MONOREPO)/libraries/logger/package.json \
 	$(MONOREPO)/libraries/metrics/package.json \

+ 4 - 4
services/document-updater/app/js/sharejs/server/model.js

@@ -631,14 +631,14 @@ module.exports = Model = function (db, options) {
   // after.
   this.getOps = getOps = function (docName, start, end, callback) {
     // getOps will only use the op cache if its there. It won't fill the op cache in.
-    if (!(start >= 0)) {
-      throw new Error('start must be 0+')
-    }
-
     if (typeof end === 'function') {
       ;[end, callback] = Array.from([null, end])
     }
 
+    if (!(start >= 0)) {
+      return callback(new Error('start must be 0+'))
+    }
+
     const ops = docs[docName] != null ? docs[docName].ops : undefined
 
     if (ops) {

+ 3 - 3
services/document-updater/app/js/sharejs/types/json-api.js

@@ -158,7 +158,7 @@ json.api = {
         op.od = elem[key]
       }
     } else {
-      throw new Error('bad path')
+      return cb(new Error('bad path'))
     }
     return this.submitOp([op], cb)
   },
@@ -166,7 +166,7 @@ json.api = {
   removeAt(path, cb) {
     const { elem, key } = traverse(this.snapshot, path)
     if (typeof elem[key] === 'undefined') {
-      throw new Error('no element at that path')
+      return cb(new Error('no element at that path'))
     }
     const op = { p: path }
     if (elem.constructor === Array) {
@@ -174,7 +174,7 @@ json.api = {
     } else if (typeof elem === 'object') {
       op.od = elem[key]
     } else {
-      throw new Error('bad path')
+      return cb(new Error('bad path'))
     }
     return this.submitOp([op], cb)
   },

+ 4 - 4
services/document-updater/app/js/sharejs/types/model.js

@@ -618,14 +618,14 @@ module.exports = Model = function (db, options) {
   // after.
   this.getOps = getOps = function (docName, start, end, callback) {
     // getOps will only use the op cache if its there. It won't fill the op cache in.
-    if (!(start >= 0)) {
-      throw new Error('start must be 0+')
-    }
-
     if (typeof end === 'function') {
       ;[end, callback] = Array.from([null, end])
     }
 
+    if (!(start >= 0)) {
+      return callback(new Error('start must be 0+'))
+    }
+
     const ops = docs[docName] != null ? docs[docName].ops : undefined
 
     if (ops) {

+ 2 - 0
services/filestore/Dockerfile

@@ -21,6 +21,7 @@ RUN mkdir /home/node/.config && chown node:node /home/node/.config
 FROM base AS app
 
 COPY package.json yarn.lock .yarnrc.yml /overleaf/
+COPY libraries/eslint-plugin/package.json /overleaf/libraries/eslint-plugin/package.json
 COPY libraries/fetch-utils/package.json /overleaf/libraries/fetch-utils/package.json
 COPY libraries/logger/package.json /overleaf/libraries/logger/package.json
 COPY libraries/metrics/package.json /overleaf/libraries/metrics/package.json
@@ -32,6 +33,7 @@ COPY services/filestore/package.json /overleaf/services/filestore/package.json
 COPY .yarn/patches/ /overleaf/.yarn/patches/
 
 RUN cd /overleaf && yarn workspaces focus @overleaf/filestore overleaf
+COPY libraries/eslint-plugin/ /overleaf/libraries/eslint-plugin/
 COPY libraries/fetch-utils/ /overleaf/libraries/fetch-utils/
 COPY libraries/logger/ /overleaf/libraries/logger/
 COPY libraries/metrics/ /overleaf/libraries/metrics/

+ 1 - 0
services/filestore/Makefile

@@ -16,6 +16,7 @@ IMAGE_REPO_FINAL ?= $(IMAGE_REPO):$(BRANCH_NAME_TAG_SAFE)-$(BUILD_NUMBER)
 IMAGE_CACHE ?= $(IMAGE_REPO):cache-$(shell cat \
 	$(MONOREPO)/package.json \
 	$(MONOREPO)/yarn.lock \
+	$(MONOREPO)/libraries/eslint-plugin/package.json \
 	$(MONOREPO)/libraries/fetch-utils/package.json \
 	$(MONOREPO)/libraries/logger/package.json \
 	$(MONOREPO)/libraries/metrics/package.json \

+ 2 - 0
services/history-v1/Dockerfile

@@ -24,6 +24,7 @@ RUN mkdir /buckets && chown node:node /buckets
 FROM base AS app
 
 COPY package.json yarn.lock .yarnrc.yml /overleaf/
+COPY libraries/eslint-plugin/package.json /overleaf/libraries/eslint-plugin/package.json
 COPY libraries/fetch-utils/package.json /overleaf/libraries/fetch-utils/package.json
 COPY libraries/logger/package.json /overleaf/libraries/logger/package.json
 COPY libraries/metrics/package.json /overleaf/libraries/metrics/package.json
@@ -42,6 +43,7 @@ COPY .yarn/patches/ /overleaf/.yarn/patches/
 COPY tools/migrations/ /overleaf/tools/migrations/
 
 RUN cd /overleaf && yarn workspaces focus overleaf-editor overleaf
+COPY libraries/eslint-plugin/ /overleaf/libraries/eslint-plugin/
 COPY libraries/fetch-utils/ /overleaf/libraries/fetch-utils/
 COPY libraries/logger/ /overleaf/libraries/logger/
 COPY libraries/metrics/ /overleaf/libraries/metrics/

+ 1 - 0
services/history-v1/Makefile

@@ -16,6 +16,7 @@ IMAGE_REPO_FINAL ?= $(IMAGE_REPO):$(BRANCH_NAME_TAG_SAFE)-$(BUILD_NUMBER)
 IMAGE_CACHE ?= $(IMAGE_REPO):cache-$(shell cat \
 	$(MONOREPO)/package.json \
 	$(MONOREPO)/yarn.lock \
+	$(MONOREPO)/libraries/eslint-plugin/package.json \
 	$(MONOREPO)/libraries/fetch-utils/package.json \
 	$(MONOREPO)/libraries/logger/package.json \
 	$(MONOREPO)/libraries/metrics/package.json \

+ 2 - 0
services/notifications/Dockerfile

@@ -19,6 +19,7 @@ RUN mkdir /home/node/.config && chown node:node /home/node/.config
 FROM base AS app
 
 COPY package.json yarn.lock .yarnrc.yml /overleaf/
+COPY libraries/eslint-plugin/package.json /overleaf/libraries/eslint-plugin/package.json
 COPY libraries/fetch-utils/package.json /overleaf/libraries/fetch-utils/package.json
 COPY libraries/logger/package.json /overleaf/libraries/logger/package.json
 COPY libraries/metrics/package.json /overleaf/libraries/metrics/package.json
@@ -33,6 +34,7 @@ COPY .yarn/patches/ /overleaf/.yarn/patches/
 COPY tools/migrations/ /overleaf/tools/migrations/
 
 RUN cd /overleaf && yarn workspaces focus @overleaf/notifications overleaf
+COPY libraries/eslint-plugin/ /overleaf/libraries/eslint-plugin/
 COPY libraries/fetch-utils/ /overleaf/libraries/fetch-utils/
 COPY libraries/logger/ /overleaf/libraries/logger/
 COPY libraries/metrics/ /overleaf/libraries/metrics/

+ 1 - 0
services/notifications/Makefile

@@ -16,6 +16,7 @@ IMAGE_REPO_FINAL ?= $(IMAGE_REPO):$(BRANCH_NAME_TAG_SAFE)-$(BUILD_NUMBER)
 IMAGE_CACHE ?= $(IMAGE_REPO):cache-$(shell cat \
 	$(MONOREPO)/package.json \
 	$(MONOREPO)/yarn.lock \
+	$(MONOREPO)/libraries/eslint-plugin/package.json \
 	$(MONOREPO)/libraries/fetch-utils/package.json \
 	$(MONOREPO)/libraries/logger/package.json \
 	$(MONOREPO)/libraries/metrics/package.json \

+ 2 - 0
services/project-history/Dockerfile

@@ -19,6 +19,7 @@ RUN mkdir /home/node/.config && chown node:node /home/node/.config
 FROM base AS app
 
 COPY package.json yarn.lock .yarnrc.yml /overleaf/
+COPY libraries/eslint-plugin/package.json /overleaf/libraries/eslint-plugin/package.json
 COPY libraries/fetch-utils/package.json /overleaf/libraries/fetch-utils/package.json
 COPY libraries/logger/package.json /overleaf/libraries/logger/package.json
 COPY libraries/metrics/package.json /overleaf/libraries/metrics/package.json
@@ -36,6 +37,7 @@ COPY .yarn/patches/ /overleaf/.yarn/patches/
 COPY tools/migrations/ /overleaf/tools/migrations/
 
 RUN cd /overleaf && yarn workspaces focus @overleaf/project-history overleaf
+COPY libraries/eslint-plugin/ /overleaf/libraries/eslint-plugin/
 COPY libraries/fetch-utils/ /overleaf/libraries/fetch-utils/
 COPY libraries/logger/ /overleaf/libraries/logger/
 COPY libraries/metrics/ /overleaf/libraries/metrics/

+ 1 - 0
services/project-history/Makefile

@@ -16,6 +16,7 @@ IMAGE_REPO_FINAL ?= $(IMAGE_REPO):$(BRANCH_NAME_TAG_SAFE)-$(BUILD_NUMBER)
 IMAGE_CACHE ?= $(IMAGE_REPO):cache-$(shell cat \
 	$(MONOREPO)/package.json \
 	$(MONOREPO)/yarn.lock \
+	$(MONOREPO)/libraries/eslint-plugin/package.json \
 	$(MONOREPO)/libraries/fetch-utils/package.json \
 	$(MONOREPO)/libraries/logger/package.json \
 	$(MONOREPO)/libraries/metrics/package.json \

+ 1 - 1
services/project-history/app/js/DiffManager.js

@@ -77,7 +77,7 @@ export function getFileTreeDiff(projectId, fromVersion, toVersion, callback) {
           if (error instanceof Errors.InconsistentChunkError) {
             return callback(error)
           } else {
-            throw OError.tag(error)
+            return callback(OError.tag(error))
           }
         }
         callback(null, diff)

+ 2 - 0
services/real-time/Dockerfile

@@ -19,6 +19,7 @@ RUN mkdir /home/node/.config && chown node:node /home/node/.config
 FROM base AS app
 
 COPY package.json yarn.lock .yarnrc.yml /overleaf/
+COPY libraries/eslint-plugin/package.json /overleaf/libraries/eslint-plugin/package.json
 COPY libraries/fetch-utils/package.json /overleaf/libraries/fetch-utils/package.json
 COPY libraries/logger/package.json /overleaf/libraries/logger/package.json
 COPY libraries/metrics/package.json /overleaf/libraries/metrics/package.json
@@ -31,6 +32,7 @@ COPY services/real-time/package.json /overleaf/services/real-time/package.json
 COPY .yarn/patches/ /overleaf/.yarn/patches/
 
 RUN cd /overleaf && yarn workspaces focus @overleaf/real-time overleaf
+COPY libraries/eslint-plugin/ /overleaf/libraries/eslint-plugin/
 COPY libraries/fetch-utils/ /overleaf/libraries/fetch-utils/
 COPY libraries/logger/ /overleaf/libraries/logger/
 COPY libraries/metrics/ /overleaf/libraries/metrics/

+ 1 - 0
services/real-time/Makefile

@@ -16,6 +16,7 @@ IMAGE_REPO_FINAL ?= $(IMAGE_REPO):$(BRANCH_NAME_TAG_SAFE)-$(BUILD_NUMBER)
 IMAGE_CACHE ?= $(IMAGE_REPO):cache-$(shell cat \
 	$(MONOREPO)/package.json \
 	$(MONOREPO)/yarn.lock \
+	$(MONOREPO)/libraries/eslint-plugin/package.json \
 	$(MONOREPO)/libraries/fetch-utils/package.json \
 	$(MONOREPO)/libraries/logger/package.json \
 	$(MONOREPO)/libraries/metrics/package.json \

+ 0 - 1
services/web/package.json

@@ -222,7 +222,6 @@
     "@lezer/markdown": "1.6.3",
     "@overleaf/codemirror-tree-view": "^0.1.3",
     "@overleaf/dictionaries": "https://github.com/overleaf/dictionaries/archive/refs/tags/v0.0.3.tar.gz",
-    "@overleaf/eslint-plugin": "workspace:*",
     "@overleaf/ranges-tracker": "workspace:*",
     "@overleaf/stream-utils": "workspace:*",
     "@pmmmwh/react-refresh-webpack-plugin": "^0.5.16",

+ 2 - 1
yarn.lock

@@ -7259,7 +7259,6 @@ __metadata:
     "@overleaf/access-token-encryptor": "workspace:*"
     "@overleaf/codemirror-tree-view": "npm:^0.1.3"
     "@overleaf/dictionaries": "https://github.com/overleaf/dictionaries/archive/refs/tags/v0.0.3.tar.gz"
-    "@overleaf/eslint-plugin": "workspace:*"
     "@overleaf/fetch-utils": "workspace:*"
     "@overleaf/logger": "workspace:*"
     "@overleaf/metrics": "workspace:*"
@@ -22649,6 +22648,7 @@ __metadata:
     "@babel/preset-env": "npm:^7.28.5"
     "@babel/preset-react": "npm:^7.28.5"
     "@babel/register": "npm:^7.28.3"
+    "@overleaf/eslint-plugin": "workspace:*"
     "@overleaf/fetch-utils": "workspace:*"
     "@overleaf/o-error": "workspace:*"
     "@popperjs/core": "npm:^2.11.8"
@@ -25970,6 +25970,7 @@ __metadata:
   version: 0.0.0-use.local
   resolution: "overleaf@workspace:."
   dependencies:
+    "@overleaf/eslint-plugin": "workspace:*"
     "@prettier/plugin-pug": "npm:^3.4.0"
     "@types/chai": "npm:^4.3.0"
     "@types/chai-as-promised": "npm:^7.1.8"