@ -84,6 +84,20 @@ var escClose = '\0CLOSE'+Math.random()+'\0';
var escComma = '\0COMMA' + Math . random ( ) + '\0' ;
var escComma = '\0COMMA' + Math . random ( ) + '\0' ;
var escPeriod = '\0PERIOD' + Math . random ( ) + '\0' ;
var escPeriod = '\0PERIOD' + Math . random ( ) + '\0' ;
var EXPANSION _MAX = 100000
// `EXPANSION_MAX` caps the *number* of expansions, but not their length. An
// input like `'{a,b}'.repeat(1500)` stays under that count - its output is
// truncated to 100k results - while making every result ~1500 characters
// long. The result set, and the intermediate arrays built while combining
// brace sets, then grow large enough to exhaust memory and crash the process
// (CVE-2026-14257). `EXPANSION_MAX_LENGTH` bounds the total number of
// characters the accumulator may hold at any point, so memory stays flat no
// matter how many brace groups are chained. The limit sits well above any
// realistic expansion (100k results hitting `EXPANSION_MAX` measure ~1M
// characters) so legitimate input is unaffected.
var EXPANSION _MAX _LENGTH = 4000000
function numeric ( str ) {
function numeric ( str ) {
return parseInt ( str , 10 ) == str
return parseInt ( str , 10 ) == str
? parseInt ( str , 10 )
? parseInt ( str , 10 )
@ -142,7 +156,8 @@ function expandTop(str, options) {
return [ ] ;
return [ ] ;
options = options || { } ;
options = options || { } ;
var max = options . max == null ? Infinity : options . max ;
var max = options . max == null ? EXPANSION _MAX : options . max ;
var maxLength = options . maxLength == null ? EXPANSION _MAX _LENGTH : options . maxLength ;
// I don't know why Bash 4.3 does this, but it does.
// I don't know why Bash 4.3 does this, but it does.
// Anything starting with {} will have the first two bytes preserved
// Anything starting with {} will have the first two bytes preserved
@ -154,7 +169,7 @@ function expandTop(str, options) {
str = '\\{\\}' + str . substr ( 2 ) ;
str = '\\{\\}' + str . substr ( 2 ) ;
}
}
return expand ( escapeBraces ( str ) , max , true ) . map ( unescapeBraces ) ;
return expand ( escapeBraces ( str ) , max , maxLength , true ) . map ( unescapeBraces ) ;
}
}
function identity ( e ) {
function identity ( e ) {
@ -175,15 +190,155 @@ function gte(i, y) {
return i >= y ;
return i >= y ;
}
}
function expand ( str , max , isTop ) {
// Build `{ acc[a] + pre + values[v] }` for every combination, capping the
var expansions = [ ] ;
// number of results at `max` and the total number of characters at `maxLength`.
// This is the one place output grows, so bounding it here keeps the single
// accumulator - and therefore memory - flat regardless of how many brace groups
// are combined (CVE-2026-14257).
//
// `base[a]` is the length of the part of `acc[a]` that predates the current
// empty-drop baseline (see `expand`). The matching baselines for the results
// are appended to `outBase`, which the caller carries forward alongside them.
function combine (
acc ,
base ,
pre ,
values ,
max ,
maxLength ,
dropEmpties ,
outBase
) {
var out = [ ]
var length = 0
for ( var a = 0 ; a < acc . length ; a ++ ) {
for ( var v = 0 ; v < values . length ; v ++ ) {
if ( out . length >= max ) return out
var expansion = acc [ a ] + pre + values [ v ]
// Bash drops empty results at the top level. Skip them before they count
// against `max`, so `max` bounds the number of *kept* results. "Empty"
// means "adds nothing past the baseline", not "empty overall".
if ( dropEmpties && expansion . length === base [ a ] ) continue
if ( length + expansion . length > maxLength ) return out
out . push ( expansion )
outBase . push ( base [ a ] )
length += expansion . length
}
}
return out
}
// The expansion values of a single numeric (`1..5`) or alphabetic (`a..e..2`)
// sequence body.
function expandSequence (
body ,
isAlphaSequence ,
max ,
maxLength
) {
var n = body . split ( /\.\./ )
var N = [ ]
// A sequence body always splits into two or three parts, but the compiler
// can't know that.
/* c8 ignore start */
if ( n [ 0 ] === undefined || n [ 1 ] === undefined ) {
return N
}
/* c8 ignore stop */
var x = numeric ( n [ 0 ] )
var y = numeric ( n [ 1 ] )
var width = Math . max ( n [ 0 ] . length , n [ 1 ] . length )
var incr =
n . length === 3 && n [ 2 ] !== undefined ?
Math . max ( Math . abs ( numeric ( n [ 2 ] ) ) , 1 )
: 1
var test = lte
var reverse = y < x
if ( reverse ) {
incr *= - 1
test = gte
}
var pad = n . some ( isPadded )
var length = 0
for ( var i = x ; test ( i , y ) && N . length < max ; i += incr ) {
var c
if ( isAlphaSequence ) {
c = String . fromCharCode ( i )
if ( c === '\\' ) {
c = ''
}
} else {
c = String ( i )
if ( pad ) {
var need = width - c . length
if ( need > 0 ) {
var z = new Array ( need + 1 ) . join ( '0' )
if ( i < 0 ) {
c = '-' + z + c . slice ( 1 )
} else {
c = z + c
}
}
}
}
if ( length + c . length > maxLength ) break
N . push ( c )
length += c . length
}
return N
}
function expand (
str ,
max ,
maxLength ,
isTop
) {
// Consume the string's top-level brace groups left to right, threading a
// running set of combined prefixes (`acc`). Expanding the tail iteratively -
// rather than recursing on `m.post` once per group - keeps the native stack
// depth constant, so deeply chained input (`'{a,b}'.repeat(3000)`) can no
// longer overflow the stack, and leaves a single accumulator whose size
// `maxLength` bounds directly (CVE-2026-14257).
var acc = [ '' ]
// Bash drops empty results, but only when the *first* group of the run is a
// comma set - a sequence like `{a..\}` may legitimately yield ''. The drop
// is on the final strings, so it is applied to whichever `combine` produces
// them (the one with no brace set left in the tail).
//
// The old implementation recursed on `m.post`, so the drop tested only the
// expansion of the current call's substring. The `{a},b}` rewrite below turns
// `isTop` back on part-way through a string, starting a fresh such run, so
// the drop must ignore whatever `acc` already holds from earlier groups.
// `accBase[a]` records how much of `acc[a]` predates the current run;
// `combine` treats an expansion as empty when it adds nothing past that.
var accBase = [ 0 ]
var dropEmpties = false
var firstGroup = true
var nextBase
// The `{a},b}` rewrite below restarts expansion on a rewritten string with
// the same `max` and `isTop = true`. Loop instead of recursing so a long run
// of non-expanding `{}` groups can't exhaust the call stack.
for ( ; ; ) {
for ( ; ; ) {
var m = balanced ( '{' , '}' , str ) ;
var m = balanced ( '{' , '}' , str ) ;
if ( ! m || /\$$/ . test ( m . pre ) ) return [ str ] ;
// No brace set left: the rest of the string is literal.
if ( ! m ) {
return combine ( acc , accBase , str , [ '' ] , max , maxLength , dropEmpties , [ ] )
}
// no need to expand pre, since it is guaranteed to be free of brace-sets
var pre = m . pre ;
// For compatibility reasons, `${` is not eligible for brace expansion, and
// on the 1.x line it suppresses expansion of the rest of the string too:
// the whole remainder is literal. The 2.x and 5.x lines instead keep
// expanding the tail, which is what bash does, but changing that here would
// be a breaking change for 1.x consumers. Routed through `combine` so the
// result is still bounded by `max` and `maxLength`.
if ( /\$$/ . test ( pre ) ) {
return combine ( acc , accBase , str , [ '' ] , max , maxLength , dropEmpties , [ ] )
}
var isNumericSequence = /^-?\d+\.\.-?\d+(?:\.\.-?\d+)?$/ . test ( m . body ) ;
var isNumericSequence = /^-?\d+\.\.-?\d+(?:\.\.-?\d+)?$/ . test ( m . body ) ;
var isAlphaSequence = /^[a-zA-Z]\.\.[a-zA-Z](?:\.\.-?\d+)?$/ . test ( m . body ) ;
var isAlphaSequence = /^[a-zA-Z]\.\.[a-zA-Z](?:\.\.-?\d+)?$/ . test ( m . body ) ;
@ -193,94 +348,112 @@ function expand(str, max, isTop) {
// {a},b}
// {a},b}
if ( m . post . match ( /,(?!,).*\}/ ) ) {
if ( m . post . match ( /,(?!,).*\}/ ) ) {
str = m . pre + '{' + m . body + escClose + m . post ;
str = m . pre + '{' + m . body + escClose + m . post ;
// The rewritten string is expanded as if it were a fresh top-level one,
// so start a new empty-drop run: anchor the baseline at what `acc`
// holds now, and let the next expanding group decide whether to drop.
isTop = true
isTop = true
firstGroup = true
dropEmpties = false
accBase = [ ]
for ( var b = 0 ; b < acc . length ; b ++ ) {
accBase . push ( acc [ b ] . length )
}
continue
continue
}
}
return [ str ] ;
// Nothing here expands, so the whole remaining string is literal.
return combine (
acc ,
accBase ,
pre + '{' + m . body + '}' + m . post ,
[ '' ] ,
max ,
maxLength ,
dropEmpties ,
[ ]
)
}
if ( firstGroup ) {
dropEmpties = isTop && ! isSequence
firstGroup = false
}
}
var n ;
var values ;
if ( isSequence ) {
if ( isSequence ) {
n = m . body . split ( /\.\./ ) ;
values = expandSequence ( m . body , isAlphaSequence , max , maxLength ) ;
} else {
} else {
n = parseCommaParts ( m . body ) ;
var n = parseCommaParts ( m . body ) ;
if ( n . length === 1 ) {
if ( n . length === 1 && n [ 0 ] !== undefined ) {
// x{{a,b}}y ==> x{a}y x{b}y
// x{{a,b}}y ==> x{a}y x{b}y
n = expand ( n [ 0 ] , max , false ) . map ( embrace ) ;
n = expand ( n [ 0 ] , max , maxLength , false ) . map ( embrace ) ;
//XXX is this necessary? Can't seem to hit it in tests.
/* c8 ignore start */
if ( n . length === 1 ) {
if ( n . length === 1 ) {
var post = m . post . length
nextBase = [ ]
? expand ( m . post , max , false )
acc = combine (
: [ '' ] ;
acc ,
return post . map ( function ( p ) {
accBase ,
return m . pre + n [ 0 ] + p ;
pre + n [ 0 ] ,
} ) ;
[ '' ] ,
}
max ,
maxLength ,
dropEmpties && ! m . post . length ,
nextBase
)
accBase = nextBase
if ( ! m . post . length ) break
str = m . post
continue
}
}
/* c8 ignore stop */
}
}
// at this point, n is the parts, and we know it's not a comma set
// Values that `combine` is going to drop as empty produce no result, so
// with a single entry.
// they must not count against `max` - otherwise `{a,,b}` with `max: 2`
// would stop at `['a', '']` and yield one result instead of two. Skipping
// no need to expand pre, since it is guaranteed to be free of brace-sets
// them outright keeps `values` bounded while leaving `max` a bound on
var pre = m . pre ;
// *kept* results. A value is dropped when it adds nothing past the
var post = m . post . length
// baseline, which is what `combine` tests.
? expand ( m . post , max , false )
var dropsEmpties = dropEmpties && ! m . post . length && ! pre
: [ '' ] ;
for ( var d = 0 ; dropsEmpties && d < acc . length ; d ++ ) {
if ( acc [ d ] . length !== accBase [ d ] ) {
var N ;
dropsEmpties = false
if ( isSequence ) {
var x = numeric ( n [ 0 ] ) ;
var y = numeric ( n [ 1 ] ) ;
var width = Math . max ( n [ 0 ] . length , n [ 1 ] . length )
var incr = n . length == 3
? Math . max ( Math . abs ( numeric ( n [ 2 ] ) ) , 1 )
: 1 ;
var test = lte ;
var reverse = y < x ;
if ( reverse ) {
incr *= - 1 ;
test = gte ;
}
}
var pad = n . some ( isPadded ) ;
N = [ ] ;
for ( var i = x ; test ( i , y ) && N . length < max ; i += incr ) {
var c ;
if ( isAlphaSequence ) {
c = String . fromCharCode ( i ) ;
if ( c === '\\' )
c = '' ;
} else {
c = String ( i ) ;
if ( pad ) {
var need = width - c . length ;
if ( need > 0 ) {
var z = new Array ( need + 1 ) . join ( '0' ) ;
if ( i < 0 )
c = '-' + z + c . slice ( 1 ) ;
else
c = z + c ;
}
}
values = [ ]
var valuesLength = 0
outer : for ( var j = 0 ; j < n . length ; j ++ ) {
var expanded = expand ( n [ j ] , max , maxLength , false )
for ( var k = 0 ; k < expanded . length ; k ++ ) {
var v = expanded [ k ]
if ( dropsEmpties && ! v ) continue
if ( values . length >= max || valuesLength + v . length > maxLength ) {
break outer
}
}
values . push ( v )
valuesLength += v . length
}
}
N . push ( c ) ;
}
}
} else {
N = concatMap ( n , function ( el ) { return expand ( el , max , false ) } ) ;
}
}
for ( var j = 0 ; j < N . length ; j ++ ) {
nextBase = [ ]
for ( var k = 0 ; k < post . length && expansions . length < max ; k ++ ) {
acc = combine (
var expansion = pre + N [ j ] + post [ k ] ;
acc ,
if ( ! isTop || isSequence || expansion )
accBase ,
expansions . push ( expansion ) ;
pre ,
}
values ,
max ,
maxLength ,
dropEmpties && ! m . post . length ,
nextBase
)
accBase = nextBase
if ( ! m . post . length ) break
str = m . post
}
}
return expansions ;
return acc
}
}
}
@ -14204,7 +14377,13 @@ function processHeader (request, key, val) {
} else if ( typeof val [ i ] === 'object' ) {
} else if ( typeof val [ i ] === 'object' ) {
throw new InvalidArgumentError ( ` invalid ${ key } header ` )
throw new InvalidArgumentError ( ` invalid ${ key } header ` )
} else {
} else {
arr . push ( ` ${ val [ i ] } ` )
// Coerce primitives (and reject unsafe coercions such as functions
// with a crafted toString/Symbol.toPrimitive).
const str = ` ${ val [ i ] } `
if ( ! isValidHeaderValue ( str ) ) {
throw new InvalidArgumentError ( ` invalid ${ key } header ` )
}
arr . push ( str )
}
}
}
}
val = arr
val = arr
@ -14215,7 +14394,12 @@ function processHeader (request, key, val) {
} else if ( val === null ) {
} else if ( val === null ) {
val = ''
val = ''
} else {
} else {
// Coerce primitives (and reject unsafe coercions such as functions
// with a crafted toString/Symbol.toPrimitive).
val = ` ${ val } `
val = ` ${ val } `
if ( ! isValidHeaderValue ( val ) ) {
throw new InvalidArgumentError ( ` invalid ${ key } header ` )
}
}
}
if ( headerName === 'host' ) {
if ( headerName === 'host' ) {
@ -15587,6 +15771,7 @@ const {
RequestContentLengthMismatchError ,
RequestContentLengthMismatchError ,
ResponseContentLengthMismatchError ,
ResponseContentLengthMismatchError ,
RequestAbortedError ,
RequestAbortedError ,
InvalidArgumentError ,
HeadersTimeoutError ,
HeadersTimeoutError ,
HeadersOverflowError ,
HeadersOverflowError ,
SocketError ,
SocketError ,
@ -16570,8 +16755,16 @@ function writeH1 (client, request) {
}
}
body = bodyStream . stream
body = bodyStream . stream
contentLength = bodyStream . length
contentLength = bodyStream . length
} else if ( util . isBlobLike ( body ) && request . contentType == null && body . type ) {
} else if ( util . isBlobLike ( body ) && request . contentType == null ) {
headers . push ( 'content-type' , body . type )
const contentType = body . type
if ( contentType ) {
const contentTypeValue = ` ${ contentType } `
if ( ! util . isValidHeaderValue ( contentTypeValue ) ) {
util . errorRequest ( client , request , new InvalidArgumentError ( 'invalid content-type header' ) )
return false
}
headers . push ( 'content-type' , contentTypeValue )
}
}
}
if ( body && typeof body . read === 'function' ) {
if ( body && typeof body . read === 'function' ) {
@ -20044,6 +20237,28 @@ function calculateRetryAfterHeader (retryAfter) {
return new Date ( retryAfter ) . getTime ( ) - current
return new Date ( retryAfter ) . getTime ( ) - current
}
}
function validatePartialResponseContentLength ( headers , range , statusCode , retryCount ) {
const contentLength = headers [ 'content-length' ]
if ( contentLength == null ) {
return null
}
if ( ! Number . isFinite ( range . start ) || ! Number . isFinite ( range . end ) ) {
return null
}
const length = Number ( contentLength )
const expectedLength = range . end - range . start + 1
if ( ! Number . isFinite ( length ) || length !== expectedLength ) {
return new RequestRetryError ( 'Content-Length mismatch' , statusCode , {
headers ,
data : { count : retryCount }
} )
}
return null
}
class RetryHandler {
class RetryHandler {
constructor ( opts , handlers ) {
constructor ( opts , handlers ) {
const { retryOptions , ... dispatchOpts } = opts
const { retryOptions , ... dispatchOpts } = opts
@ -20258,6 +20473,12 @@ class RetryHandler {
return false
return false
}
}
const contentLengthError = validatePartialResponseContentLength ( headers , contentRange , statusCode , this . retryCount )
if ( contentLengthError != null ) {
this . abort ( contentLengthError )
return false
}
const { start , size , end = size - 1 } = contentRange
const { start , size , end = size - 1 } = contentRange
assert ( this . start === start , 'content-range mismatch' )
assert ( this . start === start , 'content-range mismatch' )
@ -20281,6 +20502,12 @@ class RetryHandler {
)
)
}
}
const contentLengthError = validatePartialResponseContentLength ( headers , range , statusCode , this . retryCount )
if ( contentLengthError != null ) {
this . abort ( contentLengthError )
return false
}
const { start , size , end = size - 1 } = range
const { start , size , end = size - 1 } = range
assert (
assert (
start != null && Number . isFinite ( start ) ,
start != null && Number . isFinite ( start ) ,
@ -24525,7 +24752,7 @@ function validateCookiePath (path) {
if (
if (
code < 0x20 || // exclude CTLs (0-31)
code < 0x20 || // exclude CTLs (0-31)
code === 0x7F || // DEL
code > 0x7E || // exclude DEL and non-ascii
code === 0x3B // ;
code === 0x3B // ;
) {
) {
throw new Error ( 'Invalid cookie path' )
throw new Error ( 'Invalid cookie path' )
@ -24534,16 +24761,80 @@ function validateCookiePath (path) {
}
}
/ * *
/ * *
* I have no idea why these values aren ' t allowed to be honest ,
* < let - dig > : : = < letter > | < digit >
* but Deno tests these . - Khafra
*
* < letter > : : = any one of the 52 alphabetic characters A through Z in
* upper case and a through z in lower case
*
* < digit > : : = any one of the ten digits 0 through 9 r
*
* @ see https : //www.rfc-editor.org/rfc/rfc1034#section-3.5
* @ param { number } code
* /
function isLetterOrDigit ( code ) {
return (
( code >= 0x30 && code <= 0x39 ) || // 0-9
( code >= 0x41 && code <= 0x5A ) || // A-Z
( code >= 0x61 && code <= 0x7A ) // a-z
)
}
/ * *
* Validates a cookie domain against the "preferred name syntax" .
*
* < domain > : : = < subdomain > | " "
* < subdomain > : : = < label > | < subdomain > "." < label >
* < label > : : = < let - dig > [ [ < ldh - str > ] < let - dig > ]
* < ldh - str > : : = < let - dig - hyp > | < let - dig - hyp > < ldh - str >
* < let - dig - hyp > : : = < let - dig > | "-"
*
* @ see https : //www.rfc-editor.org/rfc/rfc1034#section-3.5
* @ see https : //www.rfc-editor.org/rfc/rfc1123#section-2.1
* @ see https : //www.rfc-editor.org/rfc/rfc1035#section-2.3.4
* @ param { string } domain
* @ param { string } domain
* /
* /
function validateCookieDomain ( domain ) {
function validateCookieDomain ( domain ) {
if (
// <domain> ::= <subdomain> | " "
domain . startsWith ( '-' ) ||
if ( domain === ' ' ) {
domain . endsWith ( '.' ) ||
return
domain . endsWith ( '-' )
}
) {
if ( domain . length > 255 ) {
throw new Error ( 'Invalid cookie domain' )
}
let labelLength = 0
for ( let i = 0 ; i < domain . length ; ++ i ) {
const code = domain . charCodeAt ( i )
if ( code === 0x2E ) {
if ( labelLength === 0 ) {
throw new Error ( 'Invalid cookie domain' )
}
if ( domain . charCodeAt ( i - 1 ) === 0x2D ) { // "-"
throw new Error ( 'Invalid cookie domain' )
}
labelLength = 0
continue
}
if ( labelLength === 0 && ! isLetterOrDigit ( code ) ) {
throw new Error ( 'Invalid cookie domain' )
}
if ( ! isLetterOrDigit ( code ) && code !== 0x2D ) { // "-"
throw new Error ( 'Invalid cookie domain' )
}
if ( ++ labelLength > 63 ) {
throw new Error ( 'Invalid cookie domain' )
}
}
if ( labelLength === 0 || domain . charCodeAt ( domain . length - 1 ) === 0x2D ) { // "-"
throw new Error ( 'Invalid cookie domain' )
throw new Error ( 'Invalid cookie domain' )
}
}
}
}
@ -24686,7 +24977,13 @@ function stringify (cookie) {
const [ key , ... value ] = part . split ( '=' )
const [ key , ... value ] = part . split ( '=' )
out . push ( ` ${ key . trim ( ) } = ${ value . join ( '=' ) } ` )
const trimmedKey = key . trim ( )
const joinedValue = value . join ( '=' )
validateCookieName ( trimmedKey )
validateCookieValue ( joinedValue )
out . push ( ` ${ trimmedKey } = ${ joinedValue } ` )
}
}
return out . join ( '; ' )
return out . join ( '; ' )
@ -97137,7 +97434,7 @@ function combine(acc, pre, values, max, maxLength, dropEmpties) {
}
}
// The expansion values of a single numeric (`1..5`) or alphabetic (`a..e..2`)
// The expansion values of a single numeric (`1..5`) or alphabetic (`a..e..2`)
// sequence body.
// sequence body.
function expandSequence ( body , isAlphaSequence , max ) {
function expandSequence ( body , isAlphaSequence , max , maxLength ) {
const n = body . split ( /\.\./ ) ;
const n = body . split ( /\.\./ ) ;
const N = [ ] ;
const N = [ ] ;
// A sequence body always splits into two or three parts, but the compiler
// A sequence body always splits into two or three parts, but the compiler
@ -97160,6 +97457,7 @@ function expandSequence(body, isAlphaSequence, max) {
test = gte ;
test = gte ;
}
}
const pad = n . some ( isPadded ) ;
const pad = n . some ( isPadded ) ;
let length = 0 ;
for ( let i = x ; test ( i , y ) && N . length < max ; i += incr ) {
for ( let i = x ; test ( i , y ) && N . length < max ; i += incr ) {
let c ;
let c ;
if ( isAlphaSequence ) {
if ( isAlphaSequence ) {
@ -97183,7 +97481,10 @@ function expandSequence(body, isAlphaSequence, max) {
}
}
}
}
}
}
if ( length + c . length > maxLength )
break ;
N . push ( c ) ;
N . push ( c ) ;
length += c . length ;
}
}
return N ;
return N ;
}
}
@ -97237,7 +97538,7 @@ function expand_(str, max, maxLength, isTop) {
}
}
let values ;
let values ;
if ( isSequence ) {
if ( isSequence ) {
values = expandSequence ( m . body , isAlphaSequence , max );
values = expandSequence ( m . body , isAlphaSequence , max , maxLength );
}
}
else {
else {
let n = parseCommaParts ( m . body ) ;
let n = parseCommaParts ( m . body ) ;
@ -97255,9 +97556,31 @@ function expand_(str, max, maxLength, isTop) {
}
}
/* c8 ignore stop */
/* c8 ignore stop */
}
}
// Values that `combine` is going to drop as empty produce no result, so
// they must not count against `max` - otherwise `{a,,b}` with `max: 2`
// would stop at `['a', '']` and yield one result instead of two. Skipping
// them outright keeps `values` bounded while leaving `max` a bound on
// *kept* results.
let dropsEmpties = dropEmpties && ! m . post . length && ! pre ;
for ( let d = 0 ; dropsEmpties && d < acc . length ; d ++ ) {
if ( acc [ d ] ) {
dropsEmpties = false ;
}
}
values = [ ] ;
values = [ ] ;
for ( let j = 0 ; j < n . length ; j ++ ) {
let valuesLength = 0 ;
values . push . apply ( values , expand _ ( n [ j ] , max , maxLength , false ) ) ;
outer : for ( let j = 0 ; j < n . length ; j ++ ) {
const expanded = expand _ ( n [ j ] , max , maxLength , false ) ;
for ( let k = 0 ; k < expanded . length ; k ++ ) {
const v = expanded [ k ] ;
if ( dropsEmpties && ! v )
continue ;
if ( values . length >= max || valuesLength + v . length > maxLength ) {
break outer ;
}
values . push ( v ) ;
valuesLength += v . length ;
}
}
}
}
}
acc = combine ( acc , pre , values , max , maxLength , dropEmpties && ! m . post . length ) ;
acc = combine ( acc , pre , values , max , maxLength , dropEmpties && ! m . post . length ) ;