From 0c2517884d4afd5c6856ff3dca7951e97cd3e11d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 28 Aug 2026 10:02:05 +0000 Subject: [PATCH] Sync generated provider output --- .../scripts/lib/live-path-globs.mjs | 37 ++++++++++++++++ .../skills/impeccable/scripts/live-inject.mjs | 44 +------------------ .agents/skills/impeccable/scripts/live.mjs | 35 +-------------- .../scripts/lib/live-path-globs.mjs | 37 ++++++++++++++++ .../skills/impeccable/scripts/live-inject.mjs | 44 +------------------ .claude/skills/impeccable/scripts/live.mjs | 35 +-------------- .../scripts/lib/live-path-globs.mjs | 37 ++++++++++++++++ .../skills/impeccable/scripts/live-inject.mjs | 44 +------------------ .cursor/skills/impeccable/scripts/live.mjs | 35 +-------------- .../scripts/lib/live-path-globs.mjs | 37 ++++++++++++++++ .../skills/impeccable/scripts/live-inject.mjs | 44 +------------------ .gemini/skills/impeccable/scripts/live.mjs | 35 +-------------- .../scripts/lib/live-path-globs.mjs | 37 ++++++++++++++++ .../skills/impeccable/scripts/live-inject.mjs | 44 +------------------ .github/skills/impeccable/scripts/live.mjs | 35 +-------------- .../scripts/lib/live-path-globs.mjs | 37 ++++++++++++++++ .../skills/impeccable/scripts/live-inject.mjs | 44 +------------------ .grok/skills/impeccable/scripts/live.mjs | 35 +-------------- .../scripts/lib/live-path-globs.mjs | 37 ++++++++++++++++ .../skills/impeccable/scripts/live-inject.mjs | 44 +------------------ .hermes/skills/impeccable/scripts/live.mjs | 35 +-------------- .../scripts/lib/live-path-globs.mjs | 37 ++++++++++++++++ .../skills/impeccable/scripts/live-inject.mjs | 44 +------------------ .kiro/skills/impeccable/scripts/live.mjs | 35 +-------------- .../scripts/lib/live-path-globs.mjs | 37 ++++++++++++++++ .../skills/impeccable/scripts/live-inject.mjs | 44 +------------------ .opencode/skills/impeccable/scripts/live.mjs | 35 +-------------- .../scripts/lib/live-path-globs.mjs | 37 ++++++++++++++++ .pi/skills/impeccable/scripts/live-inject.mjs | 44 +------------------ .pi/skills/impeccable/scripts/live.mjs | 35 +-------------- .../scripts/lib/live-path-globs.mjs | 37 ++++++++++++++++ .../skills/impeccable/scripts/live-inject.mjs | 44 +------------------ .qoder/skills/impeccable/scripts/live.mjs | 35 +-------------- .../scripts/lib/live-path-globs.mjs | 37 ++++++++++++++++ .../skills/impeccable/scripts/live-inject.mjs | 44 +------------------ .rovodev/skills/impeccable/scripts/live.mjs | 35 +-------------- .../scripts/lib/live-path-globs.mjs | 37 ++++++++++++++++ .../skills/impeccable/scripts/live-inject.mjs | 44 +------------------ .trae-cn/skills/impeccable/scripts/live.mjs | 35 +-------------- .../scripts/lib/live-path-globs.mjs | 37 ++++++++++++++++ .../skills/impeccable/scripts/live-inject.mjs | 44 +------------------ .trae/skills/impeccable/scripts/live.mjs | 35 +-------------- .../scripts/lib/live-path-globs.mjs | 37 ++++++++++++++++ .../skills/impeccable/scripts/live-inject.mjs | 44 +------------------ .vibe/skills/impeccable/scripts/live.mjs | 35 +-------------- .../scripts/lib/live-path-globs.mjs | 37 ++++++++++++++++ .../skills/impeccable/scripts/live-inject.mjs | 44 +------------------ plugin/skills/impeccable/scripts/live.mjs | 35 +-------------- 48 files changed, 656 insertions(+), 1200 deletions(-) create mode 100644 .agents/skills/impeccable/scripts/lib/live-path-globs.mjs create mode 100644 .claude/skills/impeccable/scripts/lib/live-path-globs.mjs create mode 100644 .cursor/skills/impeccable/scripts/lib/live-path-globs.mjs create mode 100644 .gemini/skills/impeccable/scripts/lib/live-path-globs.mjs create mode 100644 .github/skills/impeccable/scripts/lib/live-path-globs.mjs create mode 100644 .grok/skills/impeccable/scripts/lib/live-path-globs.mjs create mode 100644 .hermes/skills/impeccable/scripts/lib/live-path-globs.mjs create mode 100644 .kiro/skills/impeccable/scripts/lib/live-path-globs.mjs create mode 100644 .opencode/skills/impeccable/scripts/lib/live-path-globs.mjs create mode 100644 .pi/skills/impeccable/scripts/lib/live-path-globs.mjs create mode 100644 .qoder/skills/impeccable/scripts/lib/live-path-globs.mjs create mode 100644 .rovodev/skills/impeccable/scripts/lib/live-path-globs.mjs create mode 100644 .trae-cn/skills/impeccable/scripts/lib/live-path-globs.mjs create mode 100644 .trae/skills/impeccable/scripts/lib/live-path-globs.mjs create mode 100644 .vibe/skills/impeccable/scripts/lib/live-path-globs.mjs create mode 100644 plugin/skills/impeccable/scripts/lib/live-path-globs.mjs diff --git a/.agents/skills/impeccable/scripts/lib/live-path-globs.mjs b/.agents/skills/impeccable/scripts/lib/live-path-globs.mjs new file mode 100644 index 000000000..4a3eebda0 --- /dev/null +++ b/.agents/skills/impeccable/scripts/lib/live-path-globs.mjs @@ -0,0 +1,37 @@ +/** + * Convert a live-config glob pattern to a RegExp. + * + * Supports `**` across path segments, `*` within one segment, and `?` for one + * character. Callers normalize project-relative paths to forward slashes. + */ +export function livePathGlobToRegex(pattern) { + let re = ''; + let i = 0; + while (i < pattern.length) { + const c = pattern[i]; + if (c === '*') { + if (pattern[i + 1] === '*') { + if (pattern[i + 2] === '/') { + re += '(?:.*/)?'; + i += 3; + } else { + re += '.*'; + i += 2; + } + } else { + re += '[^/]*'; + i += 1; + } + } else if (c === '?') { + re += '[^/]'; + i += 1; + } else if (/[.+^${}()|[\]\\]/.test(c)) { + re += `\\${c}`; + i += 1; + } else { + re += c; + i += 1; + } + } + return new RegExp(`^${re}$`); +} diff --git a/.agents/skills/impeccable/scripts/live-inject.mjs b/.agents/skills/impeccable/scripts/live-inject.mjs index 81848010b..0b5fe9c18 100644 --- a/.agents/skills/impeccable/scripts/live-inject.mjs +++ b/.agents/skills/impeccable/scripts/live-inject.mjs @@ -27,6 +27,7 @@ import fs from 'node:fs'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; import { resolveLiveConfigPath } from './lib/impeccable-paths.mjs'; +import { livePathGlobToRegex } from './lib/live-path-globs.mjs'; import { describeInjectArtifacts, frameworkIgnorePatterns, @@ -364,7 +365,7 @@ export function resolveFiles(rootDir, config) { const patterns = config.files; const userExcludes = Array.isArray(config.exclude) ? config.exclude : []; const allExcludes = [...HARD_EXCLUDES, ...userExcludes]; - const excludeRegexes = allExcludes.map(globToRegex); + const excludeRegexes = allExcludes.map(livePathGlobToRegex); const isExcluded = (relPath) => excludeRegexes.some((re) => re.test(relPath)); const isGlob = (s) => /[*?[]/.test(s); @@ -401,47 +402,6 @@ export function resolveFiles(rootDir, config) { return out; } -/** - * Convert a glob pattern to a RegExp. Supports: - * ** → any number of path segments (including zero) - * * → any chars except `/` - * ? → any single char except `/` - * Paths are normalized to forward slashes before matching. - */ -function globToRegex(pattern) { - let re = ''; - let i = 0; - while (i < pattern.length) { - const c = pattern[i]; - if (c === '*') { - if (pattern[i + 1] === '*') { - // ** — any number of segments, including zero. Handle the common - // **/ and /** forms so `a/**/b` matches `a/b` as well as `a/x/y/b`. - if (pattern[i + 2] === '/') { - re += '(?:.*/)?'; - i += 3; - } else { - re += '.*'; - i += 2; - } - } else { - re += '[^/]*'; - i += 1; - } - } else if (c === '?') { - re += '[^/]'; - i += 1; - } else if (/[.+^${}()|[\]\\]/.test(c)) { - re += '\\' + c; - i += 1; - } else { - re += c; - i += 1; - } - } - return new RegExp('^' + re + '$'); -} - // --------------------------------------------------------------------------- // Core operations // --------------------------------------------------------------------------- diff --git a/.agents/skills/impeccable/scripts/live.mjs b/.agents/skills/impeccable/scripts/live.mjs index 7738c3f02..ccbef4949 100644 --- a/.agents/skills/impeccable/scripts/live.mjs +++ b/.agents/skills/impeccable/scripts/live.mjs @@ -24,6 +24,7 @@ import { fileURLToPath } from 'node:url'; import { resolveTargetSelection } from './context.mjs'; import { resolveFiles } from './live-inject.mjs'; import { readLiveServerInfo } from './lib/impeccable-paths.mjs'; +import { livePathGlobToRegex } from './lib/live-path-globs.mjs'; import { resolveSurfaceBrief } from './lib/surface-briefs.mjs'; import { resolveLiveTarget } from './live-target.mjs'; import { bootInstructions } from './live/instructions.mjs'; @@ -240,7 +241,7 @@ function scanForDrift(rootDir, resolvedFiles, config) { // Files matching the user's `exclude` globs are intentional omissions, // not drift. Compile them to regexes so the orphan list stays signal. const userExcludeRegexes = (Array.isArray(config.exclude) ? config.exclude : []) - .map((p) => globToRegex(p)); + .map(livePathGlobToRegex); const isUserExcluded = (rel) => userExcludeRegexes.some((re) => re.test(rel)); const orphans = []; @@ -278,38 +279,6 @@ function scanForDrift(rootDir, resolvedFiles, config) { }; } -/** - * Same glob-to-regex mapping used by live-inject.mjs. Kept inline here - * to avoid a circular import (live-inject.mjs already imports nothing - * from live.mjs). The two must stay in sync. - */ -function globToRegex(pattern) { - let re = ''; - let i = 0; - while (i < pattern.length) { - const c = pattern[i]; - if (c === '*') { - if (pattern[i + 1] === '*') { - if (pattern[i + 2] === '/') { re += '(?:.*/)?'; i += 3; } - else { re += '.*'; i += 2; } - } else { - re += '[^/]*'; - i += 1; - } - } else if (c === '?') { - re += '[^/]'; - i += 1; - } else if (/[.+^${}()|[\]\\]/.test(c)) { - re += '\\' + c; - i += 1; - } else { - re += c; - i += 1; - } - } - return new RegExp('^' + re + '$'); -} - // --------------------------------------------------------------------------- // Helpers // --------------------------------------------------------------------------- diff --git a/.claude/skills/impeccable/scripts/lib/live-path-globs.mjs b/.claude/skills/impeccable/scripts/lib/live-path-globs.mjs new file mode 100644 index 000000000..4a3eebda0 --- /dev/null +++ b/.claude/skills/impeccable/scripts/lib/live-path-globs.mjs @@ -0,0 +1,37 @@ +/** + * Convert a live-config glob pattern to a RegExp. + * + * Supports `**` across path segments, `*` within one segment, and `?` for one + * character. Callers normalize project-relative paths to forward slashes. + */ +export function livePathGlobToRegex(pattern) { + let re = ''; + let i = 0; + while (i < pattern.length) { + const c = pattern[i]; + if (c === '*') { + if (pattern[i + 1] === '*') { + if (pattern[i + 2] === '/') { + re += '(?:.*/)?'; + i += 3; + } else { + re += '.*'; + i += 2; + } + } else { + re += '[^/]*'; + i += 1; + } + } else if (c === '?') { + re += '[^/]'; + i += 1; + } else if (/[.+^${}()|[\]\\]/.test(c)) { + re += `\\${c}`; + i += 1; + } else { + re += c; + i += 1; + } + } + return new RegExp(`^${re}$`); +} diff --git a/.claude/skills/impeccable/scripts/live-inject.mjs b/.claude/skills/impeccable/scripts/live-inject.mjs index 81848010b..0b5fe9c18 100644 --- a/.claude/skills/impeccable/scripts/live-inject.mjs +++ b/.claude/skills/impeccable/scripts/live-inject.mjs @@ -27,6 +27,7 @@ import fs from 'node:fs'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; import { resolveLiveConfigPath } from './lib/impeccable-paths.mjs'; +import { livePathGlobToRegex } from './lib/live-path-globs.mjs'; import { describeInjectArtifacts, frameworkIgnorePatterns, @@ -364,7 +365,7 @@ export function resolveFiles(rootDir, config) { const patterns = config.files; const userExcludes = Array.isArray(config.exclude) ? config.exclude : []; const allExcludes = [...HARD_EXCLUDES, ...userExcludes]; - const excludeRegexes = allExcludes.map(globToRegex); + const excludeRegexes = allExcludes.map(livePathGlobToRegex); const isExcluded = (relPath) => excludeRegexes.some((re) => re.test(relPath)); const isGlob = (s) => /[*?[]/.test(s); @@ -401,47 +402,6 @@ export function resolveFiles(rootDir, config) { return out; } -/** - * Convert a glob pattern to a RegExp. Supports: - * ** → any number of path segments (including zero) - * * → any chars except `/` - * ? → any single char except `/` - * Paths are normalized to forward slashes before matching. - */ -function globToRegex(pattern) { - let re = ''; - let i = 0; - while (i < pattern.length) { - const c = pattern[i]; - if (c === '*') { - if (pattern[i + 1] === '*') { - // ** — any number of segments, including zero. Handle the common - // **/ and /** forms so `a/**/b` matches `a/b` as well as `a/x/y/b`. - if (pattern[i + 2] === '/') { - re += '(?:.*/)?'; - i += 3; - } else { - re += '.*'; - i += 2; - } - } else { - re += '[^/]*'; - i += 1; - } - } else if (c === '?') { - re += '[^/]'; - i += 1; - } else if (/[.+^${}()|[\]\\]/.test(c)) { - re += '\\' + c; - i += 1; - } else { - re += c; - i += 1; - } - } - return new RegExp('^' + re + '$'); -} - // --------------------------------------------------------------------------- // Core operations // --------------------------------------------------------------------------- diff --git a/.claude/skills/impeccable/scripts/live.mjs b/.claude/skills/impeccable/scripts/live.mjs index 7738c3f02..ccbef4949 100644 --- a/.claude/skills/impeccable/scripts/live.mjs +++ b/.claude/skills/impeccable/scripts/live.mjs @@ -24,6 +24,7 @@ import { fileURLToPath } from 'node:url'; import { resolveTargetSelection } from './context.mjs'; import { resolveFiles } from './live-inject.mjs'; import { readLiveServerInfo } from './lib/impeccable-paths.mjs'; +import { livePathGlobToRegex } from './lib/live-path-globs.mjs'; import { resolveSurfaceBrief } from './lib/surface-briefs.mjs'; import { resolveLiveTarget } from './live-target.mjs'; import { bootInstructions } from './live/instructions.mjs'; @@ -240,7 +241,7 @@ function scanForDrift(rootDir, resolvedFiles, config) { // Files matching the user's `exclude` globs are intentional omissions, // not drift. Compile them to regexes so the orphan list stays signal. const userExcludeRegexes = (Array.isArray(config.exclude) ? config.exclude : []) - .map((p) => globToRegex(p)); + .map(livePathGlobToRegex); const isUserExcluded = (rel) => userExcludeRegexes.some((re) => re.test(rel)); const orphans = []; @@ -278,38 +279,6 @@ function scanForDrift(rootDir, resolvedFiles, config) { }; } -/** - * Same glob-to-regex mapping used by live-inject.mjs. Kept inline here - * to avoid a circular import (live-inject.mjs already imports nothing - * from live.mjs). The two must stay in sync. - */ -function globToRegex(pattern) { - let re = ''; - let i = 0; - while (i < pattern.length) { - const c = pattern[i]; - if (c === '*') { - if (pattern[i + 1] === '*') { - if (pattern[i + 2] === '/') { re += '(?:.*/)?'; i += 3; } - else { re += '.*'; i += 2; } - } else { - re += '[^/]*'; - i += 1; - } - } else if (c === '?') { - re += '[^/]'; - i += 1; - } else if (/[.+^${}()|[\]\\]/.test(c)) { - re += '\\' + c; - i += 1; - } else { - re += c; - i += 1; - } - } - return new RegExp('^' + re + '$'); -} - // --------------------------------------------------------------------------- // Helpers // --------------------------------------------------------------------------- diff --git a/.cursor/skills/impeccable/scripts/lib/live-path-globs.mjs b/.cursor/skills/impeccable/scripts/lib/live-path-globs.mjs new file mode 100644 index 000000000..4a3eebda0 --- /dev/null +++ b/.cursor/skills/impeccable/scripts/lib/live-path-globs.mjs @@ -0,0 +1,37 @@ +/** + * Convert a live-config glob pattern to a RegExp. + * + * Supports `**` across path segments, `*` within one segment, and `?` for one + * character. Callers normalize project-relative paths to forward slashes. + */ +export function livePathGlobToRegex(pattern) { + let re = ''; + let i = 0; + while (i < pattern.length) { + const c = pattern[i]; + if (c === '*') { + if (pattern[i + 1] === '*') { + if (pattern[i + 2] === '/') { + re += '(?:.*/)?'; + i += 3; + } else { + re += '.*'; + i += 2; + } + } else { + re += '[^/]*'; + i += 1; + } + } else if (c === '?') { + re += '[^/]'; + i += 1; + } else if (/[.+^${}()|[\]\\]/.test(c)) { + re += `\\${c}`; + i += 1; + } else { + re += c; + i += 1; + } + } + return new RegExp(`^${re}$`); +} diff --git a/.cursor/skills/impeccable/scripts/live-inject.mjs b/.cursor/skills/impeccable/scripts/live-inject.mjs index 81848010b..0b5fe9c18 100644 --- a/.cursor/skills/impeccable/scripts/live-inject.mjs +++ b/.cursor/skills/impeccable/scripts/live-inject.mjs @@ -27,6 +27,7 @@ import fs from 'node:fs'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; import { resolveLiveConfigPath } from './lib/impeccable-paths.mjs'; +import { livePathGlobToRegex } from './lib/live-path-globs.mjs'; import { describeInjectArtifacts, frameworkIgnorePatterns, @@ -364,7 +365,7 @@ export function resolveFiles(rootDir, config) { const patterns = config.files; const userExcludes = Array.isArray(config.exclude) ? config.exclude : []; const allExcludes = [...HARD_EXCLUDES, ...userExcludes]; - const excludeRegexes = allExcludes.map(globToRegex); + const excludeRegexes = allExcludes.map(livePathGlobToRegex); const isExcluded = (relPath) => excludeRegexes.some((re) => re.test(relPath)); const isGlob = (s) => /[*?[]/.test(s); @@ -401,47 +402,6 @@ export function resolveFiles(rootDir, config) { return out; } -/** - * Convert a glob pattern to a RegExp. Supports: - * ** → any number of path segments (including zero) - * * → any chars except `/` - * ? → any single char except `/` - * Paths are normalized to forward slashes before matching. - */ -function globToRegex(pattern) { - let re = ''; - let i = 0; - while (i < pattern.length) { - const c = pattern[i]; - if (c === '*') { - if (pattern[i + 1] === '*') { - // ** — any number of segments, including zero. Handle the common - // **/ and /** forms so `a/**/b` matches `a/b` as well as `a/x/y/b`. - if (pattern[i + 2] === '/') { - re += '(?:.*/)?'; - i += 3; - } else { - re += '.*'; - i += 2; - } - } else { - re += '[^/]*'; - i += 1; - } - } else if (c === '?') { - re += '[^/]'; - i += 1; - } else if (/[.+^${}()|[\]\\]/.test(c)) { - re += '\\' + c; - i += 1; - } else { - re += c; - i += 1; - } - } - return new RegExp('^' + re + '$'); -} - // --------------------------------------------------------------------------- // Core operations // --------------------------------------------------------------------------- diff --git a/.cursor/skills/impeccable/scripts/live.mjs b/.cursor/skills/impeccable/scripts/live.mjs index 7738c3f02..ccbef4949 100644 --- a/.cursor/skills/impeccable/scripts/live.mjs +++ b/.cursor/skills/impeccable/scripts/live.mjs @@ -24,6 +24,7 @@ import { fileURLToPath } from 'node:url'; import { resolveTargetSelection } from './context.mjs'; import { resolveFiles } from './live-inject.mjs'; import { readLiveServerInfo } from './lib/impeccable-paths.mjs'; +import { livePathGlobToRegex } from './lib/live-path-globs.mjs'; import { resolveSurfaceBrief } from './lib/surface-briefs.mjs'; import { resolveLiveTarget } from './live-target.mjs'; import { bootInstructions } from './live/instructions.mjs'; @@ -240,7 +241,7 @@ function scanForDrift(rootDir, resolvedFiles, config) { // Files matching the user's `exclude` globs are intentional omissions, // not drift. Compile them to regexes so the orphan list stays signal. const userExcludeRegexes = (Array.isArray(config.exclude) ? config.exclude : []) - .map((p) => globToRegex(p)); + .map(livePathGlobToRegex); const isUserExcluded = (rel) => userExcludeRegexes.some((re) => re.test(rel)); const orphans = []; @@ -278,38 +279,6 @@ function scanForDrift(rootDir, resolvedFiles, config) { }; } -/** - * Same glob-to-regex mapping used by live-inject.mjs. Kept inline here - * to avoid a circular import (live-inject.mjs already imports nothing - * from live.mjs). The two must stay in sync. - */ -function globToRegex(pattern) { - let re = ''; - let i = 0; - while (i < pattern.length) { - const c = pattern[i]; - if (c === '*') { - if (pattern[i + 1] === '*') { - if (pattern[i + 2] === '/') { re += '(?:.*/)?'; i += 3; } - else { re += '.*'; i += 2; } - } else { - re += '[^/]*'; - i += 1; - } - } else if (c === '?') { - re += '[^/]'; - i += 1; - } else if (/[.+^${}()|[\]\\]/.test(c)) { - re += '\\' + c; - i += 1; - } else { - re += c; - i += 1; - } - } - return new RegExp('^' + re + '$'); -} - // --------------------------------------------------------------------------- // Helpers // --------------------------------------------------------------------------- diff --git a/.gemini/skills/impeccable/scripts/lib/live-path-globs.mjs b/.gemini/skills/impeccable/scripts/lib/live-path-globs.mjs new file mode 100644 index 000000000..4a3eebda0 --- /dev/null +++ b/.gemini/skills/impeccable/scripts/lib/live-path-globs.mjs @@ -0,0 +1,37 @@ +/** + * Convert a live-config glob pattern to a RegExp. + * + * Supports `**` across path segments, `*` within one segment, and `?` for one + * character. Callers normalize project-relative paths to forward slashes. + */ +export function livePathGlobToRegex(pattern) { + let re = ''; + let i = 0; + while (i < pattern.length) { + const c = pattern[i]; + if (c === '*') { + if (pattern[i + 1] === '*') { + if (pattern[i + 2] === '/') { + re += '(?:.*/)?'; + i += 3; + } else { + re += '.*'; + i += 2; + } + } else { + re += '[^/]*'; + i += 1; + } + } else if (c === '?') { + re += '[^/]'; + i += 1; + } else if (/[.+^${}()|[\]\\]/.test(c)) { + re += `\\${c}`; + i += 1; + } else { + re += c; + i += 1; + } + } + return new RegExp(`^${re}$`); +} diff --git a/.gemini/skills/impeccable/scripts/live-inject.mjs b/.gemini/skills/impeccable/scripts/live-inject.mjs index 81848010b..0b5fe9c18 100644 --- a/.gemini/skills/impeccable/scripts/live-inject.mjs +++ b/.gemini/skills/impeccable/scripts/live-inject.mjs @@ -27,6 +27,7 @@ import fs from 'node:fs'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; import { resolveLiveConfigPath } from './lib/impeccable-paths.mjs'; +import { livePathGlobToRegex } from './lib/live-path-globs.mjs'; import { describeInjectArtifacts, frameworkIgnorePatterns, @@ -364,7 +365,7 @@ export function resolveFiles(rootDir, config) { const patterns = config.files; const userExcludes = Array.isArray(config.exclude) ? config.exclude : []; const allExcludes = [...HARD_EXCLUDES, ...userExcludes]; - const excludeRegexes = allExcludes.map(globToRegex); + const excludeRegexes = allExcludes.map(livePathGlobToRegex); const isExcluded = (relPath) => excludeRegexes.some((re) => re.test(relPath)); const isGlob = (s) => /[*?[]/.test(s); @@ -401,47 +402,6 @@ export function resolveFiles(rootDir, config) { return out; } -/** - * Convert a glob pattern to a RegExp. Supports: - * ** → any number of path segments (including zero) - * * → any chars except `/` - * ? → any single char except `/` - * Paths are normalized to forward slashes before matching. - */ -function globToRegex(pattern) { - let re = ''; - let i = 0; - while (i < pattern.length) { - const c = pattern[i]; - if (c === '*') { - if (pattern[i + 1] === '*') { - // ** — any number of segments, including zero. Handle the common - // **/ and /** forms so `a/**/b` matches `a/b` as well as `a/x/y/b`. - if (pattern[i + 2] === '/') { - re += '(?:.*/)?'; - i += 3; - } else { - re += '.*'; - i += 2; - } - } else { - re += '[^/]*'; - i += 1; - } - } else if (c === '?') { - re += '[^/]'; - i += 1; - } else if (/[.+^${}()|[\]\\]/.test(c)) { - re += '\\' + c; - i += 1; - } else { - re += c; - i += 1; - } - } - return new RegExp('^' + re + '$'); -} - // --------------------------------------------------------------------------- // Core operations // --------------------------------------------------------------------------- diff --git a/.gemini/skills/impeccable/scripts/live.mjs b/.gemini/skills/impeccable/scripts/live.mjs index 7738c3f02..ccbef4949 100644 --- a/.gemini/skills/impeccable/scripts/live.mjs +++ b/.gemini/skills/impeccable/scripts/live.mjs @@ -24,6 +24,7 @@ import { fileURLToPath } from 'node:url'; import { resolveTargetSelection } from './context.mjs'; import { resolveFiles } from './live-inject.mjs'; import { readLiveServerInfo } from './lib/impeccable-paths.mjs'; +import { livePathGlobToRegex } from './lib/live-path-globs.mjs'; import { resolveSurfaceBrief } from './lib/surface-briefs.mjs'; import { resolveLiveTarget } from './live-target.mjs'; import { bootInstructions } from './live/instructions.mjs'; @@ -240,7 +241,7 @@ function scanForDrift(rootDir, resolvedFiles, config) { // Files matching the user's `exclude` globs are intentional omissions, // not drift. Compile them to regexes so the orphan list stays signal. const userExcludeRegexes = (Array.isArray(config.exclude) ? config.exclude : []) - .map((p) => globToRegex(p)); + .map(livePathGlobToRegex); const isUserExcluded = (rel) => userExcludeRegexes.some((re) => re.test(rel)); const orphans = []; @@ -278,38 +279,6 @@ function scanForDrift(rootDir, resolvedFiles, config) { }; } -/** - * Same glob-to-regex mapping used by live-inject.mjs. Kept inline here - * to avoid a circular import (live-inject.mjs already imports nothing - * from live.mjs). The two must stay in sync. - */ -function globToRegex(pattern) { - let re = ''; - let i = 0; - while (i < pattern.length) { - const c = pattern[i]; - if (c === '*') { - if (pattern[i + 1] === '*') { - if (pattern[i + 2] === '/') { re += '(?:.*/)?'; i += 3; } - else { re += '.*'; i += 2; } - } else { - re += '[^/]*'; - i += 1; - } - } else if (c === '?') { - re += '[^/]'; - i += 1; - } else if (/[.+^${}()|[\]\\]/.test(c)) { - re += '\\' + c; - i += 1; - } else { - re += c; - i += 1; - } - } - return new RegExp('^' + re + '$'); -} - // --------------------------------------------------------------------------- // Helpers // --------------------------------------------------------------------------- diff --git a/.github/skills/impeccable/scripts/lib/live-path-globs.mjs b/.github/skills/impeccable/scripts/lib/live-path-globs.mjs new file mode 100644 index 000000000..4a3eebda0 --- /dev/null +++ b/.github/skills/impeccable/scripts/lib/live-path-globs.mjs @@ -0,0 +1,37 @@ +/** + * Convert a live-config glob pattern to a RegExp. + * + * Supports `**` across path segments, `*` within one segment, and `?` for one + * character. Callers normalize project-relative paths to forward slashes. + */ +export function livePathGlobToRegex(pattern) { + let re = ''; + let i = 0; + while (i < pattern.length) { + const c = pattern[i]; + if (c === '*') { + if (pattern[i + 1] === '*') { + if (pattern[i + 2] === '/') { + re += '(?:.*/)?'; + i += 3; + } else { + re += '.*'; + i += 2; + } + } else { + re += '[^/]*'; + i += 1; + } + } else if (c === '?') { + re += '[^/]'; + i += 1; + } else if (/[.+^${}()|[\]\\]/.test(c)) { + re += `\\${c}`; + i += 1; + } else { + re += c; + i += 1; + } + } + return new RegExp(`^${re}$`); +} diff --git a/.github/skills/impeccable/scripts/live-inject.mjs b/.github/skills/impeccable/scripts/live-inject.mjs index 81848010b..0b5fe9c18 100644 --- a/.github/skills/impeccable/scripts/live-inject.mjs +++ b/.github/skills/impeccable/scripts/live-inject.mjs @@ -27,6 +27,7 @@ import fs from 'node:fs'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; import { resolveLiveConfigPath } from './lib/impeccable-paths.mjs'; +import { livePathGlobToRegex } from './lib/live-path-globs.mjs'; import { describeInjectArtifacts, frameworkIgnorePatterns, @@ -364,7 +365,7 @@ export function resolveFiles(rootDir, config) { const patterns = config.files; const userExcludes = Array.isArray(config.exclude) ? config.exclude : []; const allExcludes = [...HARD_EXCLUDES, ...userExcludes]; - const excludeRegexes = allExcludes.map(globToRegex); + const excludeRegexes = allExcludes.map(livePathGlobToRegex); const isExcluded = (relPath) => excludeRegexes.some((re) => re.test(relPath)); const isGlob = (s) => /[*?[]/.test(s); @@ -401,47 +402,6 @@ export function resolveFiles(rootDir, config) { return out; } -/** - * Convert a glob pattern to a RegExp. Supports: - * ** → any number of path segments (including zero) - * * → any chars except `/` - * ? → any single char except `/` - * Paths are normalized to forward slashes before matching. - */ -function globToRegex(pattern) { - let re = ''; - let i = 0; - while (i < pattern.length) { - const c = pattern[i]; - if (c === '*') { - if (pattern[i + 1] === '*') { - // ** — any number of segments, including zero. Handle the common - // **/ and /** forms so `a/**/b` matches `a/b` as well as `a/x/y/b`. - if (pattern[i + 2] === '/') { - re += '(?:.*/)?'; - i += 3; - } else { - re += '.*'; - i += 2; - } - } else { - re += '[^/]*'; - i += 1; - } - } else if (c === '?') { - re += '[^/]'; - i += 1; - } else if (/[.+^${}()|[\]\\]/.test(c)) { - re += '\\' + c; - i += 1; - } else { - re += c; - i += 1; - } - } - return new RegExp('^' + re + '$'); -} - // --------------------------------------------------------------------------- // Core operations // --------------------------------------------------------------------------- diff --git a/.github/skills/impeccable/scripts/live.mjs b/.github/skills/impeccable/scripts/live.mjs index 7738c3f02..ccbef4949 100644 --- a/.github/skills/impeccable/scripts/live.mjs +++ b/.github/skills/impeccable/scripts/live.mjs @@ -24,6 +24,7 @@ import { fileURLToPath } from 'node:url'; import { resolveTargetSelection } from './context.mjs'; import { resolveFiles } from './live-inject.mjs'; import { readLiveServerInfo } from './lib/impeccable-paths.mjs'; +import { livePathGlobToRegex } from './lib/live-path-globs.mjs'; import { resolveSurfaceBrief } from './lib/surface-briefs.mjs'; import { resolveLiveTarget } from './live-target.mjs'; import { bootInstructions } from './live/instructions.mjs'; @@ -240,7 +241,7 @@ function scanForDrift(rootDir, resolvedFiles, config) { // Files matching the user's `exclude` globs are intentional omissions, // not drift. Compile them to regexes so the orphan list stays signal. const userExcludeRegexes = (Array.isArray(config.exclude) ? config.exclude : []) - .map((p) => globToRegex(p)); + .map(livePathGlobToRegex); const isUserExcluded = (rel) => userExcludeRegexes.some((re) => re.test(rel)); const orphans = []; @@ -278,38 +279,6 @@ function scanForDrift(rootDir, resolvedFiles, config) { }; } -/** - * Same glob-to-regex mapping used by live-inject.mjs. Kept inline here - * to avoid a circular import (live-inject.mjs already imports nothing - * from live.mjs). The two must stay in sync. - */ -function globToRegex(pattern) { - let re = ''; - let i = 0; - while (i < pattern.length) { - const c = pattern[i]; - if (c === '*') { - if (pattern[i + 1] === '*') { - if (pattern[i + 2] === '/') { re += '(?:.*/)?'; i += 3; } - else { re += '.*'; i += 2; } - } else { - re += '[^/]*'; - i += 1; - } - } else if (c === '?') { - re += '[^/]'; - i += 1; - } else if (/[.+^${}()|[\]\\]/.test(c)) { - re += '\\' + c; - i += 1; - } else { - re += c; - i += 1; - } - } - return new RegExp('^' + re + '$'); -} - // --------------------------------------------------------------------------- // Helpers // --------------------------------------------------------------------------- diff --git a/.grok/skills/impeccable/scripts/lib/live-path-globs.mjs b/.grok/skills/impeccable/scripts/lib/live-path-globs.mjs new file mode 100644 index 000000000..4a3eebda0 --- /dev/null +++ b/.grok/skills/impeccable/scripts/lib/live-path-globs.mjs @@ -0,0 +1,37 @@ +/** + * Convert a live-config glob pattern to a RegExp. + * + * Supports `**` across path segments, `*` within one segment, and `?` for one + * character. Callers normalize project-relative paths to forward slashes. + */ +export function livePathGlobToRegex(pattern) { + let re = ''; + let i = 0; + while (i < pattern.length) { + const c = pattern[i]; + if (c === '*') { + if (pattern[i + 1] === '*') { + if (pattern[i + 2] === '/') { + re += '(?:.*/)?'; + i += 3; + } else { + re += '.*'; + i += 2; + } + } else { + re += '[^/]*'; + i += 1; + } + } else if (c === '?') { + re += '[^/]'; + i += 1; + } else if (/[.+^${}()|[\]\\]/.test(c)) { + re += `\\${c}`; + i += 1; + } else { + re += c; + i += 1; + } + } + return new RegExp(`^${re}$`); +} diff --git a/.grok/skills/impeccable/scripts/live-inject.mjs b/.grok/skills/impeccable/scripts/live-inject.mjs index 81848010b..0b5fe9c18 100644 --- a/.grok/skills/impeccable/scripts/live-inject.mjs +++ b/.grok/skills/impeccable/scripts/live-inject.mjs @@ -27,6 +27,7 @@ import fs from 'node:fs'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; import { resolveLiveConfigPath } from './lib/impeccable-paths.mjs'; +import { livePathGlobToRegex } from './lib/live-path-globs.mjs'; import { describeInjectArtifacts, frameworkIgnorePatterns, @@ -364,7 +365,7 @@ export function resolveFiles(rootDir, config) { const patterns = config.files; const userExcludes = Array.isArray(config.exclude) ? config.exclude : []; const allExcludes = [...HARD_EXCLUDES, ...userExcludes]; - const excludeRegexes = allExcludes.map(globToRegex); + const excludeRegexes = allExcludes.map(livePathGlobToRegex); const isExcluded = (relPath) => excludeRegexes.some((re) => re.test(relPath)); const isGlob = (s) => /[*?[]/.test(s); @@ -401,47 +402,6 @@ export function resolveFiles(rootDir, config) { return out; } -/** - * Convert a glob pattern to a RegExp. Supports: - * ** → any number of path segments (including zero) - * * → any chars except `/` - * ? → any single char except `/` - * Paths are normalized to forward slashes before matching. - */ -function globToRegex(pattern) { - let re = ''; - let i = 0; - while (i < pattern.length) { - const c = pattern[i]; - if (c === '*') { - if (pattern[i + 1] === '*') { - // ** — any number of segments, including zero. Handle the common - // **/ and /** forms so `a/**/b` matches `a/b` as well as `a/x/y/b`. - if (pattern[i + 2] === '/') { - re += '(?:.*/)?'; - i += 3; - } else { - re += '.*'; - i += 2; - } - } else { - re += '[^/]*'; - i += 1; - } - } else if (c === '?') { - re += '[^/]'; - i += 1; - } else if (/[.+^${}()|[\]\\]/.test(c)) { - re += '\\' + c; - i += 1; - } else { - re += c; - i += 1; - } - } - return new RegExp('^' + re + '$'); -} - // --------------------------------------------------------------------------- // Core operations // --------------------------------------------------------------------------- diff --git a/.grok/skills/impeccable/scripts/live.mjs b/.grok/skills/impeccable/scripts/live.mjs index 7738c3f02..ccbef4949 100644 --- a/.grok/skills/impeccable/scripts/live.mjs +++ b/.grok/skills/impeccable/scripts/live.mjs @@ -24,6 +24,7 @@ import { fileURLToPath } from 'node:url'; import { resolveTargetSelection } from './context.mjs'; import { resolveFiles } from './live-inject.mjs'; import { readLiveServerInfo } from './lib/impeccable-paths.mjs'; +import { livePathGlobToRegex } from './lib/live-path-globs.mjs'; import { resolveSurfaceBrief } from './lib/surface-briefs.mjs'; import { resolveLiveTarget } from './live-target.mjs'; import { bootInstructions } from './live/instructions.mjs'; @@ -240,7 +241,7 @@ function scanForDrift(rootDir, resolvedFiles, config) { // Files matching the user's `exclude` globs are intentional omissions, // not drift. Compile them to regexes so the orphan list stays signal. const userExcludeRegexes = (Array.isArray(config.exclude) ? config.exclude : []) - .map((p) => globToRegex(p)); + .map(livePathGlobToRegex); const isUserExcluded = (rel) => userExcludeRegexes.some((re) => re.test(rel)); const orphans = []; @@ -278,38 +279,6 @@ function scanForDrift(rootDir, resolvedFiles, config) { }; } -/** - * Same glob-to-regex mapping used by live-inject.mjs. Kept inline here - * to avoid a circular import (live-inject.mjs already imports nothing - * from live.mjs). The two must stay in sync. - */ -function globToRegex(pattern) { - let re = ''; - let i = 0; - while (i < pattern.length) { - const c = pattern[i]; - if (c === '*') { - if (pattern[i + 1] === '*') { - if (pattern[i + 2] === '/') { re += '(?:.*/)?'; i += 3; } - else { re += '.*'; i += 2; } - } else { - re += '[^/]*'; - i += 1; - } - } else if (c === '?') { - re += '[^/]'; - i += 1; - } else if (/[.+^${}()|[\]\\]/.test(c)) { - re += '\\' + c; - i += 1; - } else { - re += c; - i += 1; - } - } - return new RegExp('^' + re + '$'); -} - // --------------------------------------------------------------------------- // Helpers // --------------------------------------------------------------------------- diff --git a/.hermes/skills/impeccable/scripts/lib/live-path-globs.mjs b/.hermes/skills/impeccable/scripts/lib/live-path-globs.mjs new file mode 100644 index 000000000..4a3eebda0 --- /dev/null +++ b/.hermes/skills/impeccable/scripts/lib/live-path-globs.mjs @@ -0,0 +1,37 @@ +/** + * Convert a live-config glob pattern to a RegExp. + * + * Supports `**` across path segments, `*` within one segment, and `?` for one + * character. Callers normalize project-relative paths to forward slashes. + */ +export function livePathGlobToRegex(pattern) { + let re = ''; + let i = 0; + while (i < pattern.length) { + const c = pattern[i]; + if (c === '*') { + if (pattern[i + 1] === '*') { + if (pattern[i + 2] === '/') { + re += '(?:.*/)?'; + i += 3; + } else { + re += '.*'; + i += 2; + } + } else { + re += '[^/]*'; + i += 1; + } + } else if (c === '?') { + re += '[^/]'; + i += 1; + } else if (/[.+^${}()|[\]\\]/.test(c)) { + re += `\\${c}`; + i += 1; + } else { + re += c; + i += 1; + } + } + return new RegExp(`^${re}$`); +} diff --git a/.hermes/skills/impeccable/scripts/live-inject.mjs b/.hermes/skills/impeccable/scripts/live-inject.mjs index 81848010b..0b5fe9c18 100644 --- a/.hermes/skills/impeccable/scripts/live-inject.mjs +++ b/.hermes/skills/impeccable/scripts/live-inject.mjs @@ -27,6 +27,7 @@ import fs from 'node:fs'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; import { resolveLiveConfigPath } from './lib/impeccable-paths.mjs'; +import { livePathGlobToRegex } from './lib/live-path-globs.mjs'; import { describeInjectArtifacts, frameworkIgnorePatterns, @@ -364,7 +365,7 @@ export function resolveFiles(rootDir, config) { const patterns = config.files; const userExcludes = Array.isArray(config.exclude) ? config.exclude : []; const allExcludes = [...HARD_EXCLUDES, ...userExcludes]; - const excludeRegexes = allExcludes.map(globToRegex); + const excludeRegexes = allExcludes.map(livePathGlobToRegex); const isExcluded = (relPath) => excludeRegexes.some((re) => re.test(relPath)); const isGlob = (s) => /[*?[]/.test(s); @@ -401,47 +402,6 @@ export function resolveFiles(rootDir, config) { return out; } -/** - * Convert a glob pattern to a RegExp. Supports: - * ** → any number of path segments (including zero) - * * → any chars except `/` - * ? → any single char except `/` - * Paths are normalized to forward slashes before matching. - */ -function globToRegex(pattern) { - let re = ''; - let i = 0; - while (i < pattern.length) { - const c = pattern[i]; - if (c === '*') { - if (pattern[i + 1] === '*') { - // ** — any number of segments, including zero. Handle the common - // **/ and /** forms so `a/**/b` matches `a/b` as well as `a/x/y/b`. - if (pattern[i + 2] === '/') { - re += '(?:.*/)?'; - i += 3; - } else { - re += '.*'; - i += 2; - } - } else { - re += '[^/]*'; - i += 1; - } - } else if (c === '?') { - re += '[^/]'; - i += 1; - } else if (/[.+^${}()|[\]\\]/.test(c)) { - re += '\\' + c; - i += 1; - } else { - re += c; - i += 1; - } - } - return new RegExp('^' + re + '$'); -} - // --------------------------------------------------------------------------- // Core operations // --------------------------------------------------------------------------- diff --git a/.hermes/skills/impeccable/scripts/live.mjs b/.hermes/skills/impeccable/scripts/live.mjs index 7738c3f02..ccbef4949 100644 --- a/.hermes/skills/impeccable/scripts/live.mjs +++ b/.hermes/skills/impeccable/scripts/live.mjs @@ -24,6 +24,7 @@ import { fileURLToPath } from 'node:url'; import { resolveTargetSelection } from './context.mjs'; import { resolveFiles } from './live-inject.mjs'; import { readLiveServerInfo } from './lib/impeccable-paths.mjs'; +import { livePathGlobToRegex } from './lib/live-path-globs.mjs'; import { resolveSurfaceBrief } from './lib/surface-briefs.mjs'; import { resolveLiveTarget } from './live-target.mjs'; import { bootInstructions } from './live/instructions.mjs'; @@ -240,7 +241,7 @@ function scanForDrift(rootDir, resolvedFiles, config) { // Files matching the user's `exclude` globs are intentional omissions, // not drift. Compile them to regexes so the orphan list stays signal. const userExcludeRegexes = (Array.isArray(config.exclude) ? config.exclude : []) - .map((p) => globToRegex(p)); + .map(livePathGlobToRegex); const isUserExcluded = (rel) => userExcludeRegexes.some((re) => re.test(rel)); const orphans = []; @@ -278,38 +279,6 @@ function scanForDrift(rootDir, resolvedFiles, config) { }; } -/** - * Same glob-to-regex mapping used by live-inject.mjs. Kept inline here - * to avoid a circular import (live-inject.mjs already imports nothing - * from live.mjs). The two must stay in sync. - */ -function globToRegex(pattern) { - let re = ''; - let i = 0; - while (i < pattern.length) { - const c = pattern[i]; - if (c === '*') { - if (pattern[i + 1] === '*') { - if (pattern[i + 2] === '/') { re += '(?:.*/)?'; i += 3; } - else { re += '.*'; i += 2; } - } else { - re += '[^/]*'; - i += 1; - } - } else if (c === '?') { - re += '[^/]'; - i += 1; - } else if (/[.+^${}()|[\]\\]/.test(c)) { - re += '\\' + c; - i += 1; - } else { - re += c; - i += 1; - } - } - return new RegExp('^' + re + '$'); -} - // --------------------------------------------------------------------------- // Helpers // --------------------------------------------------------------------------- diff --git a/.kiro/skills/impeccable/scripts/lib/live-path-globs.mjs b/.kiro/skills/impeccable/scripts/lib/live-path-globs.mjs new file mode 100644 index 000000000..4a3eebda0 --- /dev/null +++ b/.kiro/skills/impeccable/scripts/lib/live-path-globs.mjs @@ -0,0 +1,37 @@ +/** + * Convert a live-config glob pattern to a RegExp. + * + * Supports `**` across path segments, `*` within one segment, and `?` for one + * character. Callers normalize project-relative paths to forward slashes. + */ +export function livePathGlobToRegex(pattern) { + let re = ''; + let i = 0; + while (i < pattern.length) { + const c = pattern[i]; + if (c === '*') { + if (pattern[i + 1] === '*') { + if (pattern[i + 2] === '/') { + re += '(?:.*/)?'; + i += 3; + } else { + re += '.*'; + i += 2; + } + } else { + re += '[^/]*'; + i += 1; + } + } else if (c === '?') { + re += '[^/]'; + i += 1; + } else if (/[.+^${}()|[\]\\]/.test(c)) { + re += `\\${c}`; + i += 1; + } else { + re += c; + i += 1; + } + } + return new RegExp(`^${re}$`); +} diff --git a/.kiro/skills/impeccable/scripts/live-inject.mjs b/.kiro/skills/impeccable/scripts/live-inject.mjs index 81848010b..0b5fe9c18 100644 --- a/.kiro/skills/impeccable/scripts/live-inject.mjs +++ b/.kiro/skills/impeccable/scripts/live-inject.mjs @@ -27,6 +27,7 @@ import fs from 'node:fs'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; import { resolveLiveConfigPath } from './lib/impeccable-paths.mjs'; +import { livePathGlobToRegex } from './lib/live-path-globs.mjs'; import { describeInjectArtifacts, frameworkIgnorePatterns, @@ -364,7 +365,7 @@ export function resolveFiles(rootDir, config) { const patterns = config.files; const userExcludes = Array.isArray(config.exclude) ? config.exclude : []; const allExcludes = [...HARD_EXCLUDES, ...userExcludes]; - const excludeRegexes = allExcludes.map(globToRegex); + const excludeRegexes = allExcludes.map(livePathGlobToRegex); const isExcluded = (relPath) => excludeRegexes.some((re) => re.test(relPath)); const isGlob = (s) => /[*?[]/.test(s); @@ -401,47 +402,6 @@ export function resolveFiles(rootDir, config) { return out; } -/** - * Convert a glob pattern to a RegExp. Supports: - * ** → any number of path segments (including zero) - * * → any chars except `/` - * ? → any single char except `/` - * Paths are normalized to forward slashes before matching. - */ -function globToRegex(pattern) { - let re = ''; - let i = 0; - while (i < pattern.length) { - const c = pattern[i]; - if (c === '*') { - if (pattern[i + 1] === '*') { - // ** — any number of segments, including zero. Handle the common - // **/ and /** forms so `a/**/b` matches `a/b` as well as `a/x/y/b`. - if (pattern[i + 2] === '/') { - re += '(?:.*/)?'; - i += 3; - } else { - re += '.*'; - i += 2; - } - } else { - re += '[^/]*'; - i += 1; - } - } else if (c === '?') { - re += '[^/]'; - i += 1; - } else if (/[.+^${}()|[\]\\]/.test(c)) { - re += '\\' + c; - i += 1; - } else { - re += c; - i += 1; - } - } - return new RegExp('^' + re + '$'); -} - // --------------------------------------------------------------------------- // Core operations // --------------------------------------------------------------------------- diff --git a/.kiro/skills/impeccable/scripts/live.mjs b/.kiro/skills/impeccable/scripts/live.mjs index 7738c3f02..ccbef4949 100644 --- a/.kiro/skills/impeccable/scripts/live.mjs +++ b/.kiro/skills/impeccable/scripts/live.mjs @@ -24,6 +24,7 @@ import { fileURLToPath } from 'node:url'; import { resolveTargetSelection } from './context.mjs'; import { resolveFiles } from './live-inject.mjs'; import { readLiveServerInfo } from './lib/impeccable-paths.mjs'; +import { livePathGlobToRegex } from './lib/live-path-globs.mjs'; import { resolveSurfaceBrief } from './lib/surface-briefs.mjs'; import { resolveLiveTarget } from './live-target.mjs'; import { bootInstructions } from './live/instructions.mjs'; @@ -240,7 +241,7 @@ function scanForDrift(rootDir, resolvedFiles, config) { // Files matching the user's `exclude` globs are intentional omissions, // not drift. Compile them to regexes so the orphan list stays signal. const userExcludeRegexes = (Array.isArray(config.exclude) ? config.exclude : []) - .map((p) => globToRegex(p)); + .map(livePathGlobToRegex); const isUserExcluded = (rel) => userExcludeRegexes.some((re) => re.test(rel)); const orphans = []; @@ -278,38 +279,6 @@ function scanForDrift(rootDir, resolvedFiles, config) { }; } -/** - * Same glob-to-regex mapping used by live-inject.mjs. Kept inline here - * to avoid a circular import (live-inject.mjs already imports nothing - * from live.mjs). The two must stay in sync. - */ -function globToRegex(pattern) { - let re = ''; - let i = 0; - while (i < pattern.length) { - const c = pattern[i]; - if (c === '*') { - if (pattern[i + 1] === '*') { - if (pattern[i + 2] === '/') { re += '(?:.*/)?'; i += 3; } - else { re += '.*'; i += 2; } - } else { - re += '[^/]*'; - i += 1; - } - } else if (c === '?') { - re += '[^/]'; - i += 1; - } else if (/[.+^${}()|[\]\\]/.test(c)) { - re += '\\' + c; - i += 1; - } else { - re += c; - i += 1; - } - } - return new RegExp('^' + re + '$'); -} - // --------------------------------------------------------------------------- // Helpers // --------------------------------------------------------------------------- diff --git a/.opencode/skills/impeccable/scripts/lib/live-path-globs.mjs b/.opencode/skills/impeccable/scripts/lib/live-path-globs.mjs new file mode 100644 index 000000000..4a3eebda0 --- /dev/null +++ b/.opencode/skills/impeccable/scripts/lib/live-path-globs.mjs @@ -0,0 +1,37 @@ +/** + * Convert a live-config glob pattern to a RegExp. + * + * Supports `**` across path segments, `*` within one segment, and `?` for one + * character. Callers normalize project-relative paths to forward slashes. + */ +export function livePathGlobToRegex(pattern) { + let re = ''; + let i = 0; + while (i < pattern.length) { + const c = pattern[i]; + if (c === '*') { + if (pattern[i + 1] === '*') { + if (pattern[i + 2] === '/') { + re += '(?:.*/)?'; + i += 3; + } else { + re += '.*'; + i += 2; + } + } else { + re += '[^/]*'; + i += 1; + } + } else if (c === '?') { + re += '[^/]'; + i += 1; + } else if (/[.+^${}()|[\]\\]/.test(c)) { + re += `\\${c}`; + i += 1; + } else { + re += c; + i += 1; + } + } + return new RegExp(`^${re}$`); +} diff --git a/.opencode/skills/impeccable/scripts/live-inject.mjs b/.opencode/skills/impeccable/scripts/live-inject.mjs index 81848010b..0b5fe9c18 100644 --- a/.opencode/skills/impeccable/scripts/live-inject.mjs +++ b/.opencode/skills/impeccable/scripts/live-inject.mjs @@ -27,6 +27,7 @@ import fs from 'node:fs'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; import { resolveLiveConfigPath } from './lib/impeccable-paths.mjs'; +import { livePathGlobToRegex } from './lib/live-path-globs.mjs'; import { describeInjectArtifacts, frameworkIgnorePatterns, @@ -364,7 +365,7 @@ export function resolveFiles(rootDir, config) { const patterns = config.files; const userExcludes = Array.isArray(config.exclude) ? config.exclude : []; const allExcludes = [...HARD_EXCLUDES, ...userExcludes]; - const excludeRegexes = allExcludes.map(globToRegex); + const excludeRegexes = allExcludes.map(livePathGlobToRegex); const isExcluded = (relPath) => excludeRegexes.some((re) => re.test(relPath)); const isGlob = (s) => /[*?[]/.test(s); @@ -401,47 +402,6 @@ export function resolveFiles(rootDir, config) { return out; } -/** - * Convert a glob pattern to a RegExp. Supports: - * ** → any number of path segments (including zero) - * * → any chars except `/` - * ? → any single char except `/` - * Paths are normalized to forward slashes before matching. - */ -function globToRegex(pattern) { - let re = ''; - let i = 0; - while (i < pattern.length) { - const c = pattern[i]; - if (c === '*') { - if (pattern[i + 1] === '*') { - // ** — any number of segments, including zero. Handle the common - // **/ and /** forms so `a/**/b` matches `a/b` as well as `a/x/y/b`. - if (pattern[i + 2] === '/') { - re += '(?:.*/)?'; - i += 3; - } else { - re += '.*'; - i += 2; - } - } else { - re += '[^/]*'; - i += 1; - } - } else if (c === '?') { - re += '[^/]'; - i += 1; - } else if (/[.+^${}()|[\]\\]/.test(c)) { - re += '\\' + c; - i += 1; - } else { - re += c; - i += 1; - } - } - return new RegExp('^' + re + '$'); -} - // --------------------------------------------------------------------------- // Core operations // --------------------------------------------------------------------------- diff --git a/.opencode/skills/impeccable/scripts/live.mjs b/.opencode/skills/impeccable/scripts/live.mjs index 7738c3f02..ccbef4949 100644 --- a/.opencode/skills/impeccable/scripts/live.mjs +++ b/.opencode/skills/impeccable/scripts/live.mjs @@ -24,6 +24,7 @@ import { fileURLToPath } from 'node:url'; import { resolveTargetSelection } from './context.mjs'; import { resolveFiles } from './live-inject.mjs'; import { readLiveServerInfo } from './lib/impeccable-paths.mjs'; +import { livePathGlobToRegex } from './lib/live-path-globs.mjs'; import { resolveSurfaceBrief } from './lib/surface-briefs.mjs'; import { resolveLiveTarget } from './live-target.mjs'; import { bootInstructions } from './live/instructions.mjs'; @@ -240,7 +241,7 @@ function scanForDrift(rootDir, resolvedFiles, config) { // Files matching the user's `exclude` globs are intentional omissions, // not drift. Compile them to regexes so the orphan list stays signal. const userExcludeRegexes = (Array.isArray(config.exclude) ? config.exclude : []) - .map((p) => globToRegex(p)); + .map(livePathGlobToRegex); const isUserExcluded = (rel) => userExcludeRegexes.some((re) => re.test(rel)); const orphans = []; @@ -278,38 +279,6 @@ function scanForDrift(rootDir, resolvedFiles, config) { }; } -/** - * Same glob-to-regex mapping used by live-inject.mjs. Kept inline here - * to avoid a circular import (live-inject.mjs already imports nothing - * from live.mjs). The two must stay in sync. - */ -function globToRegex(pattern) { - let re = ''; - let i = 0; - while (i < pattern.length) { - const c = pattern[i]; - if (c === '*') { - if (pattern[i + 1] === '*') { - if (pattern[i + 2] === '/') { re += '(?:.*/)?'; i += 3; } - else { re += '.*'; i += 2; } - } else { - re += '[^/]*'; - i += 1; - } - } else if (c === '?') { - re += '[^/]'; - i += 1; - } else if (/[.+^${}()|[\]\\]/.test(c)) { - re += '\\' + c; - i += 1; - } else { - re += c; - i += 1; - } - } - return new RegExp('^' + re + '$'); -} - // --------------------------------------------------------------------------- // Helpers // --------------------------------------------------------------------------- diff --git a/.pi/skills/impeccable/scripts/lib/live-path-globs.mjs b/.pi/skills/impeccable/scripts/lib/live-path-globs.mjs new file mode 100644 index 000000000..4a3eebda0 --- /dev/null +++ b/.pi/skills/impeccable/scripts/lib/live-path-globs.mjs @@ -0,0 +1,37 @@ +/** + * Convert a live-config glob pattern to a RegExp. + * + * Supports `**` across path segments, `*` within one segment, and `?` for one + * character. Callers normalize project-relative paths to forward slashes. + */ +export function livePathGlobToRegex(pattern) { + let re = ''; + let i = 0; + while (i < pattern.length) { + const c = pattern[i]; + if (c === '*') { + if (pattern[i + 1] === '*') { + if (pattern[i + 2] === '/') { + re += '(?:.*/)?'; + i += 3; + } else { + re += '.*'; + i += 2; + } + } else { + re += '[^/]*'; + i += 1; + } + } else if (c === '?') { + re += '[^/]'; + i += 1; + } else if (/[.+^${}()|[\]\\]/.test(c)) { + re += `\\${c}`; + i += 1; + } else { + re += c; + i += 1; + } + } + return new RegExp(`^${re}$`); +} diff --git a/.pi/skills/impeccable/scripts/live-inject.mjs b/.pi/skills/impeccable/scripts/live-inject.mjs index 81848010b..0b5fe9c18 100644 --- a/.pi/skills/impeccable/scripts/live-inject.mjs +++ b/.pi/skills/impeccable/scripts/live-inject.mjs @@ -27,6 +27,7 @@ import fs from 'node:fs'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; import { resolveLiveConfigPath } from './lib/impeccable-paths.mjs'; +import { livePathGlobToRegex } from './lib/live-path-globs.mjs'; import { describeInjectArtifacts, frameworkIgnorePatterns, @@ -364,7 +365,7 @@ export function resolveFiles(rootDir, config) { const patterns = config.files; const userExcludes = Array.isArray(config.exclude) ? config.exclude : []; const allExcludes = [...HARD_EXCLUDES, ...userExcludes]; - const excludeRegexes = allExcludes.map(globToRegex); + const excludeRegexes = allExcludes.map(livePathGlobToRegex); const isExcluded = (relPath) => excludeRegexes.some((re) => re.test(relPath)); const isGlob = (s) => /[*?[]/.test(s); @@ -401,47 +402,6 @@ export function resolveFiles(rootDir, config) { return out; } -/** - * Convert a glob pattern to a RegExp. Supports: - * ** → any number of path segments (including zero) - * * → any chars except `/` - * ? → any single char except `/` - * Paths are normalized to forward slashes before matching. - */ -function globToRegex(pattern) { - let re = ''; - let i = 0; - while (i < pattern.length) { - const c = pattern[i]; - if (c === '*') { - if (pattern[i + 1] === '*') { - // ** — any number of segments, including zero. Handle the common - // **/ and /** forms so `a/**/b` matches `a/b` as well as `a/x/y/b`. - if (pattern[i + 2] === '/') { - re += '(?:.*/)?'; - i += 3; - } else { - re += '.*'; - i += 2; - } - } else { - re += '[^/]*'; - i += 1; - } - } else if (c === '?') { - re += '[^/]'; - i += 1; - } else if (/[.+^${}()|[\]\\]/.test(c)) { - re += '\\' + c; - i += 1; - } else { - re += c; - i += 1; - } - } - return new RegExp('^' + re + '$'); -} - // --------------------------------------------------------------------------- // Core operations // --------------------------------------------------------------------------- diff --git a/.pi/skills/impeccable/scripts/live.mjs b/.pi/skills/impeccable/scripts/live.mjs index 7738c3f02..ccbef4949 100644 --- a/.pi/skills/impeccable/scripts/live.mjs +++ b/.pi/skills/impeccable/scripts/live.mjs @@ -24,6 +24,7 @@ import { fileURLToPath } from 'node:url'; import { resolveTargetSelection } from './context.mjs'; import { resolveFiles } from './live-inject.mjs'; import { readLiveServerInfo } from './lib/impeccable-paths.mjs'; +import { livePathGlobToRegex } from './lib/live-path-globs.mjs'; import { resolveSurfaceBrief } from './lib/surface-briefs.mjs'; import { resolveLiveTarget } from './live-target.mjs'; import { bootInstructions } from './live/instructions.mjs'; @@ -240,7 +241,7 @@ function scanForDrift(rootDir, resolvedFiles, config) { // Files matching the user's `exclude` globs are intentional omissions, // not drift. Compile them to regexes so the orphan list stays signal. const userExcludeRegexes = (Array.isArray(config.exclude) ? config.exclude : []) - .map((p) => globToRegex(p)); + .map(livePathGlobToRegex); const isUserExcluded = (rel) => userExcludeRegexes.some((re) => re.test(rel)); const orphans = []; @@ -278,38 +279,6 @@ function scanForDrift(rootDir, resolvedFiles, config) { }; } -/** - * Same glob-to-regex mapping used by live-inject.mjs. Kept inline here - * to avoid a circular import (live-inject.mjs already imports nothing - * from live.mjs). The two must stay in sync. - */ -function globToRegex(pattern) { - let re = ''; - let i = 0; - while (i < pattern.length) { - const c = pattern[i]; - if (c === '*') { - if (pattern[i + 1] === '*') { - if (pattern[i + 2] === '/') { re += '(?:.*/)?'; i += 3; } - else { re += '.*'; i += 2; } - } else { - re += '[^/]*'; - i += 1; - } - } else if (c === '?') { - re += '[^/]'; - i += 1; - } else if (/[.+^${}()|[\]\\]/.test(c)) { - re += '\\' + c; - i += 1; - } else { - re += c; - i += 1; - } - } - return new RegExp('^' + re + '$'); -} - // --------------------------------------------------------------------------- // Helpers // --------------------------------------------------------------------------- diff --git a/.qoder/skills/impeccable/scripts/lib/live-path-globs.mjs b/.qoder/skills/impeccable/scripts/lib/live-path-globs.mjs new file mode 100644 index 000000000..4a3eebda0 --- /dev/null +++ b/.qoder/skills/impeccable/scripts/lib/live-path-globs.mjs @@ -0,0 +1,37 @@ +/** + * Convert a live-config glob pattern to a RegExp. + * + * Supports `**` across path segments, `*` within one segment, and `?` for one + * character. Callers normalize project-relative paths to forward slashes. + */ +export function livePathGlobToRegex(pattern) { + let re = ''; + let i = 0; + while (i < pattern.length) { + const c = pattern[i]; + if (c === '*') { + if (pattern[i + 1] === '*') { + if (pattern[i + 2] === '/') { + re += '(?:.*/)?'; + i += 3; + } else { + re += '.*'; + i += 2; + } + } else { + re += '[^/]*'; + i += 1; + } + } else if (c === '?') { + re += '[^/]'; + i += 1; + } else if (/[.+^${}()|[\]\\]/.test(c)) { + re += `\\${c}`; + i += 1; + } else { + re += c; + i += 1; + } + } + return new RegExp(`^${re}$`); +} diff --git a/.qoder/skills/impeccable/scripts/live-inject.mjs b/.qoder/skills/impeccable/scripts/live-inject.mjs index 81848010b..0b5fe9c18 100644 --- a/.qoder/skills/impeccable/scripts/live-inject.mjs +++ b/.qoder/skills/impeccable/scripts/live-inject.mjs @@ -27,6 +27,7 @@ import fs from 'node:fs'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; import { resolveLiveConfigPath } from './lib/impeccable-paths.mjs'; +import { livePathGlobToRegex } from './lib/live-path-globs.mjs'; import { describeInjectArtifacts, frameworkIgnorePatterns, @@ -364,7 +365,7 @@ export function resolveFiles(rootDir, config) { const patterns = config.files; const userExcludes = Array.isArray(config.exclude) ? config.exclude : []; const allExcludes = [...HARD_EXCLUDES, ...userExcludes]; - const excludeRegexes = allExcludes.map(globToRegex); + const excludeRegexes = allExcludes.map(livePathGlobToRegex); const isExcluded = (relPath) => excludeRegexes.some((re) => re.test(relPath)); const isGlob = (s) => /[*?[]/.test(s); @@ -401,47 +402,6 @@ export function resolveFiles(rootDir, config) { return out; } -/** - * Convert a glob pattern to a RegExp. Supports: - * ** → any number of path segments (including zero) - * * → any chars except `/` - * ? → any single char except `/` - * Paths are normalized to forward slashes before matching. - */ -function globToRegex(pattern) { - let re = ''; - let i = 0; - while (i < pattern.length) { - const c = pattern[i]; - if (c === '*') { - if (pattern[i + 1] === '*') { - // ** — any number of segments, including zero. Handle the common - // **/ and /** forms so `a/**/b` matches `a/b` as well as `a/x/y/b`. - if (pattern[i + 2] === '/') { - re += '(?:.*/)?'; - i += 3; - } else { - re += '.*'; - i += 2; - } - } else { - re += '[^/]*'; - i += 1; - } - } else if (c === '?') { - re += '[^/]'; - i += 1; - } else if (/[.+^${}()|[\]\\]/.test(c)) { - re += '\\' + c; - i += 1; - } else { - re += c; - i += 1; - } - } - return new RegExp('^' + re + '$'); -} - // --------------------------------------------------------------------------- // Core operations // --------------------------------------------------------------------------- diff --git a/.qoder/skills/impeccable/scripts/live.mjs b/.qoder/skills/impeccable/scripts/live.mjs index 7738c3f02..ccbef4949 100644 --- a/.qoder/skills/impeccable/scripts/live.mjs +++ b/.qoder/skills/impeccable/scripts/live.mjs @@ -24,6 +24,7 @@ import { fileURLToPath } from 'node:url'; import { resolveTargetSelection } from './context.mjs'; import { resolveFiles } from './live-inject.mjs'; import { readLiveServerInfo } from './lib/impeccable-paths.mjs'; +import { livePathGlobToRegex } from './lib/live-path-globs.mjs'; import { resolveSurfaceBrief } from './lib/surface-briefs.mjs'; import { resolveLiveTarget } from './live-target.mjs'; import { bootInstructions } from './live/instructions.mjs'; @@ -240,7 +241,7 @@ function scanForDrift(rootDir, resolvedFiles, config) { // Files matching the user's `exclude` globs are intentional omissions, // not drift. Compile them to regexes so the orphan list stays signal. const userExcludeRegexes = (Array.isArray(config.exclude) ? config.exclude : []) - .map((p) => globToRegex(p)); + .map(livePathGlobToRegex); const isUserExcluded = (rel) => userExcludeRegexes.some((re) => re.test(rel)); const orphans = []; @@ -278,38 +279,6 @@ function scanForDrift(rootDir, resolvedFiles, config) { }; } -/** - * Same glob-to-regex mapping used by live-inject.mjs. Kept inline here - * to avoid a circular import (live-inject.mjs already imports nothing - * from live.mjs). The two must stay in sync. - */ -function globToRegex(pattern) { - let re = ''; - let i = 0; - while (i < pattern.length) { - const c = pattern[i]; - if (c === '*') { - if (pattern[i + 1] === '*') { - if (pattern[i + 2] === '/') { re += '(?:.*/)?'; i += 3; } - else { re += '.*'; i += 2; } - } else { - re += '[^/]*'; - i += 1; - } - } else if (c === '?') { - re += '[^/]'; - i += 1; - } else if (/[.+^${}()|[\]\\]/.test(c)) { - re += '\\' + c; - i += 1; - } else { - re += c; - i += 1; - } - } - return new RegExp('^' + re + '$'); -} - // --------------------------------------------------------------------------- // Helpers // --------------------------------------------------------------------------- diff --git a/.rovodev/skills/impeccable/scripts/lib/live-path-globs.mjs b/.rovodev/skills/impeccable/scripts/lib/live-path-globs.mjs new file mode 100644 index 000000000..4a3eebda0 --- /dev/null +++ b/.rovodev/skills/impeccable/scripts/lib/live-path-globs.mjs @@ -0,0 +1,37 @@ +/** + * Convert a live-config glob pattern to a RegExp. + * + * Supports `**` across path segments, `*` within one segment, and `?` for one + * character. Callers normalize project-relative paths to forward slashes. + */ +export function livePathGlobToRegex(pattern) { + let re = ''; + let i = 0; + while (i < pattern.length) { + const c = pattern[i]; + if (c === '*') { + if (pattern[i + 1] === '*') { + if (pattern[i + 2] === '/') { + re += '(?:.*/)?'; + i += 3; + } else { + re += '.*'; + i += 2; + } + } else { + re += '[^/]*'; + i += 1; + } + } else if (c === '?') { + re += '[^/]'; + i += 1; + } else if (/[.+^${}()|[\]\\]/.test(c)) { + re += `\\${c}`; + i += 1; + } else { + re += c; + i += 1; + } + } + return new RegExp(`^${re}$`); +} diff --git a/.rovodev/skills/impeccable/scripts/live-inject.mjs b/.rovodev/skills/impeccable/scripts/live-inject.mjs index 81848010b..0b5fe9c18 100644 --- a/.rovodev/skills/impeccable/scripts/live-inject.mjs +++ b/.rovodev/skills/impeccable/scripts/live-inject.mjs @@ -27,6 +27,7 @@ import fs from 'node:fs'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; import { resolveLiveConfigPath } from './lib/impeccable-paths.mjs'; +import { livePathGlobToRegex } from './lib/live-path-globs.mjs'; import { describeInjectArtifacts, frameworkIgnorePatterns, @@ -364,7 +365,7 @@ export function resolveFiles(rootDir, config) { const patterns = config.files; const userExcludes = Array.isArray(config.exclude) ? config.exclude : []; const allExcludes = [...HARD_EXCLUDES, ...userExcludes]; - const excludeRegexes = allExcludes.map(globToRegex); + const excludeRegexes = allExcludes.map(livePathGlobToRegex); const isExcluded = (relPath) => excludeRegexes.some((re) => re.test(relPath)); const isGlob = (s) => /[*?[]/.test(s); @@ -401,47 +402,6 @@ export function resolveFiles(rootDir, config) { return out; } -/** - * Convert a glob pattern to a RegExp. Supports: - * ** → any number of path segments (including zero) - * * → any chars except `/` - * ? → any single char except `/` - * Paths are normalized to forward slashes before matching. - */ -function globToRegex(pattern) { - let re = ''; - let i = 0; - while (i < pattern.length) { - const c = pattern[i]; - if (c === '*') { - if (pattern[i + 1] === '*') { - // ** — any number of segments, including zero. Handle the common - // **/ and /** forms so `a/**/b` matches `a/b` as well as `a/x/y/b`. - if (pattern[i + 2] === '/') { - re += '(?:.*/)?'; - i += 3; - } else { - re += '.*'; - i += 2; - } - } else { - re += '[^/]*'; - i += 1; - } - } else if (c === '?') { - re += '[^/]'; - i += 1; - } else if (/[.+^${}()|[\]\\]/.test(c)) { - re += '\\' + c; - i += 1; - } else { - re += c; - i += 1; - } - } - return new RegExp('^' + re + '$'); -} - // --------------------------------------------------------------------------- // Core operations // --------------------------------------------------------------------------- diff --git a/.rovodev/skills/impeccable/scripts/live.mjs b/.rovodev/skills/impeccable/scripts/live.mjs index 7738c3f02..ccbef4949 100644 --- a/.rovodev/skills/impeccable/scripts/live.mjs +++ b/.rovodev/skills/impeccable/scripts/live.mjs @@ -24,6 +24,7 @@ import { fileURLToPath } from 'node:url'; import { resolveTargetSelection } from './context.mjs'; import { resolveFiles } from './live-inject.mjs'; import { readLiveServerInfo } from './lib/impeccable-paths.mjs'; +import { livePathGlobToRegex } from './lib/live-path-globs.mjs'; import { resolveSurfaceBrief } from './lib/surface-briefs.mjs'; import { resolveLiveTarget } from './live-target.mjs'; import { bootInstructions } from './live/instructions.mjs'; @@ -240,7 +241,7 @@ function scanForDrift(rootDir, resolvedFiles, config) { // Files matching the user's `exclude` globs are intentional omissions, // not drift. Compile them to regexes so the orphan list stays signal. const userExcludeRegexes = (Array.isArray(config.exclude) ? config.exclude : []) - .map((p) => globToRegex(p)); + .map(livePathGlobToRegex); const isUserExcluded = (rel) => userExcludeRegexes.some((re) => re.test(rel)); const orphans = []; @@ -278,38 +279,6 @@ function scanForDrift(rootDir, resolvedFiles, config) { }; } -/** - * Same glob-to-regex mapping used by live-inject.mjs. Kept inline here - * to avoid a circular import (live-inject.mjs already imports nothing - * from live.mjs). The two must stay in sync. - */ -function globToRegex(pattern) { - let re = ''; - let i = 0; - while (i < pattern.length) { - const c = pattern[i]; - if (c === '*') { - if (pattern[i + 1] === '*') { - if (pattern[i + 2] === '/') { re += '(?:.*/)?'; i += 3; } - else { re += '.*'; i += 2; } - } else { - re += '[^/]*'; - i += 1; - } - } else if (c === '?') { - re += '[^/]'; - i += 1; - } else if (/[.+^${}()|[\]\\]/.test(c)) { - re += '\\' + c; - i += 1; - } else { - re += c; - i += 1; - } - } - return new RegExp('^' + re + '$'); -} - // --------------------------------------------------------------------------- // Helpers // --------------------------------------------------------------------------- diff --git a/.trae-cn/skills/impeccable/scripts/lib/live-path-globs.mjs b/.trae-cn/skills/impeccable/scripts/lib/live-path-globs.mjs new file mode 100644 index 000000000..4a3eebda0 --- /dev/null +++ b/.trae-cn/skills/impeccable/scripts/lib/live-path-globs.mjs @@ -0,0 +1,37 @@ +/** + * Convert a live-config glob pattern to a RegExp. + * + * Supports `**` across path segments, `*` within one segment, and `?` for one + * character. Callers normalize project-relative paths to forward slashes. + */ +export function livePathGlobToRegex(pattern) { + let re = ''; + let i = 0; + while (i < pattern.length) { + const c = pattern[i]; + if (c === '*') { + if (pattern[i + 1] === '*') { + if (pattern[i + 2] === '/') { + re += '(?:.*/)?'; + i += 3; + } else { + re += '.*'; + i += 2; + } + } else { + re += '[^/]*'; + i += 1; + } + } else if (c === '?') { + re += '[^/]'; + i += 1; + } else if (/[.+^${}()|[\]\\]/.test(c)) { + re += `\\${c}`; + i += 1; + } else { + re += c; + i += 1; + } + } + return new RegExp(`^${re}$`); +} diff --git a/.trae-cn/skills/impeccable/scripts/live-inject.mjs b/.trae-cn/skills/impeccable/scripts/live-inject.mjs index 81848010b..0b5fe9c18 100644 --- a/.trae-cn/skills/impeccable/scripts/live-inject.mjs +++ b/.trae-cn/skills/impeccable/scripts/live-inject.mjs @@ -27,6 +27,7 @@ import fs from 'node:fs'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; import { resolveLiveConfigPath } from './lib/impeccable-paths.mjs'; +import { livePathGlobToRegex } from './lib/live-path-globs.mjs'; import { describeInjectArtifacts, frameworkIgnorePatterns, @@ -364,7 +365,7 @@ export function resolveFiles(rootDir, config) { const patterns = config.files; const userExcludes = Array.isArray(config.exclude) ? config.exclude : []; const allExcludes = [...HARD_EXCLUDES, ...userExcludes]; - const excludeRegexes = allExcludes.map(globToRegex); + const excludeRegexes = allExcludes.map(livePathGlobToRegex); const isExcluded = (relPath) => excludeRegexes.some((re) => re.test(relPath)); const isGlob = (s) => /[*?[]/.test(s); @@ -401,47 +402,6 @@ export function resolveFiles(rootDir, config) { return out; } -/** - * Convert a glob pattern to a RegExp. Supports: - * ** → any number of path segments (including zero) - * * → any chars except `/` - * ? → any single char except `/` - * Paths are normalized to forward slashes before matching. - */ -function globToRegex(pattern) { - let re = ''; - let i = 0; - while (i < pattern.length) { - const c = pattern[i]; - if (c === '*') { - if (pattern[i + 1] === '*') { - // ** — any number of segments, including zero. Handle the common - // **/ and /** forms so `a/**/b` matches `a/b` as well as `a/x/y/b`. - if (pattern[i + 2] === '/') { - re += '(?:.*/)?'; - i += 3; - } else { - re += '.*'; - i += 2; - } - } else { - re += '[^/]*'; - i += 1; - } - } else if (c === '?') { - re += '[^/]'; - i += 1; - } else if (/[.+^${}()|[\]\\]/.test(c)) { - re += '\\' + c; - i += 1; - } else { - re += c; - i += 1; - } - } - return new RegExp('^' + re + '$'); -} - // --------------------------------------------------------------------------- // Core operations // --------------------------------------------------------------------------- diff --git a/.trae-cn/skills/impeccable/scripts/live.mjs b/.trae-cn/skills/impeccable/scripts/live.mjs index 7738c3f02..ccbef4949 100644 --- a/.trae-cn/skills/impeccable/scripts/live.mjs +++ b/.trae-cn/skills/impeccable/scripts/live.mjs @@ -24,6 +24,7 @@ import { fileURLToPath } from 'node:url'; import { resolveTargetSelection } from './context.mjs'; import { resolveFiles } from './live-inject.mjs'; import { readLiveServerInfo } from './lib/impeccable-paths.mjs'; +import { livePathGlobToRegex } from './lib/live-path-globs.mjs'; import { resolveSurfaceBrief } from './lib/surface-briefs.mjs'; import { resolveLiveTarget } from './live-target.mjs'; import { bootInstructions } from './live/instructions.mjs'; @@ -240,7 +241,7 @@ function scanForDrift(rootDir, resolvedFiles, config) { // Files matching the user's `exclude` globs are intentional omissions, // not drift. Compile them to regexes so the orphan list stays signal. const userExcludeRegexes = (Array.isArray(config.exclude) ? config.exclude : []) - .map((p) => globToRegex(p)); + .map(livePathGlobToRegex); const isUserExcluded = (rel) => userExcludeRegexes.some((re) => re.test(rel)); const orphans = []; @@ -278,38 +279,6 @@ function scanForDrift(rootDir, resolvedFiles, config) { }; } -/** - * Same glob-to-regex mapping used by live-inject.mjs. Kept inline here - * to avoid a circular import (live-inject.mjs already imports nothing - * from live.mjs). The two must stay in sync. - */ -function globToRegex(pattern) { - let re = ''; - let i = 0; - while (i < pattern.length) { - const c = pattern[i]; - if (c === '*') { - if (pattern[i + 1] === '*') { - if (pattern[i + 2] === '/') { re += '(?:.*/)?'; i += 3; } - else { re += '.*'; i += 2; } - } else { - re += '[^/]*'; - i += 1; - } - } else if (c === '?') { - re += '[^/]'; - i += 1; - } else if (/[.+^${}()|[\]\\]/.test(c)) { - re += '\\' + c; - i += 1; - } else { - re += c; - i += 1; - } - } - return new RegExp('^' + re + '$'); -} - // --------------------------------------------------------------------------- // Helpers // --------------------------------------------------------------------------- diff --git a/.trae/skills/impeccable/scripts/lib/live-path-globs.mjs b/.trae/skills/impeccable/scripts/lib/live-path-globs.mjs new file mode 100644 index 000000000..4a3eebda0 --- /dev/null +++ b/.trae/skills/impeccable/scripts/lib/live-path-globs.mjs @@ -0,0 +1,37 @@ +/** + * Convert a live-config glob pattern to a RegExp. + * + * Supports `**` across path segments, `*` within one segment, and `?` for one + * character. Callers normalize project-relative paths to forward slashes. + */ +export function livePathGlobToRegex(pattern) { + let re = ''; + let i = 0; + while (i < pattern.length) { + const c = pattern[i]; + if (c === '*') { + if (pattern[i + 1] === '*') { + if (pattern[i + 2] === '/') { + re += '(?:.*/)?'; + i += 3; + } else { + re += '.*'; + i += 2; + } + } else { + re += '[^/]*'; + i += 1; + } + } else if (c === '?') { + re += '[^/]'; + i += 1; + } else if (/[.+^${}()|[\]\\]/.test(c)) { + re += `\\${c}`; + i += 1; + } else { + re += c; + i += 1; + } + } + return new RegExp(`^${re}$`); +} diff --git a/.trae/skills/impeccable/scripts/live-inject.mjs b/.trae/skills/impeccable/scripts/live-inject.mjs index 81848010b..0b5fe9c18 100644 --- a/.trae/skills/impeccable/scripts/live-inject.mjs +++ b/.trae/skills/impeccable/scripts/live-inject.mjs @@ -27,6 +27,7 @@ import fs from 'node:fs'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; import { resolveLiveConfigPath } from './lib/impeccable-paths.mjs'; +import { livePathGlobToRegex } from './lib/live-path-globs.mjs'; import { describeInjectArtifacts, frameworkIgnorePatterns, @@ -364,7 +365,7 @@ export function resolveFiles(rootDir, config) { const patterns = config.files; const userExcludes = Array.isArray(config.exclude) ? config.exclude : []; const allExcludes = [...HARD_EXCLUDES, ...userExcludes]; - const excludeRegexes = allExcludes.map(globToRegex); + const excludeRegexes = allExcludes.map(livePathGlobToRegex); const isExcluded = (relPath) => excludeRegexes.some((re) => re.test(relPath)); const isGlob = (s) => /[*?[]/.test(s); @@ -401,47 +402,6 @@ export function resolveFiles(rootDir, config) { return out; } -/** - * Convert a glob pattern to a RegExp. Supports: - * ** → any number of path segments (including zero) - * * → any chars except `/` - * ? → any single char except `/` - * Paths are normalized to forward slashes before matching. - */ -function globToRegex(pattern) { - let re = ''; - let i = 0; - while (i < pattern.length) { - const c = pattern[i]; - if (c === '*') { - if (pattern[i + 1] === '*') { - // ** — any number of segments, including zero. Handle the common - // **/ and /** forms so `a/**/b` matches `a/b` as well as `a/x/y/b`. - if (pattern[i + 2] === '/') { - re += '(?:.*/)?'; - i += 3; - } else { - re += '.*'; - i += 2; - } - } else { - re += '[^/]*'; - i += 1; - } - } else if (c === '?') { - re += '[^/]'; - i += 1; - } else if (/[.+^${}()|[\]\\]/.test(c)) { - re += '\\' + c; - i += 1; - } else { - re += c; - i += 1; - } - } - return new RegExp('^' + re + '$'); -} - // --------------------------------------------------------------------------- // Core operations // --------------------------------------------------------------------------- diff --git a/.trae/skills/impeccable/scripts/live.mjs b/.trae/skills/impeccable/scripts/live.mjs index 7738c3f02..ccbef4949 100644 --- a/.trae/skills/impeccable/scripts/live.mjs +++ b/.trae/skills/impeccable/scripts/live.mjs @@ -24,6 +24,7 @@ import { fileURLToPath } from 'node:url'; import { resolveTargetSelection } from './context.mjs'; import { resolveFiles } from './live-inject.mjs'; import { readLiveServerInfo } from './lib/impeccable-paths.mjs'; +import { livePathGlobToRegex } from './lib/live-path-globs.mjs'; import { resolveSurfaceBrief } from './lib/surface-briefs.mjs'; import { resolveLiveTarget } from './live-target.mjs'; import { bootInstructions } from './live/instructions.mjs'; @@ -240,7 +241,7 @@ function scanForDrift(rootDir, resolvedFiles, config) { // Files matching the user's `exclude` globs are intentional omissions, // not drift. Compile them to regexes so the orphan list stays signal. const userExcludeRegexes = (Array.isArray(config.exclude) ? config.exclude : []) - .map((p) => globToRegex(p)); + .map(livePathGlobToRegex); const isUserExcluded = (rel) => userExcludeRegexes.some((re) => re.test(rel)); const orphans = []; @@ -278,38 +279,6 @@ function scanForDrift(rootDir, resolvedFiles, config) { }; } -/** - * Same glob-to-regex mapping used by live-inject.mjs. Kept inline here - * to avoid a circular import (live-inject.mjs already imports nothing - * from live.mjs). The two must stay in sync. - */ -function globToRegex(pattern) { - let re = ''; - let i = 0; - while (i < pattern.length) { - const c = pattern[i]; - if (c === '*') { - if (pattern[i + 1] === '*') { - if (pattern[i + 2] === '/') { re += '(?:.*/)?'; i += 3; } - else { re += '.*'; i += 2; } - } else { - re += '[^/]*'; - i += 1; - } - } else if (c === '?') { - re += '[^/]'; - i += 1; - } else if (/[.+^${}()|[\]\\]/.test(c)) { - re += '\\' + c; - i += 1; - } else { - re += c; - i += 1; - } - } - return new RegExp('^' + re + '$'); -} - // --------------------------------------------------------------------------- // Helpers // --------------------------------------------------------------------------- diff --git a/.vibe/skills/impeccable/scripts/lib/live-path-globs.mjs b/.vibe/skills/impeccable/scripts/lib/live-path-globs.mjs new file mode 100644 index 000000000..4a3eebda0 --- /dev/null +++ b/.vibe/skills/impeccable/scripts/lib/live-path-globs.mjs @@ -0,0 +1,37 @@ +/** + * Convert a live-config glob pattern to a RegExp. + * + * Supports `**` across path segments, `*` within one segment, and `?` for one + * character. Callers normalize project-relative paths to forward slashes. + */ +export function livePathGlobToRegex(pattern) { + let re = ''; + let i = 0; + while (i < pattern.length) { + const c = pattern[i]; + if (c === '*') { + if (pattern[i + 1] === '*') { + if (pattern[i + 2] === '/') { + re += '(?:.*/)?'; + i += 3; + } else { + re += '.*'; + i += 2; + } + } else { + re += '[^/]*'; + i += 1; + } + } else if (c === '?') { + re += '[^/]'; + i += 1; + } else if (/[.+^${}()|[\]\\]/.test(c)) { + re += `\\${c}`; + i += 1; + } else { + re += c; + i += 1; + } + } + return new RegExp(`^${re}$`); +} diff --git a/.vibe/skills/impeccable/scripts/live-inject.mjs b/.vibe/skills/impeccable/scripts/live-inject.mjs index 81848010b..0b5fe9c18 100644 --- a/.vibe/skills/impeccable/scripts/live-inject.mjs +++ b/.vibe/skills/impeccable/scripts/live-inject.mjs @@ -27,6 +27,7 @@ import fs from 'node:fs'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; import { resolveLiveConfigPath } from './lib/impeccable-paths.mjs'; +import { livePathGlobToRegex } from './lib/live-path-globs.mjs'; import { describeInjectArtifacts, frameworkIgnorePatterns, @@ -364,7 +365,7 @@ export function resolveFiles(rootDir, config) { const patterns = config.files; const userExcludes = Array.isArray(config.exclude) ? config.exclude : []; const allExcludes = [...HARD_EXCLUDES, ...userExcludes]; - const excludeRegexes = allExcludes.map(globToRegex); + const excludeRegexes = allExcludes.map(livePathGlobToRegex); const isExcluded = (relPath) => excludeRegexes.some((re) => re.test(relPath)); const isGlob = (s) => /[*?[]/.test(s); @@ -401,47 +402,6 @@ export function resolveFiles(rootDir, config) { return out; } -/** - * Convert a glob pattern to a RegExp. Supports: - * ** → any number of path segments (including zero) - * * → any chars except `/` - * ? → any single char except `/` - * Paths are normalized to forward slashes before matching. - */ -function globToRegex(pattern) { - let re = ''; - let i = 0; - while (i < pattern.length) { - const c = pattern[i]; - if (c === '*') { - if (pattern[i + 1] === '*') { - // ** — any number of segments, including zero. Handle the common - // **/ and /** forms so `a/**/b` matches `a/b` as well as `a/x/y/b`. - if (pattern[i + 2] === '/') { - re += '(?:.*/)?'; - i += 3; - } else { - re += '.*'; - i += 2; - } - } else { - re += '[^/]*'; - i += 1; - } - } else if (c === '?') { - re += '[^/]'; - i += 1; - } else if (/[.+^${}()|[\]\\]/.test(c)) { - re += '\\' + c; - i += 1; - } else { - re += c; - i += 1; - } - } - return new RegExp('^' + re + '$'); -} - // --------------------------------------------------------------------------- // Core operations // --------------------------------------------------------------------------- diff --git a/.vibe/skills/impeccable/scripts/live.mjs b/.vibe/skills/impeccable/scripts/live.mjs index 7738c3f02..ccbef4949 100644 --- a/.vibe/skills/impeccable/scripts/live.mjs +++ b/.vibe/skills/impeccable/scripts/live.mjs @@ -24,6 +24,7 @@ import { fileURLToPath } from 'node:url'; import { resolveTargetSelection } from './context.mjs'; import { resolveFiles } from './live-inject.mjs'; import { readLiveServerInfo } from './lib/impeccable-paths.mjs'; +import { livePathGlobToRegex } from './lib/live-path-globs.mjs'; import { resolveSurfaceBrief } from './lib/surface-briefs.mjs'; import { resolveLiveTarget } from './live-target.mjs'; import { bootInstructions } from './live/instructions.mjs'; @@ -240,7 +241,7 @@ function scanForDrift(rootDir, resolvedFiles, config) { // Files matching the user's `exclude` globs are intentional omissions, // not drift. Compile them to regexes so the orphan list stays signal. const userExcludeRegexes = (Array.isArray(config.exclude) ? config.exclude : []) - .map((p) => globToRegex(p)); + .map(livePathGlobToRegex); const isUserExcluded = (rel) => userExcludeRegexes.some((re) => re.test(rel)); const orphans = []; @@ -278,38 +279,6 @@ function scanForDrift(rootDir, resolvedFiles, config) { }; } -/** - * Same glob-to-regex mapping used by live-inject.mjs. Kept inline here - * to avoid a circular import (live-inject.mjs already imports nothing - * from live.mjs). The two must stay in sync. - */ -function globToRegex(pattern) { - let re = ''; - let i = 0; - while (i < pattern.length) { - const c = pattern[i]; - if (c === '*') { - if (pattern[i + 1] === '*') { - if (pattern[i + 2] === '/') { re += '(?:.*/)?'; i += 3; } - else { re += '.*'; i += 2; } - } else { - re += '[^/]*'; - i += 1; - } - } else if (c === '?') { - re += '[^/]'; - i += 1; - } else if (/[.+^${}()|[\]\\]/.test(c)) { - re += '\\' + c; - i += 1; - } else { - re += c; - i += 1; - } - } - return new RegExp('^' + re + '$'); -} - // --------------------------------------------------------------------------- // Helpers // --------------------------------------------------------------------------- diff --git a/plugin/skills/impeccable/scripts/lib/live-path-globs.mjs b/plugin/skills/impeccable/scripts/lib/live-path-globs.mjs new file mode 100644 index 000000000..4a3eebda0 --- /dev/null +++ b/plugin/skills/impeccable/scripts/lib/live-path-globs.mjs @@ -0,0 +1,37 @@ +/** + * Convert a live-config glob pattern to a RegExp. + * + * Supports `**` across path segments, `*` within one segment, and `?` for one + * character. Callers normalize project-relative paths to forward slashes. + */ +export function livePathGlobToRegex(pattern) { + let re = ''; + let i = 0; + while (i < pattern.length) { + const c = pattern[i]; + if (c === '*') { + if (pattern[i + 1] === '*') { + if (pattern[i + 2] === '/') { + re += '(?:.*/)?'; + i += 3; + } else { + re += '.*'; + i += 2; + } + } else { + re += '[^/]*'; + i += 1; + } + } else if (c === '?') { + re += '[^/]'; + i += 1; + } else if (/[.+^${}()|[\]\\]/.test(c)) { + re += `\\${c}`; + i += 1; + } else { + re += c; + i += 1; + } + } + return new RegExp(`^${re}$`); +} diff --git a/plugin/skills/impeccable/scripts/live-inject.mjs b/plugin/skills/impeccable/scripts/live-inject.mjs index 81848010b..0b5fe9c18 100644 --- a/plugin/skills/impeccable/scripts/live-inject.mjs +++ b/plugin/skills/impeccable/scripts/live-inject.mjs @@ -27,6 +27,7 @@ import fs from 'node:fs'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; import { resolveLiveConfigPath } from './lib/impeccable-paths.mjs'; +import { livePathGlobToRegex } from './lib/live-path-globs.mjs'; import { describeInjectArtifacts, frameworkIgnorePatterns, @@ -364,7 +365,7 @@ export function resolveFiles(rootDir, config) { const patterns = config.files; const userExcludes = Array.isArray(config.exclude) ? config.exclude : []; const allExcludes = [...HARD_EXCLUDES, ...userExcludes]; - const excludeRegexes = allExcludes.map(globToRegex); + const excludeRegexes = allExcludes.map(livePathGlobToRegex); const isExcluded = (relPath) => excludeRegexes.some((re) => re.test(relPath)); const isGlob = (s) => /[*?[]/.test(s); @@ -401,47 +402,6 @@ export function resolveFiles(rootDir, config) { return out; } -/** - * Convert a glob pattern to a RegExp. Supports: - * ** → any number of path segments (including zero) - * * → any chars except `/` - * ? → any single char except `/` - * Paths are normalized to forward slashes before matching. - */ -function globToRegex(pattern) { - let re = ''; - let i = 0; - while (i < pattern.length) { - const c = pattern[i]; - if (c === '*') { - if (pattern[i + 1] === '*') { - // ** — any number of segments, including zero. Handle the common - // **/ and /** forms so `a/**/b` matches `a/b` as well as `a/x/y/b`. - if (pattern[i + 2] === '/') { - re += '(?:.*/)?'; - i += 3; - } else { - re += '.*'; - i += 2; - } - } else { - re += '[^/]*'; - i += 1; - } - } else if (c === '?') { - re += '[^/]'; - i += 1; - } else if (/[.+^${}()|[\]\\]/.test(c)) { - re += '\\' + c; - i += 1; - } else { - re += c; - i += 1; - } - } - return new RegExp('^' + re + '$'); -} - // --------------------------------------------------------------------------- // Core operations // --------------------------------------------------------------------------- diff --git a/plugin/skills/impeccable/scripts/live.mjs b/plugin/skills/impeccable/scripts/live.mjs index 7738c3f02..ccbef4949 100644 --- a/plugin/skills/impeccable/scripts/live.mjs +++ b/plugin/skills/impeccable/scripts/live.mjs @@ -24,6 +24,7 @@ import { fileURLToPath } from 'node:url'; import { resolveTargetSelection } from './context.mjs'; import { resolveFiles } from './live-inject.mjs'; import { readLiveServerInfo } from './lib/impeccable-paths.mjs'; +import { livePathGlobToRegex } from './lib/live-path-globs.mjs'; import { resolveSurfaceBrief } from './lib/surface-briefs.mjs'; import { resolveLiveTarget } from './live-target.mjs'; import { bootInstructions } from './live/instructions.mjs'; @@ -240,7 +241,7 @@ function scanForDrift(rootDir, resolvedFiles, config) { // Files matching the user's `exclude` globs are intentional omissions, // not drift. Compile them to regexes so the orphan list stays signal. const userExcludeRegexes = (Array.isArray(config.exclude) ? config.exclude : []) - .map((p) => globToRegex(p)); + .map(livePathGlobToRegex); const isUserExcluded = (rel) => userExcludeRegexes.some((re) => re.test(rel)); const orphans = []; @@ -278,38 +279,6 @@ function scanForDrift(rootDir, resolvedFiles, config) { }; } -/** - * Same glob-to-regex mapping used by live-inject.mjs. Kept inline here - * to avoid a circular import (live-inject.mjs already imports nothing - * from live.mjs). The two must stay in sync. - */ -function globToRegex(pattern) { - let re = ''; - let i = 0; - while (i < pattern.length) { - const c = pattern[i]; - if (c === '*') { - if (pattern[i + 1] === '*') { - if (pattern[i + 2] === '/') { re += '(?:.*/)?'; i += 3; } - else { re += '.*'; i += 2; } - } else { - re += '[^/]*'; - i += 1; - } - } else if (c === '?') { - re += '[^/]'; - i += 1; - } else if (/[.+^${}()|[\]\\]/.test(c)) { - re += '\\' + c; - i += 1; - } else { - re += c; - i += 1; - } - } - return new RegExp('^' + re + '$'); -} - // --------------------------------------------------------------------------- // Helpers // ---------------------------------------------------------------------------