Merge pull request #28893 from overleaf/mj-linter-brace-check

[web] Allow braces in documentclass options

GitOrigin-RevId: 9675d3fc760a3b7d402c5a9df57a0cf183a1e648
This commit is contained in:
Mathias Jakobsen
2025-10-08 10:10:41 +01:00
committed by Copybot
parent b6d116e957
commit f9d0f7e3ee
2 changed files with 39 additions and 4 deletions

View File

@@ -338,11 +338,20 @@ const readOptionalArgumentWithUnderscores = function (TokeniseResult, k) {
}
let label = ''
let groupDepth = 0
let j, tok
for (j = k + 1; (tok = Tokens[j]); j++) {
if (tok[1] === '{') {
// unclosed label
break
if (label.length === 0) {
// We haven't seen a [ yet, so there is no optional argument
break
}
groupDepth++
} else if (tok[1] === '}') {
groupDepth--
if (groupDepth < 0) {
break
}
} else if (tok[1] === 'Text') {
const str = text.substring(tok[2], tok[3])
label = label + str
@@ -357,6 +366,13 @@ const readOptionalArgumentWithUnderscores = function (TokeniseResult, k) {
break // breaking due to unrecognised token
}
}
if (groupDepth !== 0) {
const missing = groupDepth > 0 ? '{' : '}'
// mismatched braces
const e = new Error(`Unmatched ${missing} in label`)
e.pos = j + 1
return e
}
if (label.length === 0) {
return null

View File

@@ -473,9 +473,8 @@ describe('LatexLinter', function () {
it('should reject an unclosed hyperref label', function () {
const { errors } = Parse('\\hyperref[foo_bar{foo bar}')
assert.equal(errors.length, 2)
assert.equal(errors.length, 1)
assert.equal(errors[0].text, 'invalid hyperref label')
assert.equal(errors[1].text, 'unexpected close group }')
})
it('should accept a hyperref command without an optional argument', function () {
@@ -511,6 +510,26 @@ describe('LatexLinter', function () {
assert.equal(errors.length, 0)
})
it('should accept a documentclass with braces in options', function () {
const { errors } = Parse(
'\\documentclass[a4paper,margin={1in,0.5in}]{article}'
)
assert.equal(errors.length, 0)
})
it('should reject documentclass with unbalanced braces in options', function () {
const { errors } = Parse('\\documentclass[foo={bar]{article}')
assert.equal(errors.length, 2)
assert.equal(errors[0].text, 'invalid documentclass option')
assert.equal(errors[1].text, 'unexpected close group }')
})
it('should reject documentclass with out of order braces in options', function () {
const { errors } = Parse('\\documentclass[foo=}bar{]{article}')
assert.equal(errors.length, 1)
assert.equal(errors[0].text, 'invalid documentclass option')
})
// %novalidate
// %begin novalidate
// %end novalidate