Merge pull request #30703 from overleaf/ae-prettier

Upgrade Prettier to v3.7.4

GitOrigin-RevId: 0f4434019bc7d12f2d5b7ecbb833ee20570d0706
This commit is contained in:
Alf Eaton
2026-01-16 09:16:29 +00:00
committed by Copybot
parent 3f19aaa58e
commit 03a3518aae
36 changed files with 144 additions and 137 deletions

View File

@@ -3,7 +3,8 @@ module.exports = {
type: 'problem',
fixable: null,
docs: {
description: 'Require loadingLabel prop when isLoading is specified on OLButton',
description:
'Require loadingLabel prop when isLoading is specified on OLButton',
},
schema: [],
},
@@ -11,10 +12,7 @@ module.exports = {
return {
'JSXOpeningElement[name.name="OLButton"]'(node) {
const attributes = new Map(
node.attributes.map(attr => [
attr.name?.name,
attr
])
node.attributes.map(attr => [attr.name?.name, attr])
)
const isLoadingAttr = attributes.get('isLoading')
@@ -26,12 +24,13 @@ module.exports = {
if (
!isLoadingValue ||
(isLoadingValue.type === 'JSXExpressionContainer' &&
isLoadingValue.expression.type === 'Literal' &&
isLoadingValue.expression.value === true)
isLoadingValue.expression.type === 'Literal' &&
isLoadingValue.expression.value === true)
) {
context.report({
node: isLoadingAttr,
message: 'Button with isLoading prop must also specify loadingLabel',
message:
'Button with isLoading prop must also specify loadingLabel',
})
} else if (
isLoadingValue.type === 'JSXExpressionContainer' &&
@@ -39,7 +38,8 @@ module.exports = {
) {
context.report({
node: isLoadingAttr,
message: 'Button with isLoading prop must also specify loadingLabel',
message:
'Button with isLoading prop must also specify loadingLabel',
})
}
}

View File

@@ -1,5 +1,5 @@
const path = require('node:path');
const fs = require('node:fs');
const path = require('node:path')
const fs = require('node:fs')
module.exports = {
meta: {
@@ -14,26 +14,39 @@ module.exports = {
hasSuggestions: true,
schema: [],
messages: {
unresolvablePath: 'The path "{{pathValue}}" in vi.doMock() cannot be resolved relative to the current file.',
notAStringLiteral: 'The first argument of vi.doMock() must be (or resolve to) a string literal representing a path.',
unresolvablePath:
'The path "{{pathValue}}" in vi.doMock() cannot be resolved relative to the current file.',
notAStringLiteral:
'The first argument of vi.doMock() must be (or resolve to) a string literal representing a path.',
noArguments: 'vi.doMock() called with no arguments.',
},
},
create(context) {
const currentFilePath = context.getFilename();
const currentFilePath = context.getFilename()
// ESLint can sometimes pass <text> or <input> for snippets not in a file
if (currentFilePath === '<text>' || currentFilePath === '<input>') {
return {}
}
const currentDirectory = path.dirname(currentFilePath);
const currentDirectory = path.dirname(currentFilePath)
function canResolve(modulePath) {
try {
require.resolve(path.resolve(currentDirectory, modulePath));
return true;
require.resolve(path.resolve(currentDirectory, modulePath))
return true
} catch (e) {
const absolutePath = path.resolve(currentDirectory, modulePath);
const extensions = ['', '.js', '.mjs', '.ts', '.jsx', '.tsx', '.json', '.node', '/index.js', '/index.ts']; // Add common extensions
const absolutePath = path.resolve(currentDirectory, modulePath)
const extensions = [
'',
'.js',
'.mjs',
'.ts',
'.jsx',
'.tsx',
'.json',
'.node',
'/index.js',
'/index.ts',
] // Add common extensions
for (const ext of extensions) {
if (fs.existsSync(absolutePath + ext)) {
return true
@@ -63,9 +76,14 @@ module.exports = {
const firstArg = node.arguments[0]
let pathValue = firstArg.value
if (firstArg.type !== 'Literal' || typeof firstArg.value !== 'string') {
if (
firstArg.type !== 'Literal' ||
typeof firstArg.value !== 'string'
) {
if (firstArg.type === 'Identifier') {
const variable = context.getScope().variables.find(v => v.name === firstArg.name);
const variable = context
.getScope()
.variables.find(v => v.name === firstArg.name)
if (
variable &&
variable.defs.length > 0 &&
@@ -80,15 +98,13 @@ module.exports = {
// If the first argument was a variable that didn't resolve then we can't auto-fix it
}
}
context.report({
node: firstArg,
messageId: 'notAStringLiteral',
})
return
context.report({
node: firstArg,
messageId: 'notAStringLiteral',
})
return
}
if (!pathValue.startsWith('.')) {
return
}
@@ -97,12 +113,13 @@ module.exports = {
const mjsPath = pathValue.replace('.js', '.mjs')
const additionalReportOptions = {}
if (canResolve(mjsPath)) {
additionalReportOptions.fix = (fixer) => fixer.replaceText(firstArg, `'${mjsPath}'`)
additionalReportOptions.fix = fixer =>
fixer.replaceText(firstArg, `'${mjsPath}'`)
additionalReportOptions.suggest = [
{
desc: `Replace with "${pathValue.replace('.js', '.mjs')}"`,
fix: (fixer) => fixer.replaceText(firstArg, `'${mjsPath}'`),
}
fix: fixer => fixer.replaceText(firstArg, `'${mjsPath}'`),
},
]
}
context.report({
@@ -111,11 +128,11 @@ module.exports = {
data: {
pathValue,
},
...additionalReportOptions
...additionalReportOptions,
})
}
}
},
}
},
};
}

View File

@@ -136,26 +136,33 @@ ruleTester.run('domock-require-valid-path', viDoMockValidPath, {
valid: [
{
code: 'vi.doMock("./require-vi-doMock-valid-path.js")',
filename: __filename
filename: __filename,
},
{
code: 'const filename = "./require-vi-doMock-valid-path.js"; vi.doMock(filename);',
filename: __filename
}
filename: __filename,
},
],
invalid: [
{
code: "vi.doMock('./require-vi-doMock-valid-path2')",
filename: __filename,
errors: [
{
message:
'The path "./require-vi-doMock-valid-path2" in vi.doMock() cannot be resolved relative to the current file.',
},
],
},
{
code: 'const filename = "./require-vi-doMock-valid-path2.js"; vi.doMock(filename);',
filename: __filename,
errors: [
{
message:
'The first argument of vi.doMock() must be (or resolve to) a string literal representing a path.',
},
],
},
],
invalid: [{
code: "vi.doMock('./require-vi-doMock-valid-path2')",
filename: __filename,
errors: [
{
message: 'The path "./require-vi-doMock-valid-path2" in vi.doMock() cannot be resolved relative to the current file.'}
]
}, {
code: 'const filename = "./require-vi-doMock-valid-path2.js"; vi.doMock(filename);',
filename: __filename,
errors: [
{
message: 'The first argument of vi.doMock() must be (or resolve to) a string literal representing a path.'}
]
}]
})

8
package-lock.json generated
View File

@@ -59,7 +59,7 @@
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-promise": "^6.0.0",
"eslint-plugin-unicorn": "^56.0.0",
"prettier": "3.6.2",
"prettier": "3.7.4",
"prettier-plugin-groovy": "0.2.1",
"typescript": "^5.9.3"
},
@@ -44023,9 +44023,9 @@
}
},
"node_modules/prettier": {
"version": "3.6.2",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz",
"integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==",
"version": "3.7.4",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.7.4.tgz",
"integrity": "sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==",
"dev": true,
"license": "MIT",
"bin": {

View File

@@ -23,7 +23,7 @@
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-promise": "^6.0.0",
"eslint-plugin-unicorn": "^56.0.0",
"prettier": "3.6.2",
"prettier": "3.7.4",
"prettier-plugin-groovy": "0.2.1",
"typescript": "^5.9.3"
},

View File

@@ -70,9 +70,8 @@ async function cleanupBackup() {
// The backupPersistor refuses to delete short prefixes. Use a low-level S3 persistor.
if (!s3PersistorForBackupCleanup) {
const { backupPersistor } = await import(
'../../../../../storage/lib/backupPersistor.mjs'
)
const { backupPersistor } =
await import('../../../../../storage/lib/backupPersistor.mjs')
s3PersistorForBackupCleanup = new S3Persistor(backupPersistor.settings)
}
await Promise.all(

View File

@@ -393,9 +393,7 @@ const AuthenticationController = {
const middleware = async (req, res, next) => {
const Oauth2Server = (
await import(
'../../../../modules/oauth2-server/app/src/Oauth2Server.mjs'
)
await import('../../../../modules/oauth2-server/app/src/Oauth2Server.mjs')
).default
const request = new Oauth2Server.Request(req)

View File

@@ -6,7 +6,8 @@ import Errors from '../Errors/Errors.js'
export class InvalidEmailError extends Errors.BackwardCompatibleError {}
export class InvalidPasswordError extends Errors.BackwardCompatibleError {}
export class ParallelLoginError extends Errors.BackwardCompatibleError {}
export class PasswordMustBeDifferentError extends Errors.BackwardCompatibleError {}
export class PasswordMustBeDifferentError
extends Errors.BackwardCompatibleError {}
export class PasswordReusedError extends Errors.BackwardCompatibleError {}
export function handleAuthenticateErrors(error, req) {

View File

@@ -876,12 +876,12 @@ function _matchesFilters(project, tags, filters) {
function _hasActiveFilter(filters) {
return Boolean(
filters.ownedByUser ||
filters.sharedWithUser ||
filters.archived ||
filters.trashed ||
filters.tag === null ||
filters.tag?.length ||
filters.search?.length
filters.sharedWithUser ||
filters.archived ||
filters.trashed ||
filters.tag === null ||
filters.tag?.length ||
filters.search?.length
)
}

View File

@@ -31,9 +31,7 @@ export function isStandaloneAiAddOnPlanCode(planCode) {
export function subscriptionChangeIsAiAssistUpgrade(subscriptionChange) {
return Boolean(
isStandaloneAiAddOnPlanCode(subscriptionChange.nextPlanCode) ||
subscriptionChange.nextAddOns?.some(
addOn => addOn.code === AI_ADD_ON_CODE
)
subscriptionChange.nextAddOns?.some(addOn => addOn.code === AI_ADD_ON_CODE)
)
}

View File

@@ -6,7 +6,7 @@ export function isProfessionalPlan(planCode) {
// only identify "modern" professional group plans as eligible, and do not include legacy plans
return Boolean(
planCode?.includes('professional') &&
FeaturesHelper.getMatchedFeatureSet(plan?.features) === 'professional'
FeaturesHelper.getMatchedFeatureSet(plan?.features) === 'professional'
)
}

View File

@@ -171,7 +171,7 @@ const SubscriptionLocator = {
return Boolean(
(subscription?.planCode &&
isStandaloneAiAddOnPlanCode(subscription?.planCode)) ||
subscription?.addOns?.some(addOn => addOn.addOnCode === AI_ADD_ON_CODE)
subscription?.addOns?.some(addOn => addOn.addOnCode === AI_ADD_ON_CODE)
)
},

View File

@@ -59,9 +59,9 @@ async function manageGroupMembers(req, res, next) {
const canUseAddSeatsFeature = Boolean(
plan?.canUseFlexibleLicensing &&
isAdmin &&
recurlySubscription &&
!recurlySubscription.pendingChange
isAdmin &&
recurlySubscription &&
!recurlySubscription.pendingChange
)
res.render('user_membership/group-members-react', {

View File

@@ -85,7 +85,7 @@ const Features = {
case 'link-url':
return Boolean(
_.get(Settings, ['apis', 'linkedUrlProxy', 'url']) &&
Settings.enabledLinkedFileTypes.includes('url')
Settings.enabledLinkedFileTypes.includes('url')
)
case 'support':
return supportModuleAvailable

View File

@@ -32,9 +32,9 @@ export function cookieBannerRequired() {
const exposedSettings = getMeta('ol-ExposedSettings')
return Boolean(
exposedSettings.gaToken ||
exposedSettings.gaTokenV4 ||
exposedSettings.propensityId ||
exposedSettings.hotjarId
exposedSettings.gaTokenV4 ||
exposedSettings.propensityId ||
exposedSettings.hotjarId
)
}

View File

@@ -14,9 +14,8 @@ const FileViewPdf: FC<{
const handleContainer = useCallback(
async (element: HTMLDivElement | null) => {
if (element) {
const { loadPdfDocumentFromUrl } = await import(
'@/features/pdf-preview/util/pdf-js'
)
const { loadPdfDocumentFromUrl } =
await import('@/features/pdf-preview/util/pdf-js')
// bail out if loading PDF.js took too long
if (!mountedRef.current) {

View File

@@ -42,8 +42,7 @@ export interface GotoOffsetOptions {
}
interface OpenDocOptions
extends Partial<GotoLineOptions>,
Partial<GotoOffsetOptions> {
extends Partial<GotoLineOptions>, Partial<GotoOffsetOptions> {
gotoOffset?: number
forceReopen?: boolean
keepCurrentView?: boolean

View File

@@ -13,18 +13,15 @@ interface BaseFileTreeFindResult<T> {
index: number
}
export interface FileTreeFolderFindResult
extends BaseFileTreeFindResult<Folder> {
export interface FileTreeFolderFindResult extends BaseFileTreeFindResult<Folder> {
type: 'folder'
}
export interface FileTreeDocumentFindResult
extends BaseFileTreeFindResult<Doc> {
export interface FileTreeDocumentFindResult extends BaseFileTreeFindResult<Doc> {
type: 'doc'
}
export interface FileTreeFileRefFindResult
extends BaseFileTreeFindResult<FileRef> {
export interface FileTreeFileRefFindResult extends BaseFileTreeFindResult<FileRef> {
type: 'fileRef'
}

View File

@@ -144,9 +144,9 @@ export function ManageTagModal({
onClick={() => runUpdateTag(tag._id)}
disabled={Boolean(
isUpdateLoading ||
isDeleteLoading ||
!newTagName?.length ||
(newTagName === tag?.name && selectedColor === getTagColor(tag))
isDeleteLoading ||
!newTagName?.length ||
(newTagName === tag?.name && selectedColor === getTagColor(tag))
)}
isLoading={isUpdateLoading}
loadingLabel={t('saving')}

View File

@@ -86,8 +86,8 @@ function MakePrimary({
const isConfirmDisabled = Boolean(
!userEmailData.confirmedAt ||
state.isLoading ||
inReconfirmNotificationPeriod(userEmailData)
state.isLoading ||
inReconfirmNotificationPeriod(userEmailData)
)
return (

View File

@@ -23,7 +23,7 @@ type EmailsRowProps = {
function EmailsRow({ userEmailData, primary }: EmailsRowProps) {
const hasSSOAffiliation = Boolean(
userEmailData.affiliation &&
ssoAvailableForInstitution(userEmailData.affiliation.institution)
ssoAvailableForInstitution(userEmailData.affiliation.institution)
)
return (

View File

@@ -45,7 +45,7 @@ export default function ShareModalBody() {
members?.some(member =>
['readAndWrite', 'review'].includes(member.privileges)
) &&
members?.some(member => member.pendingEditor || member.pendingReviewer)
members?.some(member => member.pendingEditor || member.pendingReviewer)
)
}, [members])

View File

@@ -1,7 +1,6 @@
import { forwardRef, useImperativeHandle, useLayoutEffect, useRef } from 'react'
interface CellInputProps
extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {
interface CellInputProps extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {
value: string
}

View File

@@ -61,8 +61,8 @@ interface AdjacentMatchResult extends MatchResult {
const matchedAdjacent = (match: MatchResult): match is AdjacentMatchResult =>
Boolean(
match.matched &&
match.end &&
(match.start.to === match.end.from || match.end.to === match.start.from)
match.end &&
(match.start.to === match.end.from || match.end.to === match.start.from)
)
/**

View File

@@ -922,7 +922,7 @@ export const atomicDecorations = (options: Options) => {
)
const centered = Boolean(
environmentNode &&
centeringNodeForEnvironment(environmentNode)
centeringNodeForEnvironment(environmentNode)
)
const figureData = environmentNode
? parseFigureData(environmentNode, state)

View File

@@ -241,9 +241,8 @@ export class GraphicsWidget extends WidgetType {
}
async renderPDF(view: EditorView, canvas: HTMLCanvasElement, url: string) {
const { loadPdfDocumentFromUrl } = await import(
'@/features/pdf-preview/util/pdf-js'
)
const { loadPdfDocumentFromUrl } =
await import('@/features/pdf-preview/util/pdf-js')
// bail out if loading PDF.js took too long
if (this.destroyed) {

View File

@@ -271,7 +271,6 @@ function rectanglesForRange(
for (
let pos = Math.max(r.from, start), endPos = Math.min(r.to, end);
;
) {
const docLine = view.state.doc.lineAt(pos)
for (const span of view.bidiSpans(docLine)) {

View File

@@ -85,8 +85,8 @@ export function ActiveSubscription({
const hasPendingPause = Boolean(
subscription.payment.state === 'active' &&
subscription.payment.remainingPauseCycles &&
subscription.payment.remainingPauseCycles > 0
subscription.payment.remainingPauseCycles &&
subscription.payment.remainingPauseCycles > 0
)
const isLegacyPlan =

View File

@@ -129,17 +129,17 @@ export function SubscriptionDashboardProvider({
const hasDisplayedSubscription = Boolean(
institutionMemberships?.length > 0 ||
personalSubscription ||
memberGroupSubscriptions?.length > 0 ||
managedGroupSubscriptions?.length > 0 ||
managedInstitutions?.length > 0 ||
managedPublishers?.length > 0
personalSubscription ||
memberGroupSubscriptions?.length > 0 ||
managedGroupSubscriptions?.length > 0 ||
managedInstitutions?.length > 0 ||
managedPublishers?.length > 0
)
const hasValidActiveSubscription = Boolean(
['active', 'canceled'].includes(personalSubscription?.payment?.state) ||
institutionMemberships?.length > 0 ||
memberGroupSubscriptions?.length > 0
institutionMemberships?.length > 0 ||
memberGroupSubscriptions?.length > 0
)
const getFormattedRenewalDate = useCallback(() => {

View File

@@ -58,10 +58,10 @@ const isPropensityNetworkError = (err: ErrorEvent) => {
const breadcrumbUrl = errorBreadcrumbs[0]?.data?.url
return Boolean(
breadcrumbUrl &&
[
'https://analytics.propensity.com/',
'https://analytics.propensity-abm.com/',
].some(url => breadcrumbUrl.startsWith(url))
[
'https://analytics.propensity.com/',
'https://analytics.propensity-abm.com/',
].some(url => breadcrumbUrl.startsWith(url))
)
}

View File

@@ -2,8 +2,10 @@ import ReCAPTCHA from 'react-google-recaptcha'
import getMeta from '@/utils/meta'
import { ExposedSettings } from '../../../../types/exposed-settings'
interface ReCaptcha2Props
extends Pick<React.ComponentProps<typeof ReCAPTCHA>, 'onChange'> {
interface ReCaptcha2Props extends Pick<
React.ComponentProps<typeof ReCAPTCHA>,
'onChange'
> {
page: keyof ExposedSettings['recaptchaDisabled']
recaptchaRef: React.LegacyRef<ReCAPTCHA>
}

View File

@@ -84,7 +84,7 @@ export const EditorProvider: FC<React.PropsWithChildren> = ({ children }) => {
() => {
return Boolean(
featureUsage?.aiErrorAssistant &&
featureUsage?.aiErrorAssistant.remainingUsage > 0
featureUsage?.aiErrorAssistant.remainingUsage > 0
)
}
)

View File

@@ -29,9 +29,7 @@ describe('EmailChangeHelper', function () {
)
EmailChangeHelpers = (
await import(
'../../../../app/src/Features/Analytics/EmailChangeHelper.mjs'
)
await import('../../../../app/src/Features/Analytics/EmailChangeHelper.mjs')
).default
})

View File

@@ -46,8 +46,7 @@ export interface NotificationTPDSFileLimit extends NotificationBase {
}
}
export interface NotificationDropboxDuplicateProjectNames
extends NotificationBase {
export interface NotificationDropboxDuplicateProjectNames extends NotificationBase {
templateKey: Extract<
TemplateKey,
'notification_dropbox_duplicate_project_names'
@@ -57,8 +56,7 @@ export interface NotificationDropboxDuplicateProjectNames
}
}
interface NotificationDropboxUnlinkedDueToLapsedReconfirmation
extends NotificationBase {
interface NotificationDropboxUnlinkedDueToLapsedReconfirmation extends NotificationBase {
templateKey: Extract<
TemplateKey,
'notification_dropbox_unlinked_due_to_lapsed_reconfirmation'

View File

@@ -55,8 +55,7 @@ interface AddOn {
// Extending the default interface as it lacks the `items` prop
export interface SubscriptionPricingInstanceCustom
extends SubscriptionPricingInstance,
SubscriptionPricingState {
extends SubscriptionPricingInstance, SubscriptionPricingState {
id: string
items: {
addons: AddOn[]

View File

@@ -10,16 +10,14 @@ export interface ReviewPanelCommentThreadBase {
submitting?: boolean // angular specific (to be made into a local state)
}
interface ReviewPanelUnresolvedCommentThread
extends ReviewPanelCommentThreadBase {
interface ReviewPanelUnresolvedCommentThread extends ReviewPanelCommentThreadBase {
resolved?: never
resolved_at?: never
resolved_by_user_id?: never
resolved_by_user?: never
}
export interface ReviewPanelResolvedCommentThread
extends ReviewPanelCommentThreadBase {
export interface ReviewPanelResolvedCommentThread extends ReviewPanelCommentThreadBase {
resolved: boolean
resolved_at: DateString
resolved_by_user_id: UserId