UNPKG

rsbuild-plugin-dts

Version:

Rsbuild plugin that supports emitting declaration files for TypeScript.

1,153 lines (1,152 loc) 212 kB
import { logger } from "@rsbuild/core"; import node_path, { basename, dirname, extname, isAbsolute, join, normalize, relative as external_node_path_relative, resolve } from "node:path"; import node_fs from "node:fs"; import node_module, { createRequire } from "node:module"; import fs_0, * as __rspack_external_fs from "fs"; import { readdir, readdirSync, realpath, realpathSync, stat as external_fs_stat, statSync } from "fs"; import os from "os"; import path_0, { basename as external_path_basename, dirname as external_path_dirname, isAbsolute as external_path_isAbsolute, normalize as external_path_normalize, posix, relative as external_path_relative, resolve as external_path_resolve, sep as external_path_sep } from "path"; import promises from "node:fs/promises"; import { platform } from "node:os"; import { styleText } from "node:util"; import { fileURLToPath } from "url"; import { createRequire as external_module_createRequire } from "module"; import { __webpack_require__ } from "./rslib-runtime.js"; import { createRequire as __rspack_createRequire } from "node:module"; const __rspack_createRequire_require = __rspack_createRequire(import.meta.url); __webpack_require__.add({ "../../node_modules/.pnpm/picomatch@4.0.4/node_modules/picomatch/index.js" (module, __unused_rspack_exports, __webpack_require__) { const pico = __webpack_require__("../../node_modules/.pnpm/picomatch@4.0.4/node_modules/picomatch/lib/picomatch.js"); const utils = __webpack_require__("../../node_modules/.pnpm/picomatch@4.0.4/node_modules/picomatch/lib/utils.js"); function picomatch(glob, options, returnState = false) { if (options && (null === options.windows || void 0 === options.windows)) options = { ...options, windows: utils.isWindows() }; return pico(glob, options, returnState); } Object.assign(picomatch, pico); module.exports = picomatch; }, "../../node_modules/.pnpm/picomatch@4.0.4/node_modules/picomatch/lib/constants.js" (module) { const WIN_SLASH = '\\\\/'; const WIN_NO_SLASH = `[^${WIN_SLASH}]`; const DEFAULT_MAX_EXTGLOB_RECURSION = 0; const DOT_LITERAL = '\\.'; const PLUS_LITERAL = '\\+'; const QMARK_LITERAL = '\\?'; const SLASH_LITERAL = '\\/'; const ONE_CHAR = '(?=.)'; const QMARK = '[^/]'; const END_ANCHOR = `(?:${SLASH_LITERAL}|$)`; const START_ANCHOR = `(?:^|${SLASH_LITERAL})`; const DOTS_SLASH = `${DOT_LITERAL}{1,2}${END_ANCHOR}`; const NO_DOT = `(?!${DOT_LITERAL})`; const NO_DOTS = `(?!${START_ANCHOR}${DOTS_SLASH})`; const NO_DOT_SLASH = `(?!${DOT_LITERAL}{0,1}${END_ANCHOR})`; const NO_DOTS_SLASH = `(?!${DOTS_SLASH})`; const QMARK_NO_DOT = `[^.${SLASH_LITERAL}]`; const STAR = `${QMARK}*?`; const SEP = '/'; const POSIX_CHARS = { DOT_LITERAL, PLUS_LITERAL, QMARK_LITERAL, SLASH_LITERAL, ONE_CHAR, QMARK, END_ANCHOR, DOTS_SLASH, NO_DOT, NO_DOTS, NO_DOT_SLASH, NO_DOTS_SLASH, QMARK_NO_DOT, STAR, START_ANCHOR, SEP }; const WINDOWS_CHARS = { ...POSIX_CHARS, SLASH_LITERAL: `[${WIN_SLASH}]`, QMARK: WIN_NO_SLASH, STAR: `${WIN_NO_SLASH}*?`, DOTS_SLASH: `${DOT_LITERAL}{1,2}(?:[${WIN_SLASH}]|$)`, NO_DOT: `(?!${DOT_LITERAL})`, NO_DOTS: `(?!(?:^|[${WIN_SLASH}])${DOT_LITERAL}{1,2}(?:[${WIN_SLASH}]|$))`, NO_DOT_SLASH: `(?!${DOT_LITERAL}{0,1}(?:[${WIN_SLASH}]|$))`, NO_DOTS_SLASH: `(?!${DOT_LITERAL}{1,2}(?:[${WIN_SLASH}]|$))`, QMARK_NO_DOT: `[^.${WIN_SLASH}]`, START_ANCHOR: `(?:^|[${WIN_SLASH}])`, END_ANCHOR: `(?:[${WIN_SLASH}]|$)`, SEP: '\\' }; const POSIX_REGEX_SOURCE = { __proto__: null, alnum: 'a-zA-Z0-9', alpha: 'a-zA-Z', ascii: '\\x00-\\x7F', blank: ' \\t', cntrl: '\\x00-\\x1F\\x7F', digit: '0-9', graph: '\\x21-\\x7E', lower: 'a-z', print: '\\x20-\\x7E ', punct: '\\-!"#$%&\'()\\*+,./:;<=>?@[\\]^_`{|}~', space: ' \\t\\r\\n\\v\\f', upper: 'A-Z', word: 'A-Za-z0-9_', xdigit: 'A-Fa-f0-9' }; module.exports = { DEFAULT_MAX_EXTGLOB_RECURSION, MAX_LENGTH: 65536, POSIX_REGEX_SOURCE, REGEX_BACKSLASH: /\\(?![*+?^${}(|)[\]])/g, REGEX_NON_SPECIAL_CHARS: /^[^@![\].,$*+?^{}()|\\/]+/, REGEX_SPECIAL_CHARS: /[-*+?.^${}(|)[\]]/, REGEX_SPECIAL_CHARS_BACKREF: /(\\?)((\W)(\3*))/g, REGEX_SPECIAL_CHARS_GLOBAL: /([-*+?.^${}(|)[\]])/g, REGEX_REMOVE_BACKSLASH: /(?:\[.*?[^\\]\]|\\(?=.))/g, REPLACEMENTS: { __proto__: null, '***': '*', '**/**': '**', '**/**/**': '**' }, CHAR_0: 48, CHAR_9: 57, CHAR_UPPERCASE_A: 65, CHAR_LOWERCASE_A: 97, CHAR_UPPERCASE_Z: 90, CHAR_LOWERCASE_Z: 122, CHAR_LEFT_PARENTHESES: 40, CHAR_RIGHT_PARENTHESES: 41, CHAR_ASTERISK: 42, CHAR_AMPERSAND: 38, CHAR_AT: 64, CHAR_BACKWARD_SLASH: 92, CHAR_CARRIAGE_RETURN: 13, CHAR_CIRCUMFLEX_ACCENT: 94, CHAR_COLON: 58, CHAR_COMMA: 44, CHAR_DOT: 46, CHAR_DOUBLE_QUOTE: 34, CHAR_EQUAL: 61, CHAR_EXCLAMATION_MARK: 33, CHAR_FORM_FEED: 12, CHAR_FORWARD_SLASH: 47, CHAR_GRAVE_ACCENT: 96, CHAR_HASH: 35, CHAR_HYPHEN_MINUS: 45, CHAR_LEFT_ANGLE_BRACKET: 60, CHAR_LEFT_CURLY_BRACE: 123, CHAR_LEFT_SQUARE_BRACKET: 91, CHAR_LINE_FEED: 10, CHAR_NO_BREAK_SPACE: 160, CHAR_PERCENT: 37, CHAR_PLUS: 43, CHAR_QUESTION_MARK: 63, CHAR_RIGHT_ANGLE_BRACKET: 62, CHAR_RIGHT_CURLY_BRACE: 125, CHAR_RIGHT_SQUARE_BRACKET: 93, CHAR_SEMICOLON: 59, CHAR_SINGLE_QUOTE: 39, CHAR_SPACE: 32, CHAR_TAB: 9, CHAR_UNDERSCORE: 95, CHAR_VERTICAL_LINE: 124, CHAR_ZERO_WIDTH_NOBREAK_SPACE: 65279, extglobChars (chars) { return { '!': { type: 'negate', open: '(?:(?!(?:', close: `))${chars.STAR})` }, '?': { type: 'qmark', open: '(?:', close: ')?' }, '+': { type: 'plus', open: '(?:', close: ')+' }, '*': { type: 'star', open: '(?:', close: ')*' }, '@': { type: 'at', open: '(?:', close: ')' } }; }, globChars (win32) { return true === win32 ? WINDOWS_CHARS : POSIX_CHARS; } }; }, "../../node_modules/.pnpm/picomatch@4.0.4/node_modules/picomatch/lib/parse.js" (module, __unused_rspack_exports, __webpack_require__) { const constants = __webpack_require__("../../node_modules/.pnpm/picomatch@4.0.4/node_modules/picomatch/lib/constants.js"); const utils = __webpack_require__("../../node_modules/.pnpm/picomatch@4.0.4/node_modules/picomatch/lib/utils.js"); const { MAX_LENGTH, POSIX_REGEX_SOURCE, REGEX_NON_SPECIAL_CHARS, REGEX_SPECIAL_CHARS_BACKREF, REPLACEMENTS } = constants; const expandRange = (args, options)=>{ if ('function' == typeof options.expandRange) return options.expandRange(...args, options); args.sort(); const value = `[${args.join('-')}]`; try { new RegExp(value); } catch (ex) { return args.map((v)=>utils.escapeRegex(v)).join('..'); } return value; }; const syntaxError = (type, char)=>`Missing ${type}: "${char}" - use "\\\\${char}" to match literal characters`; const splitTopLevel = (input)=>{ const parts = []; let bracket = 0; let paren = 0; let quote = 0; let value = ''; let escaped = false; for (const ch of input){ if (true === escaped) { value += ch; escaped = false; continue; } if ('\\' === ch) { value += ch; escaped = true; continue; } if ('"' === ch) { quote = 1 === quote ? 0 : 1; value += ch; continue; } if (0 === quote) { if ('[' === ch) bracket++; else if (']' === ch && bracket > 0) bracket--; else if (0 === bracket) { if ('(' === ch) paren++; else if (')' === ch && paren > 0) paren--; else if ('|' === ch && 0 === paren) { parts.push(value); value = ''; continue; } } } value += ch; } parts.push(value); return parts; }; const isPlainBranch = (branch)=>{ let escaped = false; for (const ch of branch){ if (true === escaped) { escaped = false; continue; } if ('\\' === ch) { escaped = true; continue; } if (/[?*+@!()[\]{}]/.test(ch)) return false; } return true; }; const normalizeSimpleBranch = (branch)=>{ let value = branch.trim(); let changed = true; while(true === changed){ changed = false; if (/^@\([^\\()[\]{}|]+\)$/.test(value)) { value = value.slice(2, -1); changed = true; } } if (!isPlainBranch(value)) return; return value.replace(/\\(.)/g, '$1'); }; const hasRepeatedCharPrefixOverlap = (branches)=>{ const values = branches.map(normalizeSimpleBranch).filter(Boolean); for(let i = 0; i < values.length; i++)for(let j = i + 1; j < values.length; j++){ const a = values[i]; const b = values[j]; const char = a[0]; if (char && a === char.repeat(a.length) && b === char.repeat(b.length)) { if (a === b || a.startsWith(b) || b.startsWith(a)) return true; } } return false; }; const parseRepeatedExtglob = (pattern, requireEnd = true)=>{ if ('+' !== pattern[0] && '*' !== pattern[0] || '(' !== pattern[1]) return; let bracket = 0; let paren = 0; let quote = 0; let escaped = false; for(let i = 1; i < pattern.length; i++){ const ch = pattern[i]; if (true === escaped) { escaped = false; continue; } if ('\\' === ch) { escaped = true; continue; } if ('"' === ch) { quote = 1 === quote ? 0 : 1; continue; } if (1 !== quote) { if ('[' === ch) { bracket++; continue; } if (']' === ch && bracket > 0) { bracket--; continue; } if (!(bracket > 0)) { if ('(' === ch) { paren++; continue; } if (')' === ch) { paren--; if (0 === paren) { if (true === requireEnd && i !== pattern.length - 1) return; return { type: pattern[0], body: pattern.slice(2, i), end: i }; } } } } } }; const getStarExtglobSequenceOutput = (pattern)=>{ let index = 0; const chars = []; while(index < pattern.length){ const match = parseRepeatedExtglob(pattern.slice(index), false); if (!match || '*' !== match.type) return; const branches = splitTopLevel(match.body).map((branch)=>branch.trim()); if (1 !== branches.length) return; const branch = normalizeSimpleBranch(branches[0]); if (!branch || 1 !== branch.length) return; chars.push(branch); index += match.end + 1; } if (chars.length < 1) return; const source = 1 === chars.length ? utils.escapeRegex(chars[0]) : `[${chars.map((ch)=>utils.escapeRegex(ch)).join('')}]`; return `${source}*`; }; const repeatedExtglobRecursion = (pattern)=>{ let depth = 0; let value = pattern.trim(); let match = parseRepeatedExtglob(value); while(match){ depth++; value = match.body.trim(); match = parseRepeatedExtglob(value); } return depth; }; const analyzeRepeatedExtglob = (body, options)=>{ if (false === options.maxExtglobRecursion) return { risky: false }; const max = 'number' == typeof options.maxExtglobRecursion ? options.maxExtglobRecursion : constants.DEFAULT_MAX_EXTGLOB_RECURSION; const branches = splitTopLevel(body).map((branch)=>branch.trim()); if (branches.length > 1) { if (branches.some((branch)=>'' === branch) || branches.some((branch)=>/^[*?]+$/.test(branch)) || hasRepeatedCharPrefixOverlap(branches)) return { risky: true }; } for (const branch of branches){ const safeOutput = getStarExtglobSequenceOutput(branch); if (safeOutput) return { risky: true, safeOutput }; if (repeatedExtglobRecursion(branch) > max) return { risky: true }; } return { risky: false }; }; const parse = (input, options)=>{ if ('string' != typeof input) throw new TypeError('Expected a string'); input = REPLACEMENTS[input] || input; const opts = { ...options }; const max = 'number' == typeof opts.maxLength ? Math.min(MAX_LENGTH, opts.maxLength) : MAX_LENGTH; let len = input.length; if (len > max) throw new SyntaxError(`Input length: ${len}, exceeds maximum allowed length: ${max}`); const bos = { type: 'bos', value: '', output: opts.prepend || '' }; const tokens = [ bos ]; const capture = opts.capture ? '' : '?:'; const PLATFORM_CHARS = constants.globChars(opts.windows); const EXTGLOB_CHARS = constants.extglobChars(PLATFORM_CHARS); const { DOT_LITERAL, PLUS_LITERAL, SLASH_LITERAL, ONE_CHAR, DOTS_SLASH, NO_DOT, NO_DOT_SLASH, NO_DOTS_SLASH, QMARK, QMARK_NO_DOT, STAR, START_ANCHOR } = PLATFORM_CHARS; const globstar = (opts)=>`(${capture}(?:(?!${START_ANCHOR}${opts.dot ? DOTS_SLASH : DOT_LITERAL}).)*?)`; const nodot = opts.dot ? '' : NO_DOT; const qmarkNoDot = opts.dot ? QMARK : QMARK_NO_DOT; let star = true === opts.bash ? globstar(opts) : STAR; if (opts.capture) star = `(${star})`; if ('boolean' == typeof opts.noext) opts.noextglob = opts.noext; const state = { input, index: -1, start: 0, dot: true === opts.dot, consumed: '', output: '', prefix: '', backtrack: false, negated: false, brackets: 0, braces: 0, parens: 0, quotes: 0, globstar: false, tokens }; input = utils.removePrefix(input, state); len = input.length; const extglobs = []; const braces = []; const stack = []; let prev = bos; let value; const eos = ()=>state.index === len - 1; const peek = state.peek = (n = 1)=>input[state.index + n]; const advance = state.advance = ()=>input[++state.index] || ''; const remaining = ()=>input.slice(state.index + 1); const consume = (value = '', num = 0)=>{ state.consumed += value; state.index += num; }; const append = (token)=>{ state.output += null != token.output ? token.output : token.value; consume(token.value); }; const negate = ()=>{ let count = 1; while('!' === peek() && ('(' !== peek(2) || '?' === peek(3))){ advance(); state.start++; count++; } if (count % 2 === 0) return false; state.negated = true; state.start++; return true; }; const increment = (type)=>{ state[type]++; stack.push(type); }; const decrement = (type)=>{ state[type]--; stack.pop(); }; const push = (tok)=>{ if ('globstar' === prev.type) { const isBrace = state.braces > 0 && ('comma' === tok.type || 'brace' === tok.type); const isExtglob = true === tok.extglob || extglobs.length && ('pipe' === tok.type || 'paren' === tok.type); if ('slash' !== tok.type && 'paren' !== tok.type && !isBrace && !isExtglob) { state.output = state.output.slice(0, -prev.output.length); prev.type = 'star'; prev.value = '*'; prev.output = star; state.output += prev.output; } } if (extglobs.length && 'paren' !== tok.type) extglobs[extglobs.length - 1].inner += tok.value; if (tok.value || tok.output) append(tok); if (prev && 'text' === prev.type && 'text' === tok.type) { prev.output = (prev.output || prev.value) + tok.value; prev.value += tok.value; return; } tok.prev = prev; tokens.push(tok); prev = tok; }; const extglobOpen = (type, value)=>{ const token = { ...EXTGLOB_CHARS[value], conditions: 1, inner: '' }; token.prev = prev; token.parens = state.parens; token.output = state.output; token.startIndex = state.index; token.tokensIndex = tokens.length; const output = (opts.capture ? '(' : '') + token.open; increment('parens'); push({ type, value, output: state.output ? '' : ONE_CHAR }); push({ type: 'paren', extglob: true, value: advance(), output }); extglobs.push(token); }; const extglobClose = (token)=>{ const literal = input.slice(token.startIndex, state.index + 1); const body = input.slice(token.startIndex + 2, state.index); const analysis = analyzeRepeatedExtglob(body, opts); if (('plus' === token.type || 'star' === token.type) && analysis.risky) { const safeOutput = analysis.safeOutput ? (token.output ? '' : ONE_CHAR) + (opts.capture ? `(${analysis.safeOutput})` : analysis.safeOutput) : void 0; const open = tokens[token.tokensIndex]; open.type = 'text'; open.value = literal; open.output = safeOutput || utils.escapeRegex(literal); for(let i = token.tokensIndex + 1; i < tokens.length; i++){ tokens[i].value = ''; tokens[i].output = ''; delete tokens[i].suffix; } state.output = token.output + open.output; state.backtrack = true; push({ type: 'paren', extglob: true, value, output: '' }); decrement('parens'); return; } let output = token.close + (opts.capture ? ')' : ''); let rest; if ('negate' === token.type) { let extglobStar = star; if (token.inner && token.inner.length > 1 && token.inner.includes('/')) extglobStar = globstar(opts); if (extglobStar !== star || eos() || /^\)+$/.test(remaining())) output = token.close = `)$))${extglobStar}`; if (token.inner.includes('*') && (rest = remaining()) && /^\.[^\\/.]+$/.test(rest)) { const expression = parse(rest, { ...options, fastpaths: false }).output; output = token.close = `)${expression})${extglobStar})`; } if ('bos' === token.prev.type) state.negatedExtglob = true; } push({ type: 'paren', extglob: true, value, output }); decrement('parens'); }; if (false !== opts.fastpaths && !/(^[*!]|[/()[\]{}"])/.test(input)) { let backslashes = false; let output = input.replace(REGEX_SPECIAL_CHARS_BACKREF, (m, esc, chars, first, rest, index)=>{ if ('\\' === first) { backslashes = true; return m; } if ('?' === first) { if (esc) return esc + first + (rest ? QMARK.repeat(rest.length) : ''); if (0 === index) return qmarkNoDot + (rest ? QMARK.repeat(rest.length) : ''); return QMARK.repeat(chars.length); } if ('.' === first) return DOT_LITERAL.repeat(chars.length); if ('*' === first) { if (esc) return esc + first + (rest ? star : ''); return star; } return esc ? m : `\\${m}`; }); if (true === backslashes) output = true === opts.unescape ? output.replace(/\\/g, '') : output.replace(/\\+/g, (m)=>m.length % 2 === 0 ? '\\\\' : m ? '\\' : ''); if (output === input && true === opts.contains) { state.output = input; return state; } state.output = utils.wrapOutput(output, state, options); return state; } while(!eos()){ value = advance(); if ('\u0000' === value) continue; if ('\\' === value) { const next = peek(); if ('/' === next && true !== opts.bash) continue; if ('.' === next || ';' === next) continue; if (!next) { value += '\\'; push({ type: 'text', value }); continue; } const match = /^\\+/.exec(remaining()); let slashes = 0; if (match && match[0].length > 2) { slashes = match[0].length; state.index += slashes; if (slashes % 2 !== 0) value += '\\'; } if (true === opts.unescape) value = advance(); else value += advance(); if (0 === state.brackets) { push({ type: 'text', value }); continue; } } if (state.brackets > 0 && (']' !== value || '[' === prev.value || '[^' === prev.value)) { if (false !== opts.posix && ':' === value) { const inner = prev.value.slice(1); if (inner.includes('[')) { prev.posix = true; if (inner.includes(':')) { const idx = prev.value.lastIndexOf('['); const pre = prev.value.slice(0, idx); const rest = prev.value.slice(idx + 2); const posix = POSIX_REGEX_SOURCE[rest]; if (posix) { prev.value = pre + posix; state.backtrack = true; advance(); if (!bos.output && 1 === tokens.indexOf(prev)) bos.output = ONE_CHAR; continue; } } } } if ('[' === value && ':' !== peek() || '-' === value && ']' === peek()) value = `\\${value}`; if (']' === value && ('[' === prev.value || '[^' === prev.value)) value = `\\${value}`; if (true === opts.posix && '!' === value && '[' === prev.value) value = '^'; prev.value += value; append({ value }); continue; } if (1 === state.quotes && '"' !== value) { value = utils.escapeRegex(value); prev.value += value; append({ value }); continue; } if ('"' === value) { state.quotes = 1 === state.quotes ? 0 : 1; if (true === opts.keepQuotes) push({ type: 'text', value }); continue; } if ('(' === value) { increment('parens'); push({ type: 'paren', value }); continue; } if (')' === value) { if (0 === state.parens && true === opts.strictBrackets) throw new SyntaxError(syntaxError('opening', '(')); const extglob = extglobs[extglobs.length - 1]; if (extglob && state.parens === extglob.parens + 1) { extglobClose(extglobs.pop()); continue; } push({ type: 'paren', value, output: state.parens ? ')' : '\\)' }); decrement('parens'); continue; } if ('[' === value) { if (true !== opts.nobracket && remaining().includes(']')) increment('brackets'); else { if (true !== opts.nobracket && true === opts.strictBrackets) throw new SyntaxError(syntaxError('closing', ']')); value = `\\${value}`; } push({ type: 'bracket', value }); continue; } if (']' === value) { if (true === opts.nobracket || prev && 'bracket' === prev.type && 1 === prev.value.length) { push({ type: 'text', value, output: `\\${value}` }); continue; } if (0 === state.brackets) { if (true === opts.strictBrackets) throw new SyntaxError(syntaxError('opening', '[')); push({ type: 'text', value, output: `\\${value}` }); continue; } decrement('brackets'); const prevValue = prev.value.slice(1); if (true !== prev.posix && '^' === prevValue[0] && !prevValue.includes('/')) value = `/${value}`; prev.value += value; append({ value }); if (false === opts.literalBrackets || utils.hasRegexChars(prevValue)) continue; const escaped = utils.escapeRegex(prev.value); state.output = state.output.slice(0, -prev.value.length); if (true === opts.literalBrackets) { state.output += escaped; prev.value = escaped; continue; } prev.value = `(${capture}${escaped}|${prev.value})`; state.output += prev.value; continue; } if ('{' === value && true !== opts.nobrace) { increment('braces'); const open = { type: 'brace', value, output: '(', outputIndex: state.output.length, tokensIndex: state.tokens.length }; braces.push(open); push(open); continue; } if ('}' === value) { const brace = braces[braces.length - 1]; if (true === opts.nobrace || !brace) { push({ type: 'text', value, output: value }); continue; } let output = ')'; if (true === brace.dots) { const arr = tokens.slice(); const range = []; for(let i = arr.length - 1; i >= 0; i--){ tokens.pop(); if ('brace' === arr[i].type) break; if ('dots' !== arr[i].type) range.unshift(arr[i].value); } output = expandRange(range, opts); state.backtrack = true; } if (true !== brace.comma && true !== brace.dots) { const out = state.output.slice(0, brace.outputIndex); const toks = state.tokens.slice(brace.tokensIndex); brace.value = brace.output = '\\{'; value = output = '\\}'; state.output = out; for (const t of toks)state.output += t.output || t.value; } push({ type: 'brace', value, output }); decrement('braces'); braces.pop(); continue; } if ('|' === value) { if (extglobs.length > 0) extglobs[extglobs.length - 1].conditions++; push({ type: 'text', value }); continue; } if (',' === value) { let output = value; const brace = braces[braces.length - 1]; if (brace && 'braces' === stack[stack.length - 1]) { brace.comma = true; output = '|'; } push({ type: 'comma', value, output }); continue; } if ('/' === value) { if ('dot' === prev.type && state.index === state.start + 1) { state.start = state.index + 1; state.consumed = ''; state.output = ''; tokens.pop(); prev = bos; continue; } push({ type: 'slash', value, output: SLASH_LITERAL }); continue; } if ('.' === value) { if (state.braces > 0 && 'dot' === prev.type) { if ('.' === prev.value) prev.output = DOT_LITERAL; const brace = braces[braces.length - 1]; prev.type = 'dots'; prev.output += value; prev.value += value; brace.dots = true; continue; } if (state.braces + state.parens === 0 && 'bos' !== prev.type && 'slash' !== prev.type) { push({ type: 'text', value, output: DOT_LITERAL }); continue; } push({ type: 'dot', value, output: DOT_LITERAL }); continue; } if ('?' === value) { const isGroup = prev && '(' === prev.value; if (!isGroup && true !== opts.noextglob && '(' === peek() && '?' !== peek(2)) { extglobOpen('qmark', value); continue; } if (prev && 'paren' === prev.type) { const next = peek(); let output = value; if ('(' === prev.value && !/[!=<:]/.test(next) || '<' === next && !/<([!=]|\w+>)/.test(remaining())) output = `\\${value}`; push({ type: 'text', value, output }); continue; } if (true !== opts.dot && ('slash' === prev.type || 'bos' === prev.type)) { push({ type: 'qmark', value, output: QMARK_NO_DOT }); continue; } push({ type: 'qmark', value, output: QMARK }); continue; } if ('!' === value) { if (true !== opts.noextglob && '(' === peek()) { if ('?' !== peek(2) || !/[!=<:]/.test(peek(3))) { extglobOpen('negate', value); continue; } } if (true !== opts.nonegate && 0 === state.index) { negate(); continue; } } if ('+' === value) { if (true !== opts.noextglob && '(' === peek() && '?' !== peek(2)) { extglobOpen('plus', value); continue; } if (prev && '(' === prev.value || false === opts.regex) { push({ type: 'plus', value, output: PLUS_LITERAL }); continue; } if (prev && ('bracket' === prev.type || 'paren' === prev.type || 'brace' === prev.type) || state.parens > 0) { push({ type: 'plus', value }); continue; } push({ type: 'plus', value: PLUS_LITERAL }); continue; } if ('@' === value) { if (true !== opts.noextglob && '(' === peek() && '?' !== peek(2)) { push({ type: 'at', extglob: true, value, output: '' }); continue; } push({ type: 'text', value }); continue; } if ('*' !== value) { if ('$' === value || '^' === value) value = `\\${value}`; const match = REGEX_NON_SPECIAL_CHARS.exec(remaining()); if (match) { value += match[0]; state.index += match[0].length; } push({ type: 'text', value }); continue; } if (prev && ('globstar' === prev.type || true === prev.star)) { prev.type = 'star'; prev.star = true; prev.value += value; prev.output = star; state.backtrack = true; state.globstar = true; consume(value); continue; } let rest = remaining(); if (true !== opts.noextglob && /^\([^?]/.test(rest)) { extglobOpen('star', value); continue; } if ('star' === prev.type) { if (true === opts.noglobstar) { consume(value); continue; } const prior = prev.prev; const before = prior.prev; const isStart = 'slash' === prior.type || 'bos' === prior.type; const afterStar = before && ('star' === before.type || 'globstar' === before.type); if (true === opts.bash && (!isStart || rest[0] && '/' !== rest[0])) { push({ type: 'star', value, output: '' }); continue; } const isBrace = state.braces > 0 && ('comma' === prior.type || 'brace' === prior.type); const isExtglob = extglobs.length && ('pipe' === prior.type || 'paren' === prior.type); if (!isStart && 'paren' !== prior.type && !isBrace && !isExtglob) { push({ type: 'star', value, output: '' }); continue; } while('/**' === rest.slice(0, 3)){ const after = input[state.index + 4]; if (after && '/' !== after) break; rest = rest.slice(3); consume('/**', 3); } if ('bos' === prior.type && eos()) { prev.type = 'globstar'; prev.value += value; prev.output = globstar(opts); state.output = prev.output; state.globstar = true; consume(value); continue; } if ('slash' === prior.type && 'bos' !== prior.prev.type && !afterStar && eos()) { state.output = state.output.slice(0, -(prior.output + prev.output).length); prior.output = `(?:${prior.output}`; prev.type = 'globstar'; prev.output = globstar(opts) + (opts.strictSlashes ? ')' : '|$)'); prev.value += value; state.globstar = true; state.output += prior.output + prev.output; consume(value); continue; } if ('slash' === prior.type && 'bos' !== prior.prev.type && '/' === rest[0]) { const end = void 0 !== rest[1] ? '|$' : ''; state.output = state.output.slice(0, -(prior.output + prev.output).length); prior.output = `(?:${prior.output}`; prev.type = 'globstar'; prev.output = `${globstar(opts)}${SLASH_LITERAL}|${SLASH_LITERAL}${end})`; prev.value += value; state.output += prior.output + prev.output; state.globstar = true; consume(value + advance()); push({ type: 'slash', value: '/', output: '' }); continue; } if ('bos' === prior.type && '/' === rest[0]) { prev.type = 'globstar'; prev.value += value; prev.output = `(?:^|${SLASH_LITERAL}|${globstar(opts)}${SLASH_LITERAL})`; state.output = prev.output; state.globstar = true; consume(value + advance()); push({ type: 'slash', value: '/', output: '' }); continue; } state.output = state.output.slice(0, -prev.output.length); prev.type = 'globstar'; prev.output = globstar(opts); prev.value += value; state.output += prev.output; state.globstar = true; consume(value); continue; } const token = { type: 'star', value, output: star }; if (true === opts.bash) { token.output = '.*?'; if ('bos' === prev.type || 'slash' === prev.type) token.output = nodot + token.output; push(token); continue; } if (prev && ('bracket' === prev.type || 'paren' === prev.type) && true === opts.regex) { token.output = value; push(token); continue; } if (state.index === state.start || 'slash' === prev.type || 'dot' === prev.type) { if ('dot' === prev.type) { state.output += NO_DOT_SLASH; prev.output += NO_DOT_SLASH; } else if (true === opts.dot) { state.output += NO_DOTS_SLASH; prev.output += NO_DOTS_SLASH; } else { state.output += nodot; prev.output += nodot; } if ('*' !== peek()) { state.output += ONE_CHAR; prev.output += ONE_CHAR; } } push(token); } while(state.brackets > 0){ if (true === opts.strictBrackets) throw new SyntaxError(syntaxError('closing', ']')); state.output = utils.escapeLast(state.output, '['); decrement('brackets'); } while(state.parens > 0){ if (true === opts.strictBrackets) throw new SyntaxError(syntaxError('closing', ')')); state.output = utils.escapeLast(state.output, '('); decrement('parens'); } while(state.braces > 0){ if (true === opts.strictBrackets) throw new SyntaxError(syntaxError('closing', '}')); state.output = utils.escapeLast(state.output, '{'); decrement('braces'); } if (true !== opts.strictSlashes && ('star' === prev.type || 'bracket' === prev.type)) push({ type: 'maybe_slash', value: '', output: `${SLASH_LITERAL}?` }); if (true === state.backtrack) { state.output = ''; for (const token of state.tokens){ state.output += null != token.output ? token.output : token.value; if (token.suffix) state.output += token.suffix; } } return state; }; parse.fastpaths = (input, options)=>{ const opts = { ...options }; const max = 'number' == typeof opts.maxLength ? Math.min(MAX_LENGTH, opts.maxLength) : MAX_LENGTH; const len = input.length; if (len > max) throw new SyntaxError(`Input length: ${len}, exceeds maximum allowed length: ${max}`); input = REPLACEMENTS[input] || input; const { DOT_LITERAL, SLASH_LITERAL, ONE_CHAR, DOTS_SLASH, NO_DOT, NO_DOTS, NO_DOTS_SLASH, STAR, START_ANCHOR } = constants.globChars(opts.windows); const nodot = opts.dot ? NO_DOTS : NO_DOT; const slashDot = opts.dot ? NO_DOTS_SLASH : NO_DOT; const capture = opts.capture ? '' : '?:'; const state = { negated: false, prefix: '' }; let star = true === opts.bash ? '.*?' : STAR; if (opts.capture) star = `(${star})`;