revxl-devtools 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/README.md +84 -0
  2. package/checkout/index.html +195 -0
  3. package/dist/auth.d.ts +3 -0
  4. package/dist/auth.js +77 -0
  5. package/dist/codegen/cron-codegen.d.ts +1 -0
  6. package/dist/codegen/cron-codegen.js +56 -0
  7. package/dist/codegen/regex-codegen.d.ts +1 -0
  8. package/dist/codegen/regex-codegen.js +125 -0
  9. package/dist/index.d.ts +22 -0
  10. package/dist/index.js +100 -0
  11. package/dist/registry.d.ts +10 -0
  12. package/dist/registry.js +13 -0
  13. package/dist/tools/base64.d.ts +1 -0
  14. package/dist/tools/base64.js +29 -0
  15. package/dist/tools/batch.d.ts +1 -0
  16. package/dist/tools/batch.js +56 -0
  17. package/dist/tools/chmod.d.ts +1 -0
  18. package/dist/tools/chmod.js +115 -0
  19. package/dist/tools/cron.d.ts +1 -0
  20. package/dist/tools/cron.js +311 -0
  21. package/dist/tools/hash.d.ts +1 -0
  22. package/dist/tools/hash.js +25 -0
  23. package/dist/tools/http-status.d.ts +1 -0
  24. package/dist/tools/http-status.js +59 -0
  25. package/dist/tools/json-diff.d.ts +1 -0
  26. package/dist/tools/json-diff.js +131 -0
  27. package/dist/tools/json-format.d.ts +1 -0
  28. package/dist/tools/json-format.js +38 -0
  29. package/dist/tools/json-query.d.ts +1 -0
  30. package/dist/tools/json-query.js +114 -0
  31. package/dist/tools/jwt.d.ts +1 -0
  32. package/dist/tools/jwt.js +177 -0
  33. package/dist/tools/regex.d.ts +1 -0
  34. package/dist/tools/regex.js +116 -0
  35. package/dist/tools/secrets-scan.d.ts +1 -0
  36. package/dist/tools/secrets-scan.js +173 -0
  37. package/dist/tools/sql-format.d.ts +1 -0
  38. package/dist/tools/sql-format.js +157 -0
  39. package/dist/tools/timestamp.d.ts +1 -0
  40. package/dist/tools/timestamp.js +72 -0
  41. package/dist/tools/url-encode.d.ts +1 -0
  42. package/dist/tools/url-encode.js +26 -0
  43. package/dist/tools/uuid.d.ts +1 -0
  44. package/dist/tools/uuid.js +24 -0
  45. package/dist/tools/yaml-convert.d.ts +1 -0
  46. package/dist/tools/yaml-convert.js +371 -0
  47. package/package.json +29 -0
  48. package/src/auth.ts +99 -0
  49. package/src/codegen/cron-codegen.ts +66 -0
  50. package/src/codegen/regex-codegen.ts +132 -0
  51. package/src/index.ts +134 -0
  52. package/src/registry.ts +25 -0
  53. package/src/tools/base64.ts +32 -0
  54. package/src/tools/batch.ts +69 -0
  55. package/src/tools/chmod.ts +133 -0
  56. package/src/tools/cron.ts +365 -0
  57. package/src/tools/hash.ts +26 -0
  58. package/src/tools/http-status.ts +63 -0
  59. package/src/tools/json-diff.ts +153 -0
  60. package/src/tools/json-format.ts +43 -0
  61. package/src/tools/json-query.ts +126 -0
  62. package/src/tools/jwt.ts +193 -0
  63. package/src/tools/regex.ts +131 -0
  64. package/src/tools/secrets-scan.ts +212 -0
  65. package/src/tools/sql-format.ts +178 -0
  66. package/src/tools/timestamp.ts +74 -0
  67. package/src/tools/url-encode.ts +29 -0
  68. package/src/tools/uuid.ts +25 -0
  69. package/src/tools/yaml-convert.ts +383 -0
  70. package/tsconfig.json +14 -0
@@ -0,0 +1,131 @@
1
+ import { registerTool } from "../registry.js";
2
+ function deepDiff(a, b, path, results) {
3
+ if (a === b)
4
+ return;
5
+ // Both null/undefined
6
+ if (a == null && b == null)
7
+ return;
8
+ // Type mismatch or primitive change
9
+ if (typeof a !== typeof b ||
10
+ a === null ||
11
+ b === null ||
12
+ typeof a !== "object" ||
13
+ typeof b !== "object") {
14
+ results.push({ path: path || "$", type: "changed", oldValue: a, newValue: b });
15
+ return;
16
+ }
17
+ const aIsArray = Array.isArray(a);
18
+ const bIsArray = Array.isArray(b);
19
+ // Array vs object mismatch
20
+ if (aIsArray !== bIsArray) {
21
+ results.push({ path: path || "$", type: "changed", oldValue: a, newValue: b });
22
+ return;
23
+ }
24
+ if (aIsArray && bIsArray) {
25
+ const maxLen = Math.max(a.length, b.length);
26
+ for (let i = 0; i < maxLen; i++) {
27
+ const itemPath = `${path}[${i}]`;
28
+ if (i >= a.length) {
29
+ results.push({ path: itemPath, type: "added", newValue: b[i] });
30
+ }
31
+ else if (i >= b.length) {
32
+ results.push({ path: itemPath, type: "removed", oldValue: a[i] });
33
+ }
34
+ else {
35
+ deepDiff(a[i], b[i], itemPath, results);
36
+ }
37
+ }
38
+ return;
39
+ }
40
+ // Both objects
41
+ const aObj = a;
42
+ const bObj = b;
43
+ const allKeys = new Set([...Object.keys(aObj), ...Object.keys(bObj)]);
44
+ for (const key of allKeys) {
45
+ const keyPath = path ? `${path}.${key}` : key;
46
+ if (!(key in aObj)) {
47
+ results.push({ path: keyPath, type: "added", newValue: bObj[key] });
48
+ }
49
+ else if (!(key in bObj)) {
50
+ results.push({ path: keyPath, type: "removed", oldValue: aObj[key] });
51
+ }
52
+ else {
53
+ deepDiff(aObj[key], bObj[key], keyPath, results);
54
+ }
55
+ }
56
+ }
57
+ function formatValue(val) {
58
+ if (typeof val === "string")
59
+ return JSON.stringify(val);
60
+ if (val === undefined)
61
+ return "undefined";
62
+ return JSON.stringify(val);
63
+ }
64
+ // ---------------------------------------------------------------------------
65
+ // Tool registration
66
+ // ---------------------------------------------------------------------------
67
+ registerTool({
68
+ name: "json_diff",
69
+ description: "Deep-compare two JSON objects and show all differences — added, removed, and changed values with paths",
70
+ pro: true,
71
+ inputSchema: {
72
+ type: "object",
73
+ properties: {
74
+ a: {
75
+ type: "string",
76
+ description: "First JSON string",
77
+ },
78
+ b: {
79
+ type: "string",
80
+ description: "Second JSON string",
81
+ },
82
+ },
83
+ required: ["a", "b"],
84
+ },
85
+ handler: async (args) => {
86
+ const aStr = args.a;
87
+ const bStr = args.b;
88
+ let aVal;
89
+ let bVal;
90
+ try {
91
+ aVal = JSON.parse(aStr);
92
+ }
93
+ catch {
94
+ throw new Error("Invalid JSON in 'a'");
95
+ }
96
+ try {
97
+ bVal = JSON.parse(bStr);
98
+ }
99
+ catch {
100
+ throw new Error("Invalid JSON in 'b'");
101
+ }
102
+ const diffs = [];
103
+ deepDiff(aVal, bVal, "", diffs);
104
+ if (diffs.length === 0) {
105
+ return "No differences — the two JSON values are identical.";
106
+ }
107
+ const added = diffs.filter((d) => d.type === "added").length;
108
+ const removed = diffs.filter((d) => d.type === "removed").length;
109
+ const changed = diffs.filter((d) => d.type === "changed").length;
110
+ const lines = [
111
+ `=== JSON Diff: ${diffs.length} difference${diffs.length === 1 ? "" : "s"} ===`,
112
+ `${added} added, ${removed} removed, ${changed} changed`,
113
+ "",
114
+ ];
115
+ for (const diff of diffs) {
116
+ const p = diff.path || "$";
117
+ switch (diff.type) {
118
+ case "added":
119
+ lines.push(`+ ${p}: ${formatValue(diff.newValue)}`);
120
+ break;
121
+ case "removed":
122
+ lines.push(`- ${p}: ${formatValue(diff.oldValue)}`);
123
+ break;
124
+ case "changed":
125
+ lines.push(`~ ${p}: ${formatValue(diff.oldValue)} → ${formatValue(diff.newValue)}`);
126
+ break;
127
+ }
128
+ }
129
+ return lines.join("\n");
130
+ },
131
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,38 @@
1
+ import { registerTool } from "../registry.js";
2
+ registerTool({
3
+ name: "json_format",
4
+ description: "Format, minify, or validate JSON strings",
5
+ pro: false,
6
+ inputSchema: {
7
+ type: "object",
8
+ properties: {
9
+ text: { type: "string", description: "JSON string to process" },
10
+ action: {
11
+ type: "string",
12
+ enum: ["format", "minify", "validate"],
13
+ description: "Action to perform (default: format)",
14
+ },
15
+ indent: {
16
+ type: "number",
17
+ description: "Number of spaces for indentation (default: 2)",
18
+ },
19
+ },
20
+ required: ["text"],
21
+ },
22
+ handler: async (args) => {
23
+ const text = args.text;
24
+ const action = args.action || "format";
25
+ const indent = args.indent || 2;
26
+ const parsed = JSON.parse(text);
27
+ if (action === "validate") {
28
+ const type = Array.isArray(parsed)
29
+ ? `array[${parsed.length}]`
30
+ : `object{${Object.keys(parsed).length} keys}`;
31
+ return `Valid JSON: ${type}`;
32
+ }
33
+ if (action === "minify") {
34
+ return JSON.stringify(parsed);
35
+ }
36
+ return JSON.stringify(parsed, null, indent);
37
+ },
38
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,114 @@
1
+ import { registerTool } from "../registry.js";
2
+ // ---------------------------------------------------------------------------
3
+ // Simple JSON path query — supports dot notation, [N] indexing, * wildcard
4
+ // ---------------------------------------------------------------------------
5
+ function queryPath(data, segments) {
6
+ if (segments.length === 0)
7
+ return [data];
8
+ const [head, ...rest] = segments;
9
+ if (data === null || data === undefined || typeof data !== "object") {
10
+ return [];
11
+ }
12
+ // Wildcard: expand all array items or object values
13
+ if (head === "*") {
14
+ const values = Array.isArray(data) ? data : Object.values(data);
15
+ const results = [];
16
+ for (const val of values) {
17
+ results.push(...queryPath(val, rest));
18
+ }
19
+ return results;
20
+ }
21
+ // Array index: [N]
22
+ const indexMatch = head.match(/^\[(\d+)]$/);
23
+ if (indexMatch) {
24
+ const idx = parseInt(indexMatch[1], 10);
25
+ if (Array.isArray(data) && idx < data.length) {
26
+ return queryPath(data[idx], rest);
27
+ }
28
+ return [];
29
+ }
30
+ // Object key
31
+ const obj = data;
32
+ if (head in obj) {
33
+ return queryPath(obj[head], rest);
34
+ }
35
+ return [];
36
+ }
37
+ function parseQuery(query) {
38
+ const segments = [];
39
+ let current = "";
40
+ for (let i = 0; i < query.length; i++) {
41
+ const ch = query[i];
42
+ if (ch === ".") {
43
+ if (current)
44
+ segments.push(current);
45
+ current = "";
46
+ }
47
+ else if (ch === "[") {
48
+ if (current)
49
+ segments.push(current);
50
+ current = "";
51
+ const end = query.indexOf("]", i);
52
+ if (end === -1)
53
+ throw new Error(`Unmatched '[' at position ${i}`);
54
+ segments.push(query.slice(i, end + 1));
55
+ i = end;
56
+ }
57
+ else {
58
+ current += ch;
59
+ }
60
+ }
61
+ if (current)
62
+ segments.push(current);
63
+ return segments;
64
+ }
65
+ // ---------------------------------------------------------------------------
66
+ // Tool registration
67
+ // ---------------------------------------------------------------------------
68
+ registerTool({
69
+ name: "json_query",
70
+ description: "Query JSON data with dot-path expressions — supports nested keys, array indices [N], and wildcard * expansion",
71
+ pro: true,
72
+ inputSchema: {
73
+ type: "object",
74
+ properties: {
75
+ json: {
76
+ type: "string",
77
+ description: "JSON string to query",
78
+ },
79
+ query: {
80
+ type: "string",
81
+ description: 'Dot-path query like "data.users[0].name" or "items.*.id" — use * for wildcard, [N] for array index',
82
+ },
83
+ },
84
+ required: ["json", "query"],
85
+ },
86
+ handler: async (args) => {
87
+ const jsonStr = args.json;
88
+ const query = args.query;
89
+ let data;
90
+ try {
91
+ data = JSON.parse(jsonStr);
92
+ }
93
+ catch {
94
+ throw new Error("Invalid JSON input");
95
+ }
96
+ const segments = parseQuery(query);
97
+ const results = queryPath(data, segments);
98
+ if (results.length === 0) {
99
+ return `No results for query: ${query}`;
100
+ }
101
+ const sections = [
102
+ `=== Query: ${query} ===`,
103
+ `${results.length} result${results.length === 1 ? "" : "s"}`,
104
+ "",
105
+ ];
106
+ if (results.length === 1) {
107
+ sections.push(JSON.stringify(results[0], null, 2));
108
+ }
109
+ else {
110
+ sections.push(JSON.stringify(results, null, 2));
111
+ }
112
+ return sections.join("\n");
113
+ },
114
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,177 @@
1
+ import { createHmac } from "node:crypto";
2
+ import { registerTool } from "../registry.js";
3
+ // ---------------------------------------------------------------------------
4
+ // Base64url helpers
5
+ // ---------------------------------------------------------------------------
6
+ function base64urlDecode(input) {
7
+ let base64 = input.replace(/-/g, "+").replace(/_/g, "/");
8
+ const pad = base64.length % 4;
9
+ if (pad === 2)
10
+ base64 += "==";
11
+ else if (pad === 3)
12
+ base64 += "=";
13
+ return Buffer.from(base64, "base64").toString("utf-8");
14
+ }
15
+ function base64urlEncode(input) {
16
+ const buf = typeof input === "string" ? Buffer.from(input, "utf-8") : input;
17
+ return buf.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
18
+ }
19
+ // ---------------------------------------------------------------------------
20
+ // Known JWT claims
21
+ // ---------------------------------------------------------------------------
22
+ const CLAIM_NAMES = {
23
+ iss: "Issuer",
24
+ sub: "Subject",
25
+ aud: "Audience",
26
+ exp: "Expiration Time",
27
+ nbf: "Not Before",
28
+ iat: "Issued At",
29
+ jti: "JWT ID",
30
+ };
31
+ function describeClaims(payload) {
32
+ const lines = [];
33
+ for (const [key, label] of Object.entries(CLAIM_NAMES)) {
34
+ if (key in payload) {
35
+ const val = payload[key];
36
+ if (["exp", "nbf", "iat"].includes(key) && typeof val === "number") {
37
+ const date = new Date(val * 1000);
38
+ lines.push(` ${key} (${label}): ${val} — ${date.toISOString()}`);
39
+ }
40
+ else {
41
+ lines.push(` ${key} (${label}): ${JSON.stringify(val)}`);
42
+ }
43
+ }
44
+ }
45
+ return lines;
46
+ }
47
+ function expiryStatus(payload) {
48
+ if (typeof payload.exp !== "number")
49
+ return "No expiration set";
50
+ const now = Math.floor(Date.now() / 1000);
51
+ const diff = payload.exp - now;
52
+ if (diff <= 0) {
53
+ const mins = Math.abs(Math.round(diff / 60));
54
+ return `EXPIRED ${mins} minute${mins === 1 ? "" : "s"} ago`;
55
+ }
56
+ const mins = Math.round(diff / 60);
57
+ return `Valid for ${mins} minute${mins === 1 ? "" : "s"}`;
58
+ }
59
+ // ---------------------------------------------------------------------------
60
+ // HMAC signing
61
+ // ---------------------------------------------------------------------------
62
+ function sign(header, payload, secret, algorithm) {
63
+ const algoMap = {
64
+ HS256: "sha256",
65
+ HS384: "sha384",
66
+ HS512: "sha512",
67
+ };
68
+ const hashAlgo = algoMap[algorithm];
69
+ if (!hashAlgo)
70
+ throw new Error(`Unsupported algorithm: ${algorithm}`);
71
+ const data = `${header}.${payload}`;
72
+ const hmac = createHmac(hashAlgo, secret).update(data).digest();
73
+ return base64urlEncode(hmac);
74
+ }
75
+ // ---------------------------------------------------------------------------
76
+ // Tool registration
77
+ // ---------------------------------------------------------------------------
78
+ registerTool({
79
+ name: "jwt",
80
+ description: "Decode a JWT to inspect header/payload/expiry, or create a new HMAC-signed JWT",
81
+ pro: true,
82
+ inputSchema: {
83
+ type: "object",
84
+ properties: {
85
+ action: {
86
+ type: "string",
87
+ enum: ["decode", "create"],
88
+ description: "decode: inspect a JWT | create: generate a new JWT",
89
+ },
90
+ token: {
91
+ type: "string",
92
+ description: "(decode) The JWT string to decode",
93
+ },
94
+ payload: {
95
+ type: "object",
96
+ description: "(create) Claims object for the JWT payload",
97
+ },
98
+ secret: {
99
+ type: "string",
100
+ description: "(create) HMAC secret for signing",
101
+ },
102
+ algorithm: {
103
+ type: "string",
104
+ enum: ["HS256", "HS384", "HS512"],
105
+ description: "(create) Signing algorithm, default HS256",
106
+ },
107
+ expires_in: {
108
+ type: "number",
109
+ description: "(create) Seconds until expiration",
110
+ },
111
+ },
112
+ required: ["action"],
113
+ },
114
+ handler: async (args) => {
115
+ const action = args.action;
116
+ if (action === "decode") {
117
+ const token = args.token;
118
+ if (!token)
119
+ throw new Error("token is required for decode action");
120
+ const parts = token.split(".");
121
+ if (parts.length !== 3)
122
+ throw new Error("Invalid JWT: expected 3 dot-separated parts");
123
+ const header = JSON.parse(base64urlDecode(parts[0]));
124
+ const payload = JSON.parse(base64urlDecode(parts[1]));
125
+ const lines = [
126
+ "=== JWT Decoded ===",
127
+ "",
128
+ "--- Header ---",
129
+ JSON.stringify(header, null, 2),
130
+ "",
131
+ "--- Payload ---",
132
+ JSON.stringify(payload, null, 2),
133
+ "",
134
+ "--- Known Claims ---",
135
+ ...describeClaims(payload),
136
+ "",
137
+ `--- Expiry: ${expiryStatus(payload)} ---`,
138
+ "",
139
+ "(Signature not verified — provide secret separately if needed)",
140
+ ];
141
+ return lines.join("\n");
142
+ }
143
+ if (action === "create") {
144
+ const payloadObj = args.payload || {};
145
+ const secret = args.secret;
146
+ if (!secret)
147
+ throw new Error("secret is required for create action");
148
+ const algorithm = args.algorithm || "HS256";
149
+ const expiresIn = args.expires_in;
150
+ const now = Math.floor(Date.now() / 1000);
151
+ const claims = { ...payloadObj, iat: now };
152
+ if (expiresIn)
153
+ claims.exp = now + expiresIn;
154
+ const headerB64 = base64urlEncode(JSON.stringify({ alg: algorithm, typ: "JWT" }));
155
+ const payloadB64 = base64urlEncode(JSON.stringify(claims));
156
+ const signature = sign(headerB64, payloadB64, secret, algorithm);
157
+ const token = `${headerB64}.${payloadB64}.${signature}`;
158
+ const lines = [
159
+ "=== JWT Created ===",
160
+ "",
161
+ token,
162
+ "",
163
+ "--- Header ---",
164
+ JSON.stringify({ alg: algorithm, typ: "JWT" }, null, 2),
165
+ "",
166
+ "--- Payload ---",
167
+ JSON.stringify(claims, null, 2),
168
+ "",
169
+ `Algorithm: ${algorithm}`,
170
+ ];
171
+ if (expiresIn)
172
+ lines.push(`Expires in: ${expiresIn} seconds`);
173
+ return lines.join("\n");
174
+ }
175
+ throw new Error(`Unknown action: ${action}. Use "decode" or "create".`);
176
+ },
177
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,116 @@
1
+ import { registerTool } from "../registry.js";
2
+ import { generateRegexCode } from "../codegen/regex-codegen.js";
3
+ registerTool({
4
+ name: "regex",
5
+ description: "Test a regex pattern against a string (with match details, groups, indices) and generate working code in JS/Python/Go/Rust/Java",
6
+ pro: true,
7
+ inputSchema: {
8
+ type: "object",
9
+ properties: {
10
+ pattern: {
11
+ type: "string",
12
+ description: "Regular expression pattern (without delimiters)",
13
+ },
14
+ test_string: {
15
+ type: "string",
16
+ description: "String to test against (omit to just validate the pattern)",
17
+ },
18
+ flags: {
19
+ type: "string",
20
+ description: "Regex flags, e.g. 'gi' for global+case-insensitive (default: 'g')",
21
+ },
22
+ generate_code: {
23
+ type: "boolean",
24
+ description: "Generate code snippets in multiple languages (default: false)",
25
+ },
26
+ languages: {
27
+ type: "array",
28
+ items: { type: "string" },
29
+ description: "Languages for code generation: javascript, python, go, rust, java (default: all)",
30
+ },
31
+ },
32
+ required: ["pattern"],
33
+ },
34
+ handler: async (args) => {
35
+ const pattern = args.pattern;
36
+ const testString = args.test_string;
37
+ const flags = args.flags || "g";
38
+ const generateCode = args.generate_code || false;
39
+ const languages = args.languages;
40
+ // Validate the pattern first
41
+ let regex;
42
+ try {
43
+ regex = new RegExp(pattern, flags);
44
+ }
45
+ catch (err) {
46
+ const msg = err instanceof Error ? err.message : String(err);
47
+ return `Invalid regex pattern: ${msg}`;
48
+ }
49
+ const sections = [
50
+ `=== Regex: /${pattern}/${flags} ===`,
51
+ ];
52
+ if (testString !== undefined) {
53
+ const matches = [];
54
+ if (flags.includes("g")) {
55
+ // Global: iterate all matches
56
+ let m;
57
+ while ((m = regex.exec(testString)) !== null) {
58
+ matches.push({
59
+ match: m[0],
60
+ index: m.index,
61
+ groups: m.groups ? { ...m.groups } : null,
62
+ });
63
+ // Safety: avoid infinite loop on zero-length matches
64
+ if (m[0].length === 0)
65
+ regex.lastIndex++;
66
+ }
67
+ }
68
+ else {
69
+ // Non-global: single match with capture groups
70
+ const m = regex.exec(testString);
71
+ if (m) {
72
+ matches.push({
73
+ match: m[0],
74
+ index: m.index,
75
+ groups: m.groups ? { ...m.groups } : null,
76
+ });
77
+ // Show capture groups
78
+ if (m.length > 1) {
79
+ sections.push("");
80
+ sections.push("--- Capture Groups ---");
81
+ for (let i = 1; i < m.length; i++) {
82
+ sections.push(` Group ${i}: ${JSON.stringify(m[i])}`);
83
+ }
84
+ }
85
+ }
86
+ }
87
+ sections.push("");
88
+ if (matches.length === 0) {
89
+ sections.push("No matches found.");
90
+ }
91
+ else {
92
+ sections.push(`${matches.length} match${matches.length === 1 ? "" : "es"} found:`);
93
+ sections.push("");
94
+ for (const match of matches) {
95
+ sections.push(` [${match.index}] "${match.match}"`);
96
+ if (match.groups) {
97
+ for (const [name, value] of Object.entries(match.groups)) {
98
+ sections.push(` ${name}: "${value}"`);
99
+ }
100
+ }
101
+ }
102
+ }
103
+ }
104
+ else {
105
+ sections.push("");
106
+ sections.push("Pattern is valid. Provide test_string to see matches.");
107
+ }
108
+ if (generateCode) {
109
+ sections.push("");
110
+ sections.push("=== Code Snippets ===");
111
+ sections.push("");
112
+ sections.push(generateRegexCode(pattern, flags, languages));
113
+ }
114
+ return sections.join("\n");
115
+ },
116
+ });
@@ -0,0 +1 @@
1
+ export {};