Рекурсии в нативном джаваскриптовом регэкспе нет. Соответственно вы конечно можете написать конструкцию с ограничением какой-то глубиной вложенности руками (хотя скорее сгенерить).
Проблема не новая и строители велосипедов периодически выпускают свои версии регулярок (мне вот яндекс в ответ на запрос "js recursive regex" дал такую
ссылку)
Но судя по контексту вопроса вам не нативный регексп не подойдёт, так что в общем виде ваша задача не решаема.
UPD.
по поводу генерации руками:
для глубины вложенности 3 у меня вышел вот такой франкенштейн:
/^[^()]*(\([^()]*(\([^()]*(\([^()]*\))*[^()]*\))*[^()]*\))*(?<unclosed>\([^()]*(\([^()]*(\([^()]*\))*[^()]*\))*[^()]*)*[^()]*(\([^()]*(\([^()]*(\([^()]*\))*[^()]*\))*[^()]*\))*[^()]*$/
-- если нашёл группу unclosed, то есть проблема
(думаю, основная идея видна)
UPD2:
генератор выглядит примерно так, только сайт regex101 от моей рекгулярки на глубину 150 умер. так что, возможно, тупиковая идея.
const anySymbols = `[^()]*`
const closedRegexPattern = (depth) => {
if(depth < 1)
return anySymbols
return `\\((${anySymbols}${closedRegexPattern(depth-1)})*${anySymbols}\\)`
}
const unclosedCatcherRegexPattern = (depth) => {
const unclosedPart = `(?<unclosed>\\((${anySymbols}${closedRegexPattern(depth-1)})*${anySymbols})*`
return `^${anySymbols}${closedRegexPattern(depth)}${unclosedPart}${closedRegexPattern(depth)}${anySymbols}$`
}
console.log(unclosedCatcherRegexPattern(150))
Кстати, в моей регулярке из UPD1 был косяк, из за которого вариант ((1)(2)) был валиден, а ((1)3(2)) уже нет.