Changeset 0.11.0 (#62)
This commit is contained in:
36
extensions/builtin/regex-tester/manifest.json
Normal file
36
extensions/builtin/regex-tester/manifest.json
Normal file
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"id": "regex-tester",
|
||||
"name": "Regex Tester",
|
||||
"version": "1.0.0",
|
||||
"tier": "browser",
|
||||
"author": "switchboard",
|
||||
"description": "Tests regular expressions against input strings. Allows the LLM to verify regex patterns and see matches, groups, and indices.",
|
||||
"permissions": [],
|
||||
"tools": [
|
||||
{
|
||||
"name": "regex_test",
|
||||
"description": "Test a regular expression against one or more input strings. Returns match details including captured groups, indices, and whether each string matched. Use this to verify regex patterns instead of guessing.",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"pattern": {
|
||||
"type": "string",
|
||||
"description": "The regular expression pattern (without delimiters), e.g. '^\\d{3}-\\d{4}$'"
|
||||
},
|
||||
"flags": {
|
||||
"type": "string",
|
||||
"description": "Regex flags, e.g. 'gi' for global+case-insensitive. Default: '' (no flags)"
|
||||
},
|
||||
"inputs": {
|
||||
"type": "array",
|
||||
"items": { "type": "string" },
|
||||
"description": "Array of test strings to match against the pattern"
|
||||
}
|
||||
},
|
||||
"required": ["pattern", "inputs"]
|
||||
}
|
||||
}
|
||||
],
|
||||
"surfaces": [],
|
||||
"settings": {}
|
||||
}
|
||||
102
extensions/builtin/regex-tester/script.js
Normal file
102
extensions/builtin/regex-tester/script.js
Normal file
@@ -0,0 +1,102 @@
|
||||
// ==========================================
|
||||
// Regex Tester — Browser Extension
|
||||
// ==========================================
|
||||
// Tests regular expressions against input strings.
|
||||
// Registers the regex_test tool so the LLM can verify
|
||||
// patterns instead of guessing.
|
||||
// ==========================================
|
||||
|
||||
Extensions.register({
|
||||
id: 'regex-tester',
|
||||
|
||||
async init(ctx) {
|
||||
const self = this;
|
||||
|
||||
ctx.tools.handle('regex_test', async (args) => {
|
||||
return self._test(args.pattern, args.flags || '', args.inputs || []);
|
||||
});
|
||||
},
|
||||
|
||||
_test(pattern, flags, inputs) {
|
||||
// Validate pattern
|
||||
let regex;
|
||||
try {
|
||||
regex = new RegExp(pattern, flags);
|
||||
} catch (e) {
|
||||
return {
|
||||
success: false,
|
||||
error: `Invalid regex: ${e.message}`,
|
||||
pattern,
|
||||
flags,
|
||||
};
|
||||
}
|
||||
|
||||
const results = inputs.map(input => {
|
||||
// Reset lastIndex for global/sticky patterns
|
||||
regex.lastIndex = 0;
|
||||
|
||||
const isGlobal = regex.global;
|
||||
const matches = [];
|
||||
|
||||
if (isGlobal) {
|
||||
// Collect all matches for global flag
|
||||
let match;
|
||||
while ((match = regex.exec(input)) !== null) {
|
||||
matches.push(this._formatMatch(match));
|
||||
// Prevent infinite loops on zero-length matches
|
||||
if (match[0].length === 0) regex.lastIndex++;
|
||||
}
|
||||
} else {
|
||||
const match = regex.exec(input);
|
||||
if (match) {
|
||||
matches.push(this._formatMatch(match));
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
input,
|
||||
matched: matches.length > 0,
|
||||
matchCount: matches.length,
|
||||
matches,
|
||||
};
|
||||
});
|
||||
|
||||
const totalMatched = results.filter(r => r.matched).length;
|
||||
|
||||
return {
|
||||
success: true,
|
||||
pattern,
|
||||
flags,
|
||||
summary: `${totalMatched}/${inputs.length} inputs matched`,
|
||||
results,
|
||||
};
|
||||
},
|
||||
|
||||
_formatMatch(match) {
|
||||
const result = {
|
||||
fullMatch: match[0],
|
||||
index: match.index,
|
||||
length: match[0].length,
|
||||
};
|
||||
|
||||
// Named groups (ES2018)
|
||||
if (match.groups) {
|
||||
result.namedGroups = {};
|
||||
for (const [name, value] of Object.entries(match.groups)) {
|
||||
result.namedGroups[name] = value;
|
||||
}
|
||||
}
|
||||
|
||||
// Numbered capture groups
|
||||
if (match.length > 1) {
|
||||
result.groups = [];
|
||||
for (let i = 1; i < match.length; i++) {
|
||||
result.groups.push(match[i] !== undefined ? match[i] : null);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
destroy() {}
|
||||
});
|
||||
Reference in New Issue
Block a user