UNPKG

@struktoai/mirage-core

Version:

A Unified Virtual Filesystem For AI Agents

81 lines • 3.99 kB
// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. ========= // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ========= Copyright 2026 @ Strukto.AI All Rights Reserved. ========= import { PatternType } from "./constants.js"; // Classify a grep pattern for API push-down decisions. export function classifyPattern(pattern, fixedString) { if (pattern.includes('\n')) return PatternType.REGEX; if (fixedString) return PatternType.EXACT; if (/^[\p{L}\p{N}_\s\-.]+$/u.test(pattern)) return PatternType.SIMPLE; return PatternType.REGEX; } const MIN_SEARCH_LITERAL = 3; // Backend folding may miss grep's Unicode matches for k and s, or pair // ASCII I with dotless ı instead of i under a Turkish collation. const UNICODE_FOLDED = /[iks]/; // Whether the pattern is searched verbatim, with no regex extraction. // Push-down against a whole-word search index is only complete when the term // handed to the provider is the entire match. A regex narrowed on an extracted // literal fails that: `foo[0-9]` under -w matches `foo1`, but a whole-word // search for `foo` never returns a file whose only token is `foo1`. export function isLiteralPattern(pattern, fixedString) { if (fixedString) return true; const pt = classifyPattern(pattern, fixedString); return pt === PatternType.EXACT || (pt === PatternType.SIMPLE && !pattern.includes('.')); } /** * The terms a whole-word search index may narrow a scan on, or null. * * A newline-joined pattern list (several -e, or the lines of -f) matches a * line when any one alternative does, so one search per alternative, unioned, * is complete when every alternative is itself a whole-word literal. -x narrows as -w does: a line that is the * literal entire is a word match of it. An empty alternative matches every * line, which no search can stand in for. Mirrors Python's * `whole_word_literals`. */ export function wholeWordLiterals(pattern, fixedString, wholeWord, lineRegexp = false) { if (pattern === null || !(wholeWord || lineRegexp)) return null; const terms = pattern.split('\n'); if (terms.some((t) => t === '' || !isLiteralPattern(t, fixedString))) return null; return [...new Set(terms)]; } /** * The texts a mount's search is asked for, and whether as whole words. * Literals under -w or -x are asked as whole words, which a word index can * answer; any other pattern is narrowed on the needles one of which every * match contains, asked anywhere. Under -i a literal with a non-ASCII letter, * or with i, k or s when case folds by Unicode, is left to the scan: a mount * may miss Unicode pairs (`ſ` and `s`) or even ASCII pairs (`I` and `i` * under a Turkish collation). Mirrors Python's `search_terms`. */ export function searchTerms(pattern, // Texts one of which every match holds, null when none are known. needles, // Case folds by Unicode, so `ſ` matches `s`. unicodeFolds, fixedString, wholeWord, lineRegexp, ignoreCase) { const words = wholeWordLiterals(pattern, fixedString, wholeWord, lineRegexp); const untrusted = (w) => /[\u0080-\uffff]/.test(w) || (unicodeFolds && UNICODE_FOLDED.test(w.toLowerCase())); if (words !== null && !(ignoreCase && words.some(untrusted))) { return [words, true]; } if (needles === null || needles.some((n) => n.length < MIN_SEARCH_LITERAL)) return null; return [needles, false]; } //# sourceMappingURL=grep_pushdown.js.map