Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ Here is the list of all utilities:
- [Number Base Changer](https://jam.dev/utilities/number-base-changer)
- [CSS Inliner for Email](https://jam.dev/utilities/css-inliner-for-email)
- [Regex Tester](https://jam.dev/utilities/regex-tester)
- [AI Regex Generator](https://jam.dev/utilities/ai-regex-generator)
- [Image Resizer](https://jam.dev/utilities/image-resizer)
- [CSS Units Converter](https://jam.dev/utilities/css-units-converter)
- [JWT Parser](https://jam.dev/utilities/jwt-parser)
Expand Down
77 changes: 77 additions & 0 deletions components/seo/AiRegexGeneratorSEO.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import Link from "next/link";

export default function AiRegexGeneratorSEO() {
return (
<div className="content-wrapper">
<section>
<p>
Generate regex patterns from natural language with Jam&apos;s AI Regex
Generator. Bring your own API key, keep data in your browser, and get a
clean pattern with explanations and examples.
</p>
</section>

<section>
<h2>How to use the AI Regex Generator</h2>
<p>
Describe what you want to match, add optional sample text, and let the
generator build a JavaScript-compatible regex. You can instantly test
the output against your own text.
</p>
</section>

<section>
<h2>Privacy-friendly by design</h2>
<p>
This tool runs entirely in the browser and uses your own API key. Your
key stays on your device and is never sent to Jam servers.
</p>
</section>

<section>
<h2>Why use an AI regex generator?</h2>
<ul>
<li>
<b>Faster debugging:</b> <br /> Quickly generate patterns that can
filter logs, parse errors, or validate input.
</li>
<li>
<b>Clear explanations:</b> <br /> Understand why a regex works so
you can maintain it confidently.
</li>
<li>
<b>Real-world examples:</b> <br /> Get sample matches to validate
behavior before shipping.
</li>
</ul>
</section>

<section>
<h2>More regex tools</h2>
<p>
Need to dive deeper? Pair this with our{" "}
<Link href="/utilities/regex-tester">Regex Tester</Link> to visualize
matches, flags, and capture groups.
</p>
</section>

<section>
<h2>FAQs</h2>
<ul>
<li>
<b>Does this tool store my API key?</b> <br /> Only if you choose to
remember it in your browser. It is never sent to Jam servers.
</li>
<li>
<b>Which providers are supported?</b> <br /> OpenAI and Anthropic
are supported, and you can choose the model you want to use.
</li>
<li>
<b>Is the generated regex always correct?</b> <br /> AI output can
be imperfect. Always validate with your own test cases.
</li>
</ul>
</section>
</div>
);
}
76 changes: 76 additions & 0 deletions components/utils/ai-regex-generator.utils.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import {
buildRegexPrompt,
getDefaultModel,
parseRegexResponse,
} from "./ai-regex-generator.utils";

describe("buildRegexPrompt", () => {
test("includes description and optional fields", () => {
const prompt = buildRegexPrompt({
description: "Match email addresses",
sampleText: "test@example.com",
expectedMatches: "test@example.com",
});

expect(prompt.system).toContain("regex patterns");
expect(prompt.user).toContain("Match email addresses");
expect(prompt.user).toContain("Sample text:");
expect(prompt.user).toContain("Expected matches:");
expect(prompt.user).toContain('"pattern"');
});
});

describe("parseRegexResponse", () => {
test("parses valid JSON response", () => {
const result = parseRegexResponse(
JSON.stringify({
pattern: "\\d+",
flags: "g",
regex: "/\\d+/g",
explanation: "Matches digits",
examples: [{ text: "123", matches: ["123"] }],
warnings: [],
})
);

expect(result.regex).toBe("/\\d+/g");
expect(result.pattern).toBe("\\d+");
expect(result.flags).toBe("g");
expect(result.explanation).toContain("digits");
expect(result.examples).toHaveLength(1);
});

test("parses fenced JSON response", () => {
const result = parseRegexResponse(
"```json\n" +
JSON.stringify({
pattern: "[a-z]+",
flags: "i",
regex: "/[a-z]+/i",
explanation: "Matches letters",
examples: [],
warnings: [],
}) +
"\n```"
);

expect(result.regex).toBe("/[a-z]+/i");
expect(result.pattern).toBe("[a-z]+");
});

test("falls back to regex extraction when JSON is invalid", () => {
const result = parseRegexResponse(
"Try using /[A-Z]{2,}/g to match uppercase strings."
);

expect(result.regex).toBe("/[A-Z]{2,}/g");
expect(result.warnings[0]).toContain("could not be parsed");
});
});

describe("getDefaultModel", () => {
test("returns provider defaults", () => {
expect(getDefaultModel("openai")).toBe("gpt-4o-mini");
expect(getDefaultModel("anthropic")).toBe("claude-3-haiku-20240307");
});
});
Loading